TLS variables access for -static -lpthread executables

Jan Kratochvil jan.kratochvil@redhat.com
Wed Mar 26 18:21:00 GMT 2014


Hi,

Reproducer:
gcc -g -o tlsvar tlsvar.c -pthread -static; gdb ./tlsvar -ex 'b 12' -ex r -ex 'info thread' -ex 'p *thread_local_p'

Actual output:
Cannot find executable file `.../tlsvar' in dynamic linker's load module list

Expected output:
$1 = 10 (or 20 or 30)

With -static there is no _r_debug, no link_map, no '.dynamic' section so there
is nothing to pass as 'psaddr_t __map_address' for td_thr_tls_get_addr.

Attached GDB fix that uses td_thr_tlsbase() instead of td_thr_tls_get_addr()
and pass 'modid' as value 1.  But I haven't found it documented anywhere.

Is such patch acceptable for upstream GDB or is there some better way with
glibc?


Thanks,
Jan
-------------- next part --------------
#include <pthread.h>
#include <stdio.h>

__thread int *thread_local_p;

void *start_routine(void *arg)
{
  int i = (int)(long)arg;
  thread_local_p = &i;
  printf ("thread_local_p: & == %016lx, . == %016lx, * == %d\n",
	  (long)&thread_local_p, (long)thread_local_p, *thread_local_p);
  return arg;
}

main()
{
  pthread_t handle1, handle2, handle3;
  pthread_create(&handle1, NULL, &start_routine, (void *)10);
  pthread_create(&handle2, NULL, &start_routine, (void *)20);
  pthread_create(&handle3, NULL, &start_routine, (void *)30);
  start_routine((void *)0);
  pthread_join(handle1, NULL);
  pthread_join(handle2, NULL);
  pthread_join(handle3, NULL);
}
-------------- next part --------------
diff --git a/gdb/linux-thread-db.c b/gdb/linux-thread-db.c
index ca614a3..092a896 100644
--- a/gdb/linux-thread-db.c
+++ b/gdb/linux-thread-db.c
@@ -196,6 +196,9 @@ struct thread_db_info
   td_err_e (*td_thr_tls_get_addr_p) (const td_thrhandle_t *th,
 				     psaddr_t map_address,
 				     size_t offset, psaddr_t *address);
+  td_err_e (*td_thr_tlsbase_p) (const td_thrhandle_t *th,
+				unsigned long int modid,
+				psaddr_t *base);
 };
 
 /* List of known processes using thread_db, and the required
@@ -799,6 +802,7 @@ try_thread_db_load_1 (struct thread_db_info *info)
   info->td_ta_event_getmsg_p = dlsym (info->handle, "td_ta_event_getmsg");
   info->td_thr_event_enable_p = dlsym (info->handle, "td_thr_event_enable");
   info->td_thr_tls_get_addr_p = dlsym (info->handle, "td_thr_tls_get_addr");
+  info->td_thr_tlsbase_p = dlsym (info->handle, "td_thr_tlsbase");
 
   if (thread_db_find_new_threads_silently (inferior_ptid) != 0)
     {
@@ -1811,21 +1815,36 @@ thread_db_get_thread_local_address (struct target_ops *ops,
 
       info = get_thread_db_info (ptid_get_pid (ptid));
 
-      /* glibc doesn't provide the needed interface.  */
-      if (!info->td_thr_tls_get_addr_p)
-	throw_error (TLS_NO_LIBRARY_SUPPORT_ERROR,
-		     _("No TLS library support"));
-
+#if 0
       /* Caller should have verified that lm != 0.  */
       gdb_assert (lm != 0);
-
+#endif
       /* Finally, get the address of the variable.  */
-      /* Note the cast through uintptr_t: this interface only works if
-	 a target address fits in a psaddr_t, which is a host pointer.
-	 So a 32-bit debugger can not access 64-bit TLS through this.  */
-      err = info->td_thr_tls_get_addr_p (&thread_info->private->th,
-					 (psaddr_t)(uintptr_t) lm,
-					 offset, &address);
+      if (lm != 0)
+	{
+	  /* glibc doesn't provide the needed interface.  */
+	  if (!info->td_thr_tls_get_addr_p)
+	    throw_error (TLS_NO_LIBRARY_SUPPORT_ERROR,
+			 _("No TLS library support"));
+
+	  /* Note the cast through uintptr_t: this interface only works if
+	     a target address fits in a psaddr_t, which is a host pointer.
+	     So a 32-bit debugger can not access 64-bit TLS through this.  */
+	  err = info->td_thr_tls_get_addr_p (&thread_info->private->th,
+					     (psaddr_t)(uintptr_t) lm,
+					     offset, &address);
+	}
+      else
+	{
+	  /* glibc doesn't provide the needed interface.  */
+	  if (!info->td_thr_tlsbase_p)
+	    throw_error (TLS_NO_LIBRARY_SUPPORT_ERROR,
+			 _("No TLS library support"));
+
+	  err = info->td_thr_tlsbase_p (&thread_info->private->th,
+					1, &address);
+	  address = (char *) address + offset;
+	}
 
 #ifdef THREAD_DB_HAS_TD_NOTALLOC
       /* The memory hasn't been allocated, yet.  */
diff --git a/gdb/target.c b/gdb/target.c
index 1b48f79..e2cc446 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -753,10 +753,12 @@ target_translate_tls_address (struct objfile *objfile, CORE_ADDR offset)
 	  /* Fetch the load module address for this objfile.  */
 	  lm_addr = gdbarch_fetch_tls_load_module_address (target_gdbarch (),
 	                                                   objfile);
+#if 0
 	  /* If it's 0, throw the appropriate exception.  */
 	  if (lm_addr == 0)
 	    throw_error (TLS_LOAD_MODULE_NOT_FOUND_ERROR,
 			 _("TLS load module not found"));
+#endif
 
 	  addr = target->to_get_thread_local_address (target, ptid,
 						      lm_addr, offset);


More information about the Libc-help mailing list