From patchwork Sat Feb 9 00:40:10 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Baldwin X-Patchwork-Id: 31382 Received: (qmail 28441 invoked by alias); 9 Feb 2019 00:42:45 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 28231 invoked by uid 89); 9 Feb 2019 00:42:43 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-24.7 required=5.0 tests=BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_STOCKGEN, SPF_HELO_PASS, SPF_SOFTFAIL autolearn=ham version=3.3.2 spammy=internal_error, sk:bmsymbo, UD:minsym, sk:BMSYMBO X-HELO: mail.baldwin.cx Received: from bigwig.baldwin.cx (HELO mail.baldwin.cx) (96.47.65.170) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Sat, 09 Feb 2019 00:42:41 +0000 Received: from ralph.com (ralph.baldwin.cx [66.234.199.215]) by mail.baldwin.cx (Postfix) with ESMTPSA id BE44E10B716 for ; Fri, 8 Feb 2019 19:42:38 -0500 (EST) From: John Baldwin To: gdb-patches@sourceware.org Subject: [PATCH v2 07/11] Add a helper function to resolve TLS variable addresses for FreeBSD. Date: Fri, 8 Feb 2019 16:40:10 -0800 Message-Id: In-Reply-To: References: MIME-Version: 1.0 X-IsSubscribed: yes The fbsd_get_thread_local_address function accepts the base address of a thread's DTV array and the base address of an object file's link map and uses this to compute a TLS variable's address. FreeBSD architectures use an architecture-specific method to determine the address of the DTV array pointer and call this helper function to perform the rest of the address calculation. * fbsd-tdep.c (fbsd_pspace_data_handle): New variable. (struct fbsd_pspace_data): New type. (get_fbsd_pspace_data, fbsd_pspace_data_cleanup) (fbsd_read_integer_by_name, fbsd_fetch_rtld_offsets) (fbsd_get_tls_index, fbsd_get_thread_local_address): New function. (_initialize_fbsd_tdep): Initialize 'fbsd_pspace_data_handle'. * fbsd-tdep.c (fbsd_get_thread_local_address): New prototype. --- gdb/ChangeLog | 10 ++++ gdb/fbsd-tdep.c | 153 ++++++++++++++++++++++++++++++++++++++++++++++++ gdb/fbsd-tdep.h | 10 ++++ 3 files changed, 173 insertions(+) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index c7fee7eb11..387d5c1aee 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,13 @@ +2019-02-08 John Baldwin + + * fbsd-tdep.c (fbsd_pspace_data_handle): New variable. + (struct fbsd_pspace_data): New type. + (get_fbsd_pspace_data, fbsd_pspace_data_cleanup) + (fbsd_read_integer_by_name, fbsd_fetch_rtld_offsets) + (fbsd_get_tls_index, fbsd_get_thread_local_address): New function. + (_initialize_fbsd_tdep): Initialize 'fbsd_pspace_data_handle'. + * fbsd-tdep.c (fbsd_get_thread_local_address): New prototype. + 2019-02-08 John Baldwin * gdbtypes.c (lookup_struct_elt): New function. diff --git a/gdb/fbsd-tdep.c b/gdb/fbsd-tdep.c index d971d3a653..59d7c30f73 100644 --- a/gdb/fbsd-tdep.c +++ b/gdb/fbsd-tdep.c @@ -24,6 +24,7 @@ #include "regcache.h" #include "regset.h" #include "gdbthread.h" +#include "objfiles.h" #include "xml-syscall.h" #include #include @@ -444,6 +445,41 @@ get_fbsd_gdbarch_data (struct gdbarch *gdbarch) gdbarch_data (gdbarch, fbsd_gdbarch_data_handle)); } +/* Per-program-space data for FreeBSD architectures. */ +static const struct program_space_data *fbsd_pspace_data_handle; + +struct fbsd_pspace_data + { + /* Offsets in the runtime linker's 'Obj_Entry' structure. */ + LONGEST off_linkmap; + LONGEST off_tlsindex; + bool rtld_offsets_valid; + }; + +static struct fbsd_pspace_data * +get_fbsd_pspace_data (struct program_space *pspace) +{ + struct fbsd_pspace_data *data; + + data = ((struct fbsd_pspace_data *) + program_space_data (pspace, fbsd_pspace_data_handle)); + if (data == NULL) + { + data = XCNEW (struct fbsd_pspace_data); + set_program_space_data (pspace, fbsd_pspace_data_handle, data); + } + + return data; +} + +/* The cleanup callback for FreeBSD architecture per-program-space data. */ + +static void +fbsd_pspace_data_cleanup (struct program_space *pspace, void *data) +{ + xfree (data); +} + /* This is how we want PTIDs from core files to be printed. */ static const char * @@ -1932,6 +1968,121 @@ fbsd_get_syscall_number (struct gdbarch *gdbarch, thread_info *thread) internal_error (__FILE__, __LINE__, _("fbsd_get_sycall_number called")); } +/* Read an integer symbol value from the current target. */ + +static LONGEST +fbsd_read_integer_by_name (struct gdbarch *gdbarch, const char *name) +{ + bound_minimal_symbol ms = lookup_minimal_symbol (name, NULL, NULL); + if (ms.minsym == NULL) + error (_("Unable to resolve symbol '%s'"), name); + + gdb_byte buf[4]; + if (target_read_memory (BMSYMBOL_VALUE_ADDRESS (ms), buf, sizeof buf) != 0) + error (_("Unable to read value of '%s'"), name); + + return extract_signed_integer (buf, sizeof buf, gdbarch_byte_order (gdbarch)); +} + +/* Lookup offsets of fields in the runtime linker's 'Obj_Entry' + structure needed to determine the TLS index of an object file. */ + +static void +fbsd_fetch_rtld_offsets (struct gdbarch *gdbarch, struct fbsd_pspace_data *data) +{ + TRY + { + /* Fetch offsets from debug symbols in rtld. */ + struct symbol *obj_entry_sym + = lookup_symbol_in_language ("Struct_Obj_Entry", NULL, STRUCT_DOMAIN, + language_c, NULL).symbol; + if (obj_entry_sym == NULL) + error (_("Unable to find Struct_Obj_Entry symbol")); + data->off_linkmap = lookup_struct_elt (SYMBOL_TYPE(obj_entry_sym), + "linkmap", 0).offset / 8; + data->off_tlsindex = lookup_struct_elt (SYMBOL_TYPE(obj_entry_sym), + "tlsindex", 0).offset / 8; + data->rtld_offsets_valid = true; + return; + } + CATCH (e, RETURN_MASK_ERROR) + { + data->off_linkmap = -1; + } + END_CATCH + + TRY + { + /* Fetch offsets from global variables in libthr. Note that + this does not work for single-threaded processes that are not + linked against libthr. */ + data->off_linkmap = fbsd_read_integer_by_name(gdbarch, + "_thread_off_linkmap"); + data->off_tlsindex = fbsd_read_integer_by_name(gdbarch, + "_thread_off_tlsindex"); + data->rtld_offsets_valid = true; + return; + } + CATCH (e, RETURN_MASK_ERROR) + { + data->off_linkmap = -1; + } + END_CATCH +} + +/* Helper function to read the TLS index of an object file associated + with a link map entry at LM_ADDR. */ + +static LONGEST +fbsd_get_tls_index (struct gdbarch *gdbarch, CORE_ADDR lm_addr) +{ + struct fbsd_pspace_data *data = get_fbsd_pspace_data (current_program_space); + + if (!data->rtld_offsets_valid) + fbsd_fetch_rtld_offsets (gdbarch, data); + + if (data->off_linkmap == -1) + throw_error (TLS_GENERIC_ERROR, + _("Cannot fetch runtime linker structure offsets")); + + /* Simulate container_of to convert from LM_ADDR to the Obj_Entry + pointer and then compute the offset of the tlsindex member. */ + CORE_ADDR tlsindex_addr = lm_addr - data->off_linkmap + data->off_tlsindex; + + gdb_byte buf[4]; + if (target_read_memory (tlsindex_addr, buf, sizeof buf) != 0) + throw_error (TLS_GENERIC_ERROR, + _("Cannot find thread-local variables on this target")); + + return extract_signed_integer (buf, sizeof buf, gdbarch_byte_order (gdbarch)); +} + +/* See fbsd-tdep.h. */ + +CORE_ADDR +fbsd_get_thread_local_address (struct gdbarch *gdbarch, CORE_ADDR dtv_addr, + CORE_ADDR lm_addr, CORE_ADDR offset) +{ + LONGEST tls_index = fbsd_get_tls_index (gdbarch, lm_addr); + + gdb_byte buf[gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT]; + if (target_read_memory (dtv_addr, buf, sizeof buf) != 0) + throw_error (TLS_GENERIC_ERROR, + _("Cannot find thread-local variables on this target")); + + const struct builtin_type *builtin = builtin_type (gdbarch); + CORE_ADDR addr = gdbarch_pointer_to_address (gdbarch, + builtin->builtin_data_ptr, buf); + + addr += (tls_index + 1) * TYPE_LENGTH (builtin->builtin_data_ptr); + if (target_read_memory (addr, buf, sizeof buf) != 0) + throw_error (TLS_GENERIC_ERROR, + _("Cannot find thread-local variables on this target")); + + addr = gdbarch_pointer_to_address (gdbarch, builtin->builtin_data_ptr, buf); + return addr + offset; +} + /* To be called from GDB_OSABI_FREEBSD handlers. */ void @@ -1957,4 +2108,6 @@ _initialize_fbsd_tdep (void) { fbsd_gdbarch_data_handle = gdbarch_data_register_post_init (init_fbsd_gdbarch_data); + fbsd_pspace_data_handle + = register_program_space_data_with_cleanup (NULL, fbsd_pspace_data_cleanup); } diff --git a/gdb/fbsd-tdep.h b/gdb/fbsd-tdep.h index efd7c2c78f..0b4d1e92c7 100644 --- a/gdb/fbsd-tdep.h +++ b/gdb/fbsd-tdep.h @@ -60,4 +60,14 @@ extern void fbsd_info_proc_mappings_entry (int addr_bit, ULONGEST kve_start, int kve_flags, int kve_protection, const void *kve_path); +/* Helper function to fetch the address of a thread-local variable. + DTV_ADDR is the base address of the thread's dtv array. LM_ADDR is + the address of the link_map structure for the associated object + file. */ + +extern CORE_ADDR fbsd_get_thread_local_address (struct gdbarch *gdbarch, + CORE_ADDR dtv_addr, + CORE_ADDR lm_addr, + CORE_ADDR offset); + #endif /* fbsd-tdep.h */