/* Thread management interface, for the remote server for GDB.
- Copyright 2002
+ Copyright (C) 2002, 2004, 2005, 2006
Free Software Foundation, Inc.
Contributed by MontaVista Software.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
#include "server.h"
#include <thread_db.h>
#endif
-/* Correct for all GNU/Linux targets (for quite some time). */
-#define GDB_GREGSET_T elf_gregset_t
-#define GDB_FPREGSET_T elf_fpregset_t
-
-#ifndef HAVE_ELF_FPREGSET_T
-/* Make sure we have said types. Not all platforms bring in <linux/elf.h>
- via <sys/procfs.h>. */
-#ifdef HAVE_LINUX_ELF_H
-#include <linux/elf.h>
-#endif
-#endif
-
-#include "../gdb_proc_service.h"
+#include "gdb_proc_service.h"
/* Structure that identifies the child process for the
<proc_service.h> interface. */
return "only part of register set was written/read";
case TD_NOXREGS:
return "X register set not available for this thread";
+#ifdef HAVE_TD_VERSION
+ case TD_VERSION:
+ return "version mismatch between libthread_db and libpthread";
+#endif
default:
snprintf (buf, sizeof (buf), "unknown thread_db error '%d'", err);
return buf;
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",
error ("Cannot find new threads: %s", thread_db_err_str (err));
}
+/* Cache all future symbols that thread_db might request. We can not
+ request symbols at arbitrary states in the remote protocol, only
+ when the client tells us that new symbols are available. So when
+ we load the thread library, make sure to check the entire list. */
+
+static void
+thread_db_look_up_symbols (void)
+{
+ const char **sym_list = td_symbol_list ();
+ CORE_ADDR unused;
+
+ for (sym_list = td_symbol_list (); *sym_list; sym_list++)
+ look_up_one_symbol (*sym_list, &unused);
+}
+
+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;
+ /* FIXME drow/2004-10-16: This is the "overall process ID", which
+ GNU/Linux calls tgid, "thread group ID". When we support
+ attaching to threads, the original thread may not be the correct
+ thread. We would have to get the process ID from /proc for NPTL.
+ For LinuxThreads we could do something similar: follow the chain
+ of parent processes until we find the highest one we're attached
+ to, and use its tgid.
+
+ This isn't the only place in gdbserver that assumes that the first
+ process in the list is the thread group leader. */
proc_handle.pid = ((struct inferior_list_entry *)current_inferior)->id;
+ /* Allow new symbol lookups. */
+ all_symbols_looked_up = 0;
+
err = td_ta_new (&proc_handle, &thread_agent);
switch (err)
{
if (thread_db_enable_reporting () == 0)
return 0;
thread_db_find_new_threads ();
+ thread_db_look_up_symbols ();
+ all_symbols_looked_up = 1;
return 1;
default:
- warning ("error initializing thread_db library.");
+ warning ("error initializing thread_db library: %s",
+ thread_db_err_str (err));
}
return 0;