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]

Re: RFC: initial TLS patch


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 <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]