From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id 96wbFYEzv2ffez4AWB0awg (envelope-from ) for ; Wed, 26 Feb 2025 10:30:09 -0500 Authentication-Results: simark.ca; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=Y0slYHa6; dkim-atps=neutral Received: by simark.ca (Postfix, from userid 112) id 488891E105; Wed, 26 Feb 2025 10:30:09 -0500 (EST) X-Spam-Checker-Version: SpamAssassin 4.0.0 (2022-12-13) on simark.ca X-Spam-Level: X-Spam-Status: No, score=-6.4 required=5.0 tests=ARC_SIGNED,ARC_VALID,BAYES_00, DKIMWL_WL_HIGH,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI, RCVD_IN_DNSWL_MED autolearn=ham autolearn_force=no version=4.0.0 Received: from server2.sourceware.org (server2.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by simark.ca (Postfix) with ESMTPS id DA70D1E05C for ; Wed, 26 Feb 2025 10:30:07 -0500 (EST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 85AF83858C53 for ; Wed, 26 Feb 2025 15:30:07 +0000 (GMT) Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTP id E90EB3858D35 for ; Wed, 26 Feb 2025 15:19:01 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org E90EB3858D35 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org E90EB3858D35 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1740583142; cv=none; b=GZZofgdlRp+/dQhMWQEQo4wP6VbNXK/oX+cmRKctfy9tcrIkWtxXLUjy60qcnJjnzx90IIAahEVfCSa/PufI022T3zNHxywwxC61/P+aWQ1Q1dk10qxuzglxU3CwXv6fJiEs2qNHXqtLfw5MEe0gVZ2PCjXiL3u3HBBwY0tJIvg= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1740583142; c=relaxed/simple; bh=v3fUsZD9uhWy/Gbps4KrU0VI6qcqWt+Ht8VzbzKl+hk=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=ksU9kPAtXnHaoh0S1wmNTQfipmughaaoBZAX7U1Opp0ZD/1YJppuxJaapCXrgmcnN7CyT+eZai91OhdcT8nfXBfI0DNvnABQvfIpJvsfmUJe+lt5I0mkRtp3HEgDWGiVs5M3e78BAAJKN82zkCwAJG0catgSUq+KgOIu0okBST0= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org E90EB3858D35 Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=Y0slYHa6 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1740583141; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=Z290LPcqffnyL2uf1Qfd87fKXp6fdUyOjWY3hQZA98c=; b=Y0slYHa6kYjbewL/Ox9Xg8VrC3FdGa7sJYsE4YWJwju5YJl67mEYj8F97Y/a5HvBMr587A pzplj6HQoTEsDguXftuH4epKi4/XS65bw7OXskqrJSAR5Nnica9MqMmOC5jOab9Zq7GIy2 PXGr2e1xnPDWI8wHhUnutRDmwQtNitw= Received: from mail-wm1-f72.google.com (mail-wm1-f72.google.com [209.85.128.72]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-641-1jhb8q87OdSBCMc6xDlY5Q-1; Wed, 26 Feb 2025 10:19:00 -0500 X-MC-Unique: 1jhb8q87OdSBCMc6xDlY5Q-1 X-Mimecast-MFC-AGG-ID: 1jhb8q87OdSBCMc6xDlY5Q_1740583139 Received: by mail-wm1-f72.google.com with SMTP id 5b1f17b1804b1-43aafafe6b7so18453125e9.1 for ; Wed, 26 Feb 2025 07:18:59 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1740583139; x=1741187939; h=mime-version:message-id:date:references:in-reply-to:subject:cc:to :from:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=Z290LPcqffnyL2uf1Qfd87fKXp6fdUyOjWY3hQZA98c=; b=e8V42XBZsBpq3rlkq6jw77tbY049/OCfTEn50llwCymOdhRMSLckC5l1djmDdQ9s5r RKUoNyoxyk2MfEoEaBu5qgGBYnZFQeQkU+sFNi7S1OGxN7cIYH4DkCLsgUQ8nQBsoSKj yNzdWwvu+RMx9Ckaj9DgtXp62cE8YCCFVkSSAxupNMpTf2djXyxuzDnrs80Q9FCbS48u /HzKzP/32d0OynJOXYXxWZmrzfrUjPVuMM4stgYfqT191nlEYxtpIC8pKH8NbhdZLwXh erX2zKLJFa0T/rb58XF0NEsV8SR+OxXchxJz3Zoqoo8qrN4vYXVZCCVNaEF7QpVabbfK Mqbg== X-Forwarded-Encrypted: i=1; AJvYcCXNQsK/0qZ6WEsxxj3LIUpBDyE/IBI+Por+yi5DF4ATEY32mSQx9CW2wYsw6d0ExHapWapDrXV3DNyZ2g==@sourceware.org X-Gm-Message-State: AOJu0YyOQzA+UP0SJnoSgykVBXxoTSzKnmdxrVPgh8zln79BhX4GQLbl p+7zU+OfdYfLsNEYSV5EA3ah6O2xfPMv4AvqJS2JaWFfhq5bHr5uw1jANiPtjSr4hKZ44yYPtdO qx+O2HPFDwnnA5wmHf37YRZos8GgKPE6Z802j4N+CxRC/5iV8/57zXS4GaG8= X-Gm-Gg: ASbGnctNgHdTofA8ior5fhCUDgaMg1/3fTU+XmfsgudL6x2IiAwQ1wAt8gTsNXmcCQO +c+HysJbH2LtFhRF1WEBdPVq5DI+XZZMud0m4kFDKiDfujICW4oRhCliMrV4lO9hQ31bBiSh7Yb Khd74aNM5zB+ifYlVQnFY/duWVug9h1dqOs5ui4crxnfBByq0KUBT14zXtyUM5h1V8VvCsXUclN /mdjB4TbJxKNgeTEUxoOM0ef8HzmnQ/y6vqLjtYLrkUr7qJl3lM3cTaiirGnnAVpehyXcvubssh claT52+bDjPadQL6P87UsFCqhfE54U7bHOI/F+ir X-Received: by 2002:a05:600c:1548:b0:439:6e08:f4 with SMTP id 5b1f17b1804b1-43ab90353eamr28855425e9.26.1740583138734; Wed, 26 Feb 2025 07:18:58 -0800 (PST) X-Google-Smtp-Source: AGHT+IGYJABBWvscrgSXx5dTBK3LsLEwd2ENtSyDTxHbIsVD0/8S9TFBNPpSoIY32aPrJBL3SD6Iyw== X-Received: by 2002:a05:600c:1548:b0:439:6e08:f4 with SMTP id 5b1f17b1804b1-43ab90353eamr28855115e9.26.1740583138201; Wed, 26 Feb 2025 07:18:58 -0800 (PST) Received: from localhost (44.226.159.143.dyn.plus.net. [143.159.226.44]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-390df3616c5sm874363f8f.4.2025.02.26.07.18.57 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 26 Feb 2025 07:18:57 -0800 (PST) From: Andrew Burgess To: Kevin Buettner , gdb-patches@sourceware.org Cc: tom@tromey.com, Kevin Buettner Subject: Re: [PATCH v5 03/11] Track and fetch TLS module ids for MUSL and GLIBC In-Reply-To: <20250131174747.921323-5-kevinb@redhat.com> References: <20250131174747.921323-2-kevinb@redhat.com> <20250131174747.921323-5-kevinb@redhat.com> Date: Wed, 26 Feb 2025 15:18:56 +0000 Message-ID: <8734g0buov.fsf@redhat.com> MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: wq3kQSY2sbm8ugZAlxLqu4Qc3JxYoIg_2akgiTyzUmg_1740583139 X-Mimecast-Originator: redhat.com Content-Type: text/plain X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~public-inbox=simark.ca@sourceware.org Kevin Buettner writes: > This commit adds, to solib-svr4.h and solib-svr4.c, functions > glibc_link_map_to_tls_module_id and musl_link_map_to_tls_module_id for > use with callers in linux-tdep.c (which is not in this commit). It > adds a number of helper functions for implementing link map to module > id support. > > It also renames existing function 'find_program_interpreter' to > 'svr4_find_program_interpreter' and makes it visible to other source > files within GDB. It will be used in the libc sniffing code in > linux-tdep.c in a later commit in this series. The libc sniffer is > needed in order to know which link map to module id function to call > as the method for determining module ids differs between libc / > dynamic linker implementations. These details are discussed in > comments in the patch. I'm not sure that doing this is the correct approach. While most Linux targets do seem to use svr4, looking through configure.tgt seems to indicate that the FRV target uses solib-frv, and the Blackfin Linux target doesn't seem to link against solib-svr4 either. There might be others. I just searched through that file looking for linux-tdep.o looking for targets that didn't also include solib-svr4.o. I suspect the right approach would be to add a new callback to the solib_ops structure, and then call that from linux-tdep code. Thanks, Andrew > > Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=24548 > Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=31563 > --- > gdb/solib-svr4.c | 203 ++++++++++++++++++++++++++++++++++++++++++++++- > gdb/solib-svr4.h | 12 +++ > 2 files changed, 211 insertions(+), 4 deletions(-) > > diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c > index 8378ecaff40..781e1396b8a 100644 > --- a/gdb/solib-svr4.c > +++ b/gdb/solib-svr4.c > @@ -405,6 +405,9 @@ struct svr4_info > The special entry zero is reserved for a linear list to support > gdbstubs that do not support namespaces. */ > std::map> solib_lists; > + > + bool glibc_tls_slots_inited = false; > + std::vector glibc_tls_slots; > }; > > /* Per-program-space data key. */ > @@ -586,10 +589,10 @@ read_program_header (int type, int *p_arch_size, CORE_ADDR *base_addr) > return buf; > } > > +/* See solib-svr4.h. */ > > -/* Return program interpreter string. */ > -static std::optional > -find_program_interpreter (void) > +std::optional > +svr4_find_program_interpreter () > { > /* If we have a current exec_bfd, use its section table. */ > if (current_program_space->exec_bfd () > @@ -1516,6 +1519,194 @@ svr4_fetch_objfile_link_map (struct objfile *objfile) > return 0; > } > > +/* Return true if bfd section BFD_SECT is a thread local section > + (i.e. either named ".tdata" or ".tbss"), and false otherwise. */ > + > +static bool > +is_thread_local_section (struct bfd_section *bfd_sect) > +{ > + return ((strcmp (bfd_sect->name, ".tdata") == 0 > + || strcmp (bfd_sect->name, ".tbss") == 0) > + && bfd_sect->size != 0); > +} > + > +/* Return true if objfile OBJF contains a thread local section, and > + false otherwise. */ > + > +static bool > +has_thread_local_section (const objfile *objf) > +{ > + for (obj_section *objsec : objf->sections ()) > + if (is_thread_local_section (objsec->the_bfd_section)) > + return true; > + return false; > +} > + > +/* Return true if solib SO contains a thread local section, and false > + otherwise. */ > + > +static bool > +has_thread_local_section (const solib &so) > +{ > + for (const target_section &p : so.sections) > + if (is_thread_local_section (p.the_bfd_section)) > + return true; > + return false; > +} > + > +/* For the MUSL C library, given link map address LM_ADDR, return the > + corresponding TLS module id, or 0 if not found. > + > + Background: Unlike the mechanism used by glibc (see below), the > + scheme used by the MUSL C library is pretty simple. If the > + executable contains TLS variables it gets module id 1. Otherwise, > + the first shared object loaded which contains TLS variables is > + assigned to module id 1. TLS-containing shared objects are then > + assigned consecutive module ids, based on the order that they are > + loaded. When unloaded via dlclose, module ids are reassigned as if > + that module had never been loaded. */ > + > +int > +musl_link_map_to_tls_module_id (CORE_ADDR lm_addr) > +{ > + /* When lm_addr is zero, the program is statically linked. Any TLS > + variables will be in module id 1. */ > + if (lm_addr == 0) > + return 1; > + > + int mod_id = 0; > + if (has_thread_local_section (current_program_space->symfile_object_file)) > + mod_id++; > + > + struct svr4_info *info = get_svr4_info (current_program_space); > + > + /* Cause svr4_current_sos() to be run if it hasn't been already. */ > + if (info->main_lm_addr == 0) > + solib_add (NULL, 0, auto_solib_add); > + > + /* Handle case where lm_addr corresponds to the main program. > + Return value is either 0, when there are no TLS variables, or 1, > + when there are. */ > + if (lm_addr == info->main_lm_addr) > + return mod_id; > + > + /* Iterate through the shared objects, possibly incrementing the > + module id, and returning mod_id should a match be found. */ > + for (const solib &so : current_program_space->solibs ()) > + { > + if (has_thread_local_section (so)) > + mod_id++; > + > + auto *li = gdb::checked_static_cast (so.lm_info.get ()); > + if (li->lm_addr == lm_addr) > + return mod_id; > + } > + return 0; > +} > + > +/* For GLIBC, given link map address LM_ADDR, return the corresponding TLS > + module id, or 0 if not found. */ > + > +int > +glibc_link_map_to_tls_module_id (CORE_ADDR lm_addr) > +{ > + /* When lm_addr is zero, the program is statically linked. Any TLS > + variables will be in module id 1. */ > + if (lm_addr == 0) > + return 1; > + > + /* Look up lm_addr in the TLS slot data structure. */ > + struct svr4_info *info = get_svr4_info (current_program_space); > + auto it = std::find (info->glibc_tls_slots.begin (), > + info->glibc_tls_slots.end (), > + lm_addr); > + if (it == info->glibc_tls_slots.end ()) > + return 0; > + else > + return 1 + it - info->glibc_tls_slots.begin (); > +} > + > +/* Conditionally, based on whether the shared object, SO, contains TLS > + variables, assign a link map address to a TLS module id slot. This > + code is GLIBC-specific and may only work for specific GLIBC > + versions. That said, it is known to work for (at least) GLIBC > + versions 2.27 thru 2.40. > + > + Background: In order to implement internal TLS address lookup > + code, it is necessary to find the module id that has been > + associated with a specific link map address. In GLIBC, the TLS > + module id is stored in struct link_map, in the member > + 'l_tls_modid'. While the first several members of struct link_map > + are part of the SVR4 ABI, the offset to l_tls_modid definitely is > + not. Therefore, since we don't know the offset to l_tls_modid, we > + cannot simply look it up - which is a shame, because things would > + be so much more easy and obviously accurate, if we could access > + l_tls_modid. > + > + GLIBC has a concept of TLS module id slots. These slots are > + allocated consecutively as shared objects containing TLS variables > + are loaded. When unloaded (e.g. via dlclose()), the corresponding > + slot is marked as unused, but may be used again when later loading > + a shared object. > + > + The functions tls_maybe_fill_slot and tls_maybe_erase_slot are > + associated with the observers 'solib_loaded' and 'solib_unloaded'. > + They (attempt to) track use of TLS module id slots in the same way > + that GLIBC does, which will hopefully provide an accurate module id > + when asked to provide it via glibc_link_map_to_tls_module_id(), > + above. */ > + > +static void > +tls_maybe_fill_slot (solib &so) > +{ > + struct svr4_info *info = get_svr4_info (current_program_space); > + if (!info->glibc_tls_slots_inited) > + { > + /* Cause svr4_current_sos() to be run if it hasn't been already. */ > + if (info->main_lm_addr == 0) > + svr4_current_sos_direct (info); > + > + /* Quit early when main_lm_addr is still 0. */ > + if (info->main_lm_addr == 0) > + return; > + > + /* Also quit early when symfile_object_file is not yet known. */ > + if (current_program_space->symfile_object_file == nullptr) > + return; > + > + if (has_thread_local_section (current_program_space->symfile_object_file)) > + info->glibc_tls_slots.push_back (info->main_lm_addr); > + info->glibc_tls_slots_inited = true; > + } > + > + if (has_thread_local_section (so)) > + { > + auto it = std::find (info->glibc_tls_slots.begin (), > + info->glibc_tls_slots.end (), > + 0); > + auto *li = gdb::checked_static_cast (so.lm_info.get ()); > + if (it == info->glibc_tls_slots.end ()) > + info->glibc_tls_slots.push_back (li->lm_addr); > + else > + *it = li->lm_addr; > + } > +} > + > +/* Remove a link map address from the TLS module slot data structure. > + As noted above, this code is GLIBC-specific. */ > + > +static void > +tls_maybe_erase_slot (program_space *pspace, const solib &so) > +{ > + struct svr4_info *info = get_svr4_info (pspace); > + auto *li = gdb::checked_static_cast (so.lm_info.get ()); > + auto it = std::find (info->glibc_tls_slots.begin (), > + info->glibc_tls_slots.end (), > + li->lm_addr); > + if (it != info->glibc_tls_slots.end ()) > + *it = 0; > +} > + > /* On some systems, the only way to recognize the link map entry for > the main executable file is by looking at its name. Return > non-zero iff SONAME matches one of the known main executable names. */ > @@ -2307,7 +2498,7 @@ enable_break (struct svr4_info *info, int from_tty) > /* Find the program interpreter; if not found, warn the user and drop > into the old breakpoint at symbol code. */ > std::optional interp_name_holder > - = find_program_interpreter (); > + = svr4_find_program_interpreter (); > if (interp_name_holder) > { > const char *interp_name = (const char *) interp_name_holder->data (); > @@ -3384,4 +3575,8 @@ _initialize_svr4_solib () > { > gdb::observers::free_objfile.attach (svr4_free_objfile_observer, > "solib-svr4"); > + > + /* Set up observers for tracking GLIBC TLS module id slots. */ > + gdb::observers::solib_loaded.attach (tls_maybe_fill_slot, "solib-svr4"); > + gdb::observers::solib_unloaded.attach (tls_maybe_erase_slot, "solib-svr4"); > } > diff --git a/gdb/solib-svr4.h b/gdb/solib-svr4.h > index 37cdaff4882..618eac52d72 100644 > --- a/gdb/solib-svr4.h > +++ b/gdb/solib-svr4.h > @@ -112,4 +112,16 @@ extern struct link_map_offsets *svr4_lp64_fetch_link_map_offsets (void); > SVR4 run time loader. */ > int svr4_in_dynsym_resolve_code (CORE_ADDR pc); > > +/* For the MUSL C library, given link map address LM_ADDR, return the > + corresponding TLS module id, or 0 if not found. */ > +int musl_link_map_to_tls_module_id (CORE_ADDR lm_addr); > + > +/* For GLIBC, given link map address LM_ADDR, return the corresponding TLS > + module id, or 0 if not found. */ > +int glibc_link_map_to_tls_module_id (CORE_ADDR lm_addr); > + > +/* Return program interpreter string. */ > + > +std::optional svr4_find_program_interpreter (); > + > #endif /* GDB_SOLIB_SVR4_H */ > -- > 2.48.0