This is the mail archive of the
gdb-patches@sources.redhat.com
mailing list for the GDB project.
RFC: initial TLS patch
- From: Jim Blandy <jimb at redhat dot com>
- To: gdb-patches at sources dot redhat dot com
- Date: 02 Jul 2002 10:23:12 -0500
- Subject: 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;
}