This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
Implement qGetTLSAddr for gdbserver
- From: Daniel Jacobowitz <drow at false dot org>
- To: gdb-patches at sourceware dot org
- Date: Tue, 17 Oct 2006 12:03:32 -0400
- Subject: Implement qGetTLSAddr for gdbserver
Something I've been meaning to do for ages; this patch fixes the TLS
tests when using gdbserver on GNU/Linux. Tested and committed.
--
Daniel Jacobowitz
CodeSourcery
2006-10-17 Daniel Jacobowitz <dan@codesourcery.com>
* acinclude.m4 (SRV_CHECK_TLS_GET_ADDR): New.
* configure.ac: Use it. Define HAVE_TD_THR_TLS_GET_ADDR.
* config.in, configure: Regenerated.
* inferiors.c (gdb_id_to_thread): New function.
(gdb_id_to_thread_id): Use it.
* linux-low.c (linux_target_ops): Use thread_db_get_tls_address.
* linux-low.h (struct process_info): Add th member.
(thread_db_get_tls_address): New prototype.
* remote-utils.c (decode_address): Make non-static.
* server.c (handle_query): Handle qGetTLSAddr.
* server.h (gdb_id_to_thread, decode_address): New prototypes.
* target.h (struct target_ops): Add get_tls_address.
* thread-db.c (maybe_attach_thread): Save the thread handle.
(thread_db_get_tls_address): New.
Index: acinclude.m4
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/acinclude.m4,v
retrieving revision 1.4
diff -u -p -r1.4 acinclude.m4
--- acinclude.m4 17 Sep 2005 23:14:37 -0000 1.4
+++ acinclude.m4 17 Oct 2006 15:56:42 -0000
@@ -41,3 +41,23 @@ AC_DEFUN([SRV_CHECK_THREAD_DB],
])
LIBS="$old_LIBS"
])])
+
+AC_DEFUN([SRV_CHECK_TLS_GET_ADDR],
+[AC_CACHE_CHECK([for thread_db_tls_get_addr],[srv_cv_tls_get_addr],
+ [old_LIBS="$LIBS"
+ LIBS="$LIBS $srv_cv_thread_db"
+ AC_TRY_LINK(
+ [void ps_pglobal_lookup() {}
+ void ps_pdread() {}
+ void ps_pdwrite() {}
+ void ps_lgetregs() {}
+ void ps_lsetregs() {}
+ void ps_lgetfpregs() {}
+ void ps_lsetfpregs() {}
+ void ps_get_thread_area() {}
+ void ps_getpid() {}],
+ [td_thr_tls_get_addr();],
+ [srv_cv_tls_get_addr=yes],
+ [srv_cv_tls_get_addr=no])
+ LIBS="$old_LIBS"
+])])
Index: configure.ac
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/configure.ac,v
retrieving revision 1.10
diff -u -p -r1.10 configure.ac
--- configure.ac 23 Jul 2006 03:52:15 -0000 1.10
+++ configure.ac 17 Oct 2006 15:56:43 -0000
@@ -115,6 +115,7 @@ if test "$srv_linux_thread_db" = "yes";
srv_linux_thread_db=no
else
srv_libs="$srv_cv_thread_db"
+ SRV_CHECK_TLS_GET_ADDR
fi
old_LDFLAGS="$LDFLAGS"
LDFLAGS="$LDFLAGS -rdynamic"
@@ -133,6 +134,10 @@ if test "$srv_linux_thread_db" = "yes";
if test $gdbsrv_cv_have_td_version = yes; then
AC_DEFINE(HAVE_TD_VERSION, 1, [Define if TD_VERSION is available.])
fi
+
+ if test "$srv_cv_tls_get_addr"; then
+ AC_DEFINE(HAVE_TD_THR_TLS_GET_ADDR, 1, [Define if td_thr_tls_get_addr is available.])
+ fi
fi
GDBSERVER_DEPFILES="$srv_regobj $srv_tgtobj $srv_thread_depfiles"
Index: inferiors.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/inferiors.c,v
retrieving revision 1.7
diff -u -p -r1.7 inferiors.c
--- inferiors.c 23 Dec 2005 18:11:55 -0000 1.7
+++ inferiors.c 17 Oct 2006 15:56:43 -0000
@@ -144,8 +144,8 @@ thread_to_gdb_id (struct thread_info *th
return thread->gdb_id;
}
-unsigned long
-gdb_id_to_thread_id (unsigned int gdb_id)
+struct thread_info *
+gdb_id_to_thread (unsigned int gdb_id)
{
struct inferior_list_entry *inf = all_threads.head;
@@ -153,11 +153,19 @@ gdb_id_to_thread_id (unsigned int gdb_id
{
struct thread_info *thread = get_thread (inf);
if (thread->gdb_id == gdb_id)
- return inf->id;
+ return thread;
inf = inf->next;
}
- return 0;
+ return NULL;
+}
+
+unsigned long
+gdb_id_to_thread_id (unsigned int gdb_id)
+{
+ struct thread_info *thread = gdb_id_to_thread (gdb_id);
+
+ return thread ? thread->entry.id : 0;
}
static void
Index: linux-low.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/linux-low.c,v
retrieving revision 1.46
diff -u -p -r1.46 linux-low.c
--- linux-low.c 28 Sep 2006 22:46:29 -0000 1.46
+++ linux-low.c 17 Oct 2006 15:56:43 -0000
@@ -1652,6 +1652,13 @@ static struct target_ops linux_target_op
linux_stopped_data_address,
#if defined(__UCLIBC__) && !defined(__UCLIBC_HAS_MMU__)
linux_read_offsets,
+#else
+ NULL,
+#endif
+#ifdef USE_THREAD_DB
+ thread_db_get_tls_address,
+#else
+ NULL,
#endif
};
Index: linux-low.h
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/linux-low.h,v
retrieving revision 1.13
diff -u -p -r1.13 linux-low.h
--- linux-low.h 28 Sep 2006 22:46:29 -0000 1.13
+++ linux-low.h 17 Oct 2006 15:56:43 -0000
@@ -18,6 +18,10 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA. */
+#ifdef HAVE_THREAD_DB_H
+#include <thread_db.h>
+#endif
+
#ifdef HAVE_LINUX_REGSETS
typedef void (*regset_fill_func) (void *);
typedef void (*regset_store_func) (const void *);
@@ -124,6 +128,11 @@ struct process_info
and then processed and cleared in linux_resume_one_process. */
struct thread_resume *resume;
+
+#ifdef HAVE_THREAD_DB_H
+ /* The thread handle, used for e.g. TLS access. */
+ td_thrhandle_t th;
+#endif
};
extern struct inferior_list all_processes;
@@ -131,3 +140,5 @@ extern struct inferior_list all_processe
void linux_attach_lwp (unsigned long pid, unsigned long tid);
int thread_db_init (void);
+int thread_db_get_tls_address (struct thread_info *thread, CORE_ADDR offset,
+ CORE_ADDR load_module, CORE_ADDR *address);
Index: remote-utils.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/remote-utils.c,v
retrieving revision 1.32
diff -u -p -r1.32 remote-utils.c
--- remote-utils.c 21 Sep 2006 16:09:54 -0000 1.32
+++ remote-utils.c 17 Oct 2006 15:56:43 -0000
@@ -279,7 +279,7 @@ unhexify (char *bin, const char *hex, in
return i;
}
-static void
+void
decode_address (CORE_ADDR *addrp, const char *start, int len)
{
CORE_ADDR addr;
Index: server.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/server.c,v
retrieving revision 1.39
diff -u -p -r1.39 server.c
--- server.c 8 Aug 2006 16:03:29 -0000 1.39
+++ server.c 17 Oct 2006 15:56:43 -0000
@@ -254,6 +254,65 @@ handle_query (char *own_buf, int *new_pa
return;
}
+ /* Thread-local storage support. */
+ if (the_target->get_tls_address != NULL
+ && strncmp ("qGetTLSAddr:", own_buf, 12) == 0)
+ {
+ char *p = own_buf + 12;
+ CORE_ADDR parts[3], address = 0;
+ int i, err;
+
+ for (i = 0; i < 3; i++)
+ {
+ char *p2;
+ int len;
+
+ if (p == NULL)
+ break;
+
+ p2 = strchr (p, ',');
+ if (p2)
+ {
+ len = p2 - p;
+ p2++;
+ }
+ else
+ {
+ len = strlen (p);
+ p2 = NULL;
+ }
+
+ decode_address (&parts[i], p, len);
+ p = p2;
+ }
+
+ if (p != NULL || i < 3)
+ err = 1;
+ else
+ {
+ struct thread_info *thread = gdb_id_to_thread (parts[0]);
+
+ if (thread == NULL)
+ err = 2;
+ else
+ err = the_target->get_tls_address (thread, parts[1], parts[2],
+ &address);
+ }
+
+ if (err == 0)
+ {
+ sprintf (own_buf, "%llx", address);
+ return;
+ }
+ else if (err > 0)
+ {
+ write_enn (own_buf);
+ return;
+ }
+
+ /* Otherwise, pretend we do not understand this packet. */
+ }
+
/* Otherwise we didn't know what packet it was. Say we didn't
understand it. */
own_buf[0] = 0;
Index: server.h
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/server.h,v
retrieving revision 1.25
diff -u -p -r1.25 server.h
--- server.h 23 Jul 2006 03:52:15 -0000 1.25
+++ server.h 17 Oct 2006 15:56:43 -0000
@@ -105,6 +105,7 @@ void add_thread (unsigned long thread_id
unsigned int thread_id_to_gdb_id (unsigned long);
unsigned int thread_to_gdb_id (struct thread_info *);
unsigned long gdb_id_to_thread_id (unsigned int);
+struct thread_info *gdb_id_to_thread (unsigned int);
void clear_inferiors (void);
struct inferior_list_entry *find_inferior
(struct inferior_list *,
@@ -152,6 +153,7 @@ void new_thread_notify (int id);
void dead_thread_notify (int id);
void prepare_resume_reply (char *buf, char status, unsigned char sig);
+void decode_address (CORE_ADDR *addrp, const char *start, int len);
void decode_m_packet (char *from, CORE_ADDR * mem_addr_ptr,
unsigned int *len_ptr);
void decode_M_packet (char *from, CORE_ADDR * mem_addr_ptr,
Index: target.h
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/target.h,v
retrieving revision 1.17
diff -u -p -r1.17 target.h
--- target.h 23 Jul 2006 03:52:15 -0000 1.17
+++ target.h 17 Oct 2006 15:56:43 -0000
@@ -163,6 +163,15 @@ struct target_ops
time. */
int (*read_offsets) (CORE_ADDR *text, CORE_ADDR *data);
+
+ /* Fetch the address associated with a specific thread local storage
+ area, determined by the specified THREAD, OFFSET, and LOAD_MODULE.
+ Stores it in *ADDRESS and returns zero on success; otherwise returns
+ an error code. A return value of -1 means this system does not
+ support the operation. */
+
+ int (*get_tls_address) (struct thread_info *thread, CORE_ADDR offset,
+ CORE_ADDR load_module, CORE_ADDR *address);
};
extern struct target_ops *the_target;
Index: thread-db.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/thread-db.c,v
retrieving revision 1.6
diff -u -p -r1.6 thread-db.c
--- thread-db.c 30 May 2006 19:05:33 -0000 1.6
+++ thread-db.c 17 Oct 2006 15:56:43 -0000
@@ -266,6 +266,7 @@ found:
process->lwpid = ti_p->ti_lid;
process->thread_known = 1;
+ process->th = *th_p;
err = td_thr_event_enable (th_p, 1);
if (err != TD_OK)
error ("Cannot enable thread event reporting for %d: %s",
@@ -320,6 +321,33 @@ thread_db_look_up_symbols (void)
}
int
+thread_db_get_tls_address (struct thread_info *thread, CORE_ADDR offset,
+ CORE_ADDR load_module, CORE_ADDR *address)
+{
+#if HAVE_TD_THR_TLS_GET_ADDR
+ psaddr_t addr;
+ td_err_e err;
+ struct process_info *process;
+
+ process = get_thread_process (thread);
+ if (!process->thread_known)
+ return TD_NOTHR;
+
+ err = td_thr_tls_get_addr (&process->th, (psaddr_t) load_module, offset,
+ &addr);
+ if (err == TD_OK)
+ {
+ *address = (CORE_ADDR) addr;
+ return 0;
+ }
+ else
+ return err;
+#else
+ return -1;
+#endif
+}
+
+int
thread_db_init ()
{
int err;