This is the mail archive of the gdb-patches@sources.redhat.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

RFC: initial TLS patch


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.

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 <thread_db.h> defines TD_NOTALLOC],
+                   gdb_cv_thread_db_h_defines_td_notalloc,
+      AC_TRY_COMPILE(
+        [#include <thread_db.h>],
+        [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 <thread_db.h> 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;
  }
  


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]