From patchwork Thu Apr 22 09:29:01 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Weimer X-Patchwork-Id: 43076 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id C184D3894427; Thu, 22 Apr 2021 09:28:49 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org C184D3894427 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1619083729; bh=mucM6C45KWaNSZpVQSbLPz4IM9jdI2xrgm2LWhLLcKs=; h=To:Subject:Date:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:From; b=du9qn1Yb0AYh4iIJs6NRXSPyvqH8Fn6P8kZHwxS1vJuPhJhmDfP1ODwMMmbTKzdkl 1Y2InSXGwSFaEbUzYAlixNQkTDUbgMEGsoy+n5Z6qVseaCvrtSLE2e+9DllpO5Ld3x /0qHIvJCB9B87otTfn4+Gve/nccBUL5pufKNjVKw= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTP id 75FF13894415 for ; Thu, 22 Apr 2021 09:28:47 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 75FF13894415 Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-224-tOXUqVYWNROZL7ObBVRVAA-1; Thu, 22 Apr 2021 05:28:44 -0400 X-MC-Unique: tOXUqVYWNROZL7ObBVRVAA-1 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 0CF3F343A2; Thu, 22 Apr 2021 09:28:44 +0000 (UTC) Received: from oldenburg.str.redhat.com (ovpn-113-20.ams2.redhat.com [10.36.113.20]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 32BE45C261; Thu, 22 Apr 2021 09:28:43 +0000 (UTC) To: libc-alpha@sourceware.org Subject: [PATCH] nptl: Check for compatible GDB in nptl/tst-pthread-gdb-attach Date: Thu, 22 Apr 2021 11:29:01 +0200 Message-ID: <87h7jyk6qq.fsf@oldenburg.str.redhat.com> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/27.2 (gnu/linux) MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-12.4 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Florian Weimer via Libc-alpha From: Florian Weimer Reply-To: Florian Weimer Errors-To: libc-alpha-bounces@sourceware.org Sender: "Libc-alpha" Also do not clear the subprocess environment, in case running GDB needs certain environment variables. --- nptl/tst-pthread-gdb-attach.c | 78 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 76 insertions(+), 2 deletions(-) diff --git a/nptl/tst-pthread-gdb-attach.c b/nptl/tst-pthread-gdb-attach.c index 0603ad844d..901a120034 100644 --- a/nptl/tst-pthread-gdb-attach.c +++ b/nptl/tst-pthread-gdb-attach.c @@ -20,8 +20,12 @@ whether libthread_db can be loaded, and that access to thread-local variables works. */ +#include #include +#include +#include #include +#include #include #include #include @@ -35,6 +39,49 @@ the thread. */ __thread volatile int altered_by_debugger; +/* Common prefix between 32-bit and 64-bit ELF. */ +struct elf_prefix +{ + unsigned char e_ident[EI_NIDENT]; + uint16_t e_type; + uint16_t e_machine; + uint32_t e_version; +}; +_Static_assert (sizeof (struct elf_prefix) == EI_NIDENT + 8, + "padding in struct elf_prefix"); + +/* Reads the ELF header from PATH. Returns true if the header can be + read, false if the file is too short. */ +static bool +read_elf_header (const char *path, struct elf_prefix *elf) +{ + int fd = xopen (path, O_RDONLY, 0); + bool result = read (fd, elf, sizeof (*elf)) == sizeof (*elf); + xclose (fd); + return result; +} + +/* Searches for "gdb" alongside the path variable. See execvpe. */ +static char * +find_gdb (void) +{ + const char *path = getenv ("PATH"); + if (path == NULL) + return NULL; + while (true) + { + const char *colon = strchrnul (path, ':'); + char *candidate = xasprintf ("%.*s/gdb", (int) (colon - path), path); + if (access (candidate, X_OK) == 0) + return candidate; + free (candidate); + if (*colon == '\0') + break; + path = colon + 1; + } + return NULL; +} + /* Writes the GDB script to run the test to PATH. */ static void write_gdbscript (const char *path, int tested_pid) @@ -105,6 +152,33 @@ in_subprocess (void) static int do_test (void) { + char *gdb_path = find_gdb (); + if (gdb_path == NULL) + FAIL_UNSUPPORTED ("gdb command not found in PATH: %s", getenv ("PATH")); + + /* Check that libthread_db is compatible with the gdb architecture + because gdb loads it via dlopen. */ + { + char *threaddb_path = xasprintf ("%s/nptl_db/libthread_db.so", + support_objdir_root); + struct elf_prefix elf_threaddb; + TEST_VERIFY_EXIT (read_elf_header (threaddb_path, &elf_threaddb)); + struct elf_prefix elf_gdb; + /* If the ELF header cannot be read or "gdb" is not an ELF file, + assume this is a wrapper script that can run. */ + if (read_elf_header (gdb_path, &elf_gdb) + && memcmp (&elf_gdb, ELFMAG, SELFMAG) == 0) + { + if (elf_gdb.e_ident[EI_CLASS] != elf_threaddb.e_ident[EI_CLASS]) + FAIL_UNSUPPORTED ("GDB at %s has wrong class", gdb_path); + if (elf_gdb.e_ident[EI_DATA] != elf_threaddb.e_ident[EI_DATA]) + FAIL_UNSUPPORTED ("GDB at %s has wrong data", gdb_path); + if (elf_gdb.e_machine != elf_threaddb.e_machine) + FAIL_UNSUPPORTED ("GDB at %s has wrong machine", gdb_path); + } + free (threaddb_path); + } + pid_t tested_pid = xfork (); if (tested_pid == 0) in_subprocess (); @@ -117,9 +191,8 @@ do_test (void) pid_t gdb_pid = xfork (); if (gdb_pid == 0) { - clearenv (); xdup2 (STDOUT_FILENO, STDERR_FILENO); - execlp ("gdb", "gdb", "-nx", "-batch", "-x", gdbscript, NULL); + execl (gdb_path, "gdb", "-nx", "-batch", "-x", gdbscript, NULL); if (errno == ENOENT) _exit (EXIT_UNSUPPORTED); else @@ -137,6 +210,7 @@ do_test (void) free (tested_pid_string); free (gdbscript); + free (gdb_path); return 0; }