From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 10060 invoked by alias); 2 Jul 2002 23:47:29 -0000 Mailing-List: contact gdb-patches-help@sources.redhat.com; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sources.redhat.com Received: (qmail 9992 invoked from network); 2 Jul 2002 23:47:24 -0000 Received: from unknown (HELO cygnus.com) (205.180.83.203) by sources.redhat.com with SMTP; 2 Jul 2002 23:47:24 -0000 Received: from redhat.com (reddwarf.sfbay.redhat.com [172.16.24.50]) by runyon.cygnus.com (8.8.7-cygnus/8.8.7) with ESMTP id QAA07595; Tue, 2 Jul 2002 16:47:05 -0700 (PDT) Message-ID: <3D223796.A3911C80@redhat.com> Date: Wed, 03 Jul 2002 02:39:00 -0000 From: Michael Snyder Organization: Red Hat, Inc. X-Accept-Language: en MIME-Version: 1.0 To: Jim Blandy CC: gdb-patches@sources.redhat.com Subject: Re: RFC: initial TLS patch References: Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit X-SW-Source: 2002-07/txt/msg00053.txt.bz2 Jim Blandy wrote: > > This is a work-in-progress, posted for comments. This code has never > been executed, since I only last night got glibc and GCC to actually > compile and run a program that uses `__thread', and GCC doesn't yet > emit the Dwarf 2 extension for thread-local variables. > > If you actually want to try it out, remember to run both autoheader > and autoconf after patching configure.in. But I'm mostly just hoping > for eyeball reviews. As a preliminary comment, I think the design is pretty sound. I haven't finished my "eyeball review", but I hope to look at it some more tomorrow (before the 4th of july break). One thing -- I'm a little leary about the target module actually building a struct value. Seems like that should be done at a higher level. Michael > > Index: gdb/configure.in > =================================================================== > RCS file: /cvs/src/src/gdb/configure.in,v > retrieving revision 1.88 > diff -c -r1.88 configure.in > *** gdb/configure.in 21 Jun 2002 23:48:39 -0000 1.88 > --- gdb/configure.in 29 Jun 2002 03:38:37 -0000 > *************** > *** 599,604 **** > --- 599,621 ---- > AC_SUBST(CONFIG_LDFLAGS) > fi > > + dnl See if we have a thread_db header file that #defines TD_NOTALLOC. > + if test "x$ac_cv_header_thread_db_h" = "xyes"; then > + AC_CACHE_CHECK([whether defines TD_NOTALLOC], > + gdb_cv_thread_db_h_defines_td_notalloc, > + AC_TRY_COMPILE( > + [#include ], > + [int i = TD_NOTALLOC;], > + gdb_cv_thread_db_h_defines_td_notalloc=yes, > + gdb_cv_thread_db_h_defines_td_notalloc=no > + ) > + ) > + fi > + if test "x$gdb_cv_thread_db_h_defines_td_notalloc" = "xyes"; then > + AC_DEFINE(THREAD_DB_DEFINES_TD_NOTALLOC, 1, > + [Define if defines the TD_NOTALLOC error code.]) > + fi > + > dnl The CLI cannot be disabled yet, but may be in the future > > dnl Handle CLI sub-directory configury. > Index: gdb/dwarf2read.c > =================================================================== > RCS file: /cvs/src/src/gdb/dwarf2read.c,v > retrieving revision 1.60 > diff -c -r1.60 dwarf2read.c > *** gdb/dwarf2read.c 22 Jun 2002 00:05:59 -0000 1.60 > --- gdb/dwarf2read.c 29 Jun 2002 03:38:40 -0000 > *************** > *** 389,394 **** > --- 389,400 ---- > this function, so we can't say > which register it's relative to; > use LOC_LOCAL. */ > + static int is_thread_local; /* Variable is at a constant offset in the > + thread-local storage block for the > + current thread and the dynamic linker > + module containing this expression. > + decode_locdesc returns the offset from > + that base. */ > > /* DW_AT_frame_base values for the current function. > frame_base_reg is -1 if DW_AT_frame_base is missing, otherwise it > *************** > *** 4652,4657 **** > --- 4658,4669 ---- > { > SYMBOL_CLASS (sym) = LOC_LOCAL; > } > + else if (is_thread_local) > + { > + SYMBOL_CLASS (sym) = LOC_THREAD_LOCAL_STATIC; > + SYMBOL_OBJFILE (sym) = objfile; > + SYMBOL_VALUE_ADDRESS (sym) = addr; > + } > else > { > fixup_symbol_section (sym, objfile); > *************** > *** 6152,6157 **** > --- 6164,6170 ---- > offreg = 0; > isderef = 0; > islocal = 0; > + is_thread_local = 0; > optimized_out = 1; > > while (i < size) > *************** > *** 6374,6379 **** > --- 6387,6397 ---- > if (i < size) > complain (&dwarf2_complex_location_expr); > break; > + > + case DW_OP_GNU_push_tls_address: > + is_thread_local = 1; > + stack[++stacki] = 0; > + break; > > default: > complain (&dwarf2_unsupported_stack_op, dwarf_stack_op_name (op)); > Index: gdb/findvar.c > =================================================================== > RCS file: /cvs/src/src/gdb/findvar.c,v > retrieving revision 1.34 > diff -c -r1.34 findvar.c > *** gdb/findvar.c 15 May 2002 01:01:56 -0000 1.34 > --- gdb/findvar.c 29 Jun 2002 03:38:40 -0000 > *************** > *** 529,535 **** > > case LOC_BASEREG: > case LOC_BASEREG_ARG: > - case LOC_THREAD_LOCAL_STATIC: > { > struct value *regval; > > --- 529,534 ---- > *************** > *** 540,545 **** > --- 539,564 ---- > addr = value_as_address (regval); > addr += SYMBOL_VALUE (var); > break; > + } > + > + case LOC_THREAD_LOCAL_STATIC: > + { > + /* We want to let the target / ABI-specific code construct > + this value for us, so we need to dispose of the value > + allocated for us above. */ > + release_value (v); > + value_free (v); > + if (target_has_get_thread_local_value ()) > + return target_get_thread_local_value (inferior_ptid, > + SYMBOL_OBJFILE (var), > + SYMBOL_VALUE (var), > + SYMBOL_TYPE (var)); > + /* It wouldn't be wrong here to try a gdbarch method, too; > + finding TLS is an ABI-specific thing. But we don't do that > + yet. */ > + else > + error ("Cannot find thread-local variables on this target"); > + break; > } > > case LOC_TYPEDEF: > Index: gdb/gdb_thread_db.h > =================================================================== > RCS file: /cvs/src/src/gdb/gdb_thread_db.h,v > retrieving revision 1.3 > diff -c -r1.3 gdb_thread_db.h > *** gdb/gdb_thread_db.h 6 Mar 2001 08:21:07 -0000 1.3 > --- gdb/gdb_thread_db.h 29 Jun 2002 03:38:40 -0000 > *************** > *** 63,69 **** > TD_NOTSD, /* No thread-specific data available. */ > TD_MALLOC, /* Out of memory. */ > TD_PARTIALREG, /* Not entire register set was read or written. */ > ! TD_NOXREGS /* X register set not available for given thread. */ > } td_err_e; > > > --- 63,70 ---- > TD_NOTSD, /* No thread-specific data available. */ > TD_MALLOC, /* Out of memory. */ > TD_PARTIALREG, /* Not entire register set was read or written. */ > ! TD_NOXREGS, /* X register set not available for given thread. */ > ! TD_NOTALLOC /* TLS memory not yet allocated. */ > } td_err_e; > > > Index: gdb/hpread.c > =================================================================== > RCS file: /cvs/src/src/gdb/hpread.c,v > retrieving revision 1.21 > diff -c -r1.21 hpread.c > *** gdb/hpread.c 14 Jun 2002 14:34:25 -0000 1.21 > --- gdb/hpread.c 29 Jun 2002 03:38:44 -0000 > *************** > *** 5743,5749 **** > { > /* Thread-local variable. > */ > ! SYMBOL_CLASS (sym) = LOC_THREAD_LOCAL_STATIC; > SYMBOL_BASEREG (sym) = CR27_REGNUM; > > if (objfile->flags & OBJF_SHARED) > --- 5743,5749 ---- > { > /* Thread-local variable. > */ > ! SYMBOL_CLASS (sym) = LOC_BASEREG; > SYMBOL_BASEREG (sym) = CR27_REGNUM; > > if (objfile->flags & OBJF_SHARED) > Index: gdb/printcmd.c > =================================================================== > RCS file: /cvs/src/src/gdb/printcmd.c,v > retrieving revision 1.39 > diff -c -r1.39 printcmd.c > *** gdb/printcmd.c 11 May 2002 23:48:23 -0000 1.39 > --- gdb/printcmd.c 29 Jun 2002 03:38:45 -0000 > *************** > *** 1275,1283 **** > break; > > case LOC_THREAD_LOCAL_STATIC: > ! printf_filtered ( > ! "a thread-local variable at offset %ld from the thread base register %s", > ! val, REGISTER_NAME (basereg)); > break; > > case LOC_OPTIMIZED_OUT: > --- 1275,1283 ---- > break; > > case LOC_THREAD_LOCAL_STATIC: > ! printf_filtered ("a thread-local variable at offset %ld in the " > ! "thread-local storage for `%s'", > ! val, SYMBOL_OBJFILE (sym)->name); > break; > > case LOC_OPTIMIZED_OUT: > Index: gdb/solib.c > =================================================================== > RCS file: /cvs/src/src/gdb/solib.c,v > retrieving revision 1.50 > diff -c -r1.50 solib.c > *** gdb/solib.c 12 May 2002 04:20:06 -0000 1.50 > --- gdb/solib.c 29 Jun 2002 03:38:46 -0000 > *************** > *** 843,848 **** > --- 843,870 ---- > do_clear_solib (NULL); > } > > + > + /* Search the current shared library list for an entry whose object > + file is OBJFILE. Return zero if there is no such entry. */ > + struct so_list * > + get_solib_by_objfile (struct objfile *objfile) > + { > + struct so_list *l; > + > + for (l = so_list_head; l; l = l->next) > + if (l->objfile == objfile) > + return l; > + > + /* Refresh our list from the inferior, and try again. */ > + update_solib_list (0, 0); > + for (l = so_list_head; l; l = l->next) > + if (l->objfile == objfile) > + return l; > + > + return 0; > + } > + > + > void > _initialize_solib (void) > { > Index: gdb/solist.h > =================================================================== > RCS file: /cvs/src/src/gdb/solist.h,v > retrieving revision 1.7 > diff -c -r1.7 solist.h > *** gdb/solist.h 21 Oct 2001 19:20:30 -0000 1.7 > --- gdb/solist.h 29 Jun 2002 03:38:46 -0000 > *************** > *** 106,111 **** > --- 106,114 ---- > /* Find solib binary file and open it. */ > extern int solib_open (char *in_pathname, char **found_pathname); > > + /* Return the so_list entry whose object file is OBJFILE. */ > + extern struct so_list *get_solib_by_objfile (struct objfile *OBJFILE); > + > /* FIXME: gdbarch needs to control this variable */ > extern struct target_so_ops *current_target_so_ops; > > Index: gdb/symtab.h > =================================================================== > RCS file: /cvs/src/src/gdb/symtab.h,v > retrieving revision 1.32 > diff -c -r1.32 symtab.h > *** gdb/symtab.h 15 May 2002 21:19:21 -0000 1.32 > --- gdb/symtab.h 29 Jun 2002 03:38:47 -0000 > *************** > *** 587,594 **** > LOC_UNRESOLVED, > > /* Value is at a thread-specific location calculated by a > ! target-specific method. */ > ! > LOC_THREAD_LOCAL_STATIC, > > /* The variable does not actually exist in the program. > --- 587,596 ---- > LOC_UNRESOLVED, > > /* Value is at a thread-specific location calculated by a > ! target-specific method. SYMBOL_OBJFILE gives the object file > ! in which the symbol is defined; the symbol's value is the > ! offset into that objfile's thread-local storage for the current > ! thread. */ > LOC_THREAD_LOCAL_STATIC, > > /* The variable does not actually exist in the program. > *************** > *** 661,670 **** > { > /* Used by LOC_BASEREG and LOC_BASEREG_ARG. */ > short basereg; > } > aux_value; > > - > /* Link to a list of aliases for this symbol. > Only a "primary/main symbol may have aliases. */ > struct alias_list *aliases; > --- 663,677 ---- > { > /* Used by LOC_BASEREG and LOC_BASEREG_ARG. */ > short basereg; > + > + /* The objfile in which this symbol is defined. To find a > + thread-local variable (e.g., a variable declared with the > + `__thread' storage class), we may need to know which shared > + library it's in. */ > + struct objfile *objfile; > } > aux_value; > > /* Link to a list of aliases for this symbol. > Only a "primary/main symbol may have aliases. */ > struct alias_list *aliases; > *************** > *** 680,685 **** > --- 687,693 ---- > #define SYMBOL_TYPE(symbol) (symbol)->type > #define SYMBOL_LINE(symbol) (symbol)->line > #define SYMBOL_BASEREG(symbol) (symbol)->aux_value.basereg > + #define SYMBOL_OBJFILE(symbol) (symbol)->aux_value.objfile > #define SYMBOL_ALIASES(symbol) (symbol)->aliases > #define SYMBOL_RANGES(symbol) (symbol)->ranges > > Index: gdb/target.c > =================================================================== > RCS file: /cvs/src/src/gdb/target.c,v > retrieving revision 1.36 > diff -c -r1.36 target.c > *** gdb/target.c 15 Jun 2002 21:07:58 -0000 1.36 > --- gdb/target.c 29 Jun 2002 03:38:48 -0000 > *************** > *** 610,615 **** > --- 610,616 ---- > INHERIT (to_async_mask_value, t); > INHERIT (to_find_memory_regions, t); > INHERIT (to_make_corefile_notes, t); > + INHERIT (to_get_thread_local_value, t); > INHERIT (to_magic, t); > > #undef INHERIT > Index: gdb/target.h > =================================================================== > RCS file: /cvs/src/src/gdb/target.h,v > retrieving revision 1.24 > diff -c -r1.24 target.h > *** gdb/target.h 18 Apr 2002 18:09:06 -0000 1.24 > --- gdb/target.h 29 Jun 2002 03:38:49 -0000 > *************** > *** 180,186 **** > /* Returns zero to leave the inferior alone, one to interrupt it. */ > extern int (*target_activity_function) (void); > > ! struct thread_info; /* fwd decl for parameter list below: */ > > struct target_ops > { > --- 180,191 ---- > /* Returns zero to leave the inferior alone, one to interrupt it. */ > extern int (*target_activity_function) (void); > > ! > ! /* Forward declarations for these structure tags, used in target > ! operation parameter lists. */ > ! struct thread_info; > ! struct value; > ! struct type; > > struct target_ops > { > *************** > *** 319,324 **** > --- 324,341 ---- > void *), > void *); > char * (*to_make_corefile_notes) (bfd *, int *); > + > + /* Return the thread-local value of type TYPE at OFFSET in the > + thread-local storage for the thread PTID and the shared library > + or executable file given by OBJFILE. If that block of > + thread-local storage hasn't been allocated yet, this function > + may return an error, or try to concoct an appropriate > + (non-lvalue) value based on the initialization image. */ > + struct value *(*to_get_thread_local_value) (ptid_t PTID, > + struct objfile *OBJFILE, > + CORE_ADDR OFFSET, > + struct type *TYPE); > + > int to_magic; > /* Need sub-structure for target machine related rather than comm related? > */ > *************** > *** 1021,1026 **** > --- 1038,1050 ---- > > #define target_make_corefile_notes(BFD, SIZE_P) \ > (current_target.to_make_corefile_notes) (BFD, SIZE_P) > + > + > + /* Thread-local values. */ > + #define target_get_thread_local_value \ > + (current_target.to_get_thread_local_value) > + #define target_has_get_thread_local_value() \ > + (target_get_thread_local_value != 0) > > /* Hook to call target-dependent code after reading in a new symbol table. */ > > Index: gdb/thread-db.c > =================================================================== > RCS file: /cvs/src/src/gdb/thread-db.c,v > retrieving revision 1.22 > diff -c -r1.22 thread-db.c > *** gdb/thread-db.c 23 Mar 2002 17:38:13 -0000 1.22 > --- gdb/thread-db.c 29 Jun 2002 03:38:49 -0000 > *************** > *** 32,37 **** > --- 32,40 ---- > #include "objfiles.h" > #include "target.h" > #include "regcache.h" > + #include "solib.h" > + #include "solist.h" > + #include "value.h" > > #ifndef LIBTHREAD_DB_SO > #define LIBTHREAD_DB_SO "libthread_db.so.1" > *************** > *** 108,113 **** > --- 111,122 ---- > prgregset_t gregs); > static td_err_e (*td_thr_event_enable_p) (const td_thrhandle_t *th, int event); > > + struct link_map; > + static td_err_e (*td_thr_tls_get_addr_p) (const td_thrhandle_t *th, > + struct link_map *map, > + size_t offset, > + void **address); > + > /* Location of the thread creation event breakpoint. The code at this > location in the child process will be called by the pthread library > whenever a new thread is created. By setting a special breakpoint > *************** > *** 348,353 **** > --- 357,363 ---- > td_ta_set_event_p = dlsym (handle, "td_ta_set_event"); > td_ta_event_getmsg_p = dlsym (handle, "td_ta_event_getmsg"); > td_thr_event_enable_p = dlsym (handle, "td_thr_event_enable"); > + td_thr_tls_get_addr_p = dlsym (handle, "td_thr_tls_get_addr"); > > return 1; > } > *************** > *** 1003,1008 **** > --- 1013,1095 ---- > return normal_pid_to_str (ptid); > } > > + static struct value * > + thread_db_get_thread_local_value (ptid_t ptid, struct objfile *objfile, > + CORE_ADDR offset, struct type *type) > + { > + if (is_thread (ptid)) > + { > + struct so_list *so; > + int objfile_is_library = (objfile->flags & OBJF_SHARED); > + td_err_e err; > + td_thrhandle_t th; > + void *address; > + > + if (! td_thr_tls_get_addr_p) > + error ("Cannot find thread-local variables in this thread library."); > + > + so = get_solib_by_objfile (objfile); > + if (! so) > + error ((objfile_is_library > + ? ("Cannot find shared library `%s' in dynamic linker's " > + "module list") > + : ("Cannot find executable file `%s' in dynamic linker's " > + "module list")), > + objfile->name); > + > + if (! so->lm_info) > + error ("Missing `struct link_map' value in GDB's shared library list"); > + > + err = td_ta_map_id2thr_p (thread_agent, GET_THREAD (ptid), &th); > + if (err != TD_OK) > + error ("Cannot find thread %ld: %s", > + (long) GET_THREAD (ptid), thread_db_err_str (err)); > + > + /* That cast there is pretty icky. But thread_db's interface > + isn't cross-debugging clean, so there's not much we can do > + about it. */ > + err = td_thr_tls_get_addr_p (&th, (struct link_map *) so->lm_info, > + offset, &address); > + > + #ifdef THREAD_DB_DEFINES_TD_NOTALLOC > + if (err == TD_NOTALLOC) > + /* Now, if libthread_db provided the initialization image's > + address, we *could* try to build a non-lvalue value from > + the initialization image. */ > + error ((objfile_is_library > + ? ("The inferior has not yet allocated storage for" > + " thread-local variables in\n" > + "the shared library `%s'\n" > + "for the thread %ld") > + : ("The inferior has not yet allocated storage for" > + " thread-local variables in\n" > + "the executable `%s'\n" > + "for the thread %ld")), > + objfile->name, > + (long) GET_THREAD (ptid)); > + #endif > + > + if (err != TD_OK) > + error ((objfile_is_library > + ? ("Cannot find thread-local storage for thread %ld, " > + "shared library %s:\n%s") > + : ("Cannot find thread-local storage for thread %ld, " > + "executable file %s:\n%s")), > + (long) GET_THREAD (ptid), > + objfile->name, > + thread_db_err_str (err)); > + > + /* Another cast assuming host == target. Joy. */ > + return value_at_lazy (type, (CORE_ADDR) address, 0); > + } > + > + if (target_beneath->to_get_thread_local_value) > + return target_beneath->to_get_thread_local_value (ptid, objfile, > + offset, type); > + > + error ("Cannot find thread-local values on this target."); > + } > + > static void > init_thread_db_ops (void) > { > *************** > *** 1025,1030 **** > --- 1112,1118 ---- > thread_db_ops.to_pid_to_str = thread_db_pid_to_str; > thread_db_ops.to_stratum = thread_stratum; > thread_db_ops.to_has_thread_control = tc_schedlock; > + thread_db_ops.to_get_thread_local_value = thread_db_get_thread_local_value; > thread_db_ops.to_magic = OPS_MAGIC; > } >