Index: gdb/linux-thread-db.c |
diff --git a/gdb/linux-thread-db.c b/gdb/linux-thread-db.c |
index bdf14dfeb437e37cc25cbe50e8dac74d3ec28a63..4cc3a4cb64f346341ab1865d1215046a5bf4a26c 100644 |
--- a/gdb/linux-thread-db.c |
+++ b/gdb/linux-thread-db.c |
@@ -1,6 +1,6 @@ |
/* libthread_db assisted debugging support, generic parts. |
- Copyright (C) 1999-2001, 2003-2012 Free Software Foundation, Inc. |
+ Copyright (C) 1999-2013 Free Software Foundation, Inc. |
This file is part of GDB. |
@@ -23,7 +23,7 @@ |
#include <dlfcn.h> |
#include "gdb_proc_service.h" |
#include "gdb_thread_db.h" |
- |
+#include "gdb_vecs.h" |
#include "bfd.h" |
#include "command.h" |
#include "exceptions.h" |
@@ -42,6 +42,7 @@ |
#include "linux-procfs.h" |
#include "linux-osdata.h" |
#include "auto-load.h" |
+#include "cli/cli-utils.h" |
#include <signal.h> |
#include <ctype.h> |
@@ -102,7 +103,7 @@ set_libthread_db_search_path (char *ignored, int from_tty, |
/* If non-zero, print details of libthread_db processing. */ |
-static int libthread_db_debug; |
+static unsigned int libthread_db_debug; |
static void |
show_libthread_db_debug (struct ui_file *file, int from_tty, |
@@ -422,11 +423,6 @@ thread_get_info_callback (const td_thrhandle_t *thp, void *argp) |
thread_ptid = ptid_build (info->pid, ti.ti_lid, 0); |
inout->thread_info = find_thread_ptid (thread_ptid); |
- /* In the case of a zombie thread, don't continue. We don't want to |
- attach to it thinking it is a new thread. */ |
- if (ti.ti_state == TD_THR_UNKNOWN || ti.ti_state == TD_THR_ZOMBIE) |
- return TD_THR_ZOMBIE; |
- |
if (inout->thread_info == NULL) |
{ |
/* New thread. Attach to it now (why wait?). */ |
@@ -441,9 +437,9 @@ thread_get_info_callback (const td_thrhandle_t *thp, void *argp) |
return 0; |
} |
-/* Convert between user-level thread ids and LWP ids. */ |
+/* Fetch the user-level thread id of PTID. */ |
-static ptid_t |
+static void |
thread_from_lwp (ptid_t ptid) |
{ |
td_thrhandle_t th; |
@@ -456,33 +452,22 @@ thread_from_lwp (ptid_t ptid) |
/* This ptid comes from linux-nat.c, which should always fill in the |
LWP. */ |
- gdb_assert (GET_LWP (ptid) != 0); |
+ gdb_assert (ptid_get_lwp (ptid) != 0); |
- info = get_thread_db_info (GET_PID (ptid)); |
+ info = get_thread_db_info (ptid_get_pid (ptid)); |
/* Access an lwp we know is stopped. */ |
info->proc_handle.ptid = ptid; |
- err = info->td_ta_map_lwp2thr_p (info->thread_agent, GET_LWP (ptid), &th); |
+ err = info->td_ta_map_lwp2thr_p (info->thread_agent, ptid_get_lwp (ptid), |
+ &th); |
if (err != TD_OK) |
error (_("Cannot find user-level thread for LWP %ld: %s"), |
- GET_LWP (ptid), thread_db_err_str (err)); |
- |
- /* Fetch the thread info. If we get back TD_THR_ZOMBIE, then the |
- event thread has already died. If another gdb interface has called |
- thread_alive() previously, the thread won't be found on the thread list |
- anymore. In that case, we don't want to process this ptid anymore |
- to avoid the possibility of later treating it as a newly |
- discovered thread id that we should add to the list. Thus, |
- we return a -1 ptid which is also how the thread list marks a |
- dead thread. */ |
+ ptid_get_lwp (ptid), thread_db_err_str (err)); |
+ |
+ /* Long-winded way of fetching the thread info. */ |
io.thread_db_info = info; |
io.thread_info = NULL; |
- if (thread_get_info_callback (&th, &io) == TD_THR_ZOMBIE |
- && io.thread_info == NULL) |
- return minus_one_ptid; |
- |
- gdb_assert (ptid_get_tid (ptid) == 0); |
- return ptid; |
+ thread_get_info_callback (&th, &io); |
} |
@@ -497,14 +482,14 @@ thread_db_attach_lwp (ptid_t ptid) |
td_err_e err; |
struct thread_db_info *info; |
- info = get_thread_db_info (GET_PID (ptid)); |
+ info = get_thread_db_info (ptid_get_pid (ptid)); |
if (info == NULL) |
return 0; |
/* This ptid comes from linux-nat.c, which should always fill in the |
LWP. */ |
- gdb_assert (GET_LWP (ptid) != 0); |
+ gdb_assert (ptid_get_lwp (ptid) != 0); |
/* Access an lwp we know is stopped. */ |
info->proc_handle.ptid = ptid; |
@@ -515,7 +500,8 @@ thread_db_attach_lwp (ptid_t ptid) |
if (!have_threads (ptid)) |
thread_db_find_new_threads_1 (ptid); |
- err = info->td_ta_map_lwp2thr_p (info->thread_agent, GET_LWP (ptid), &th); |
+ err = info->td_ta_map_lwp2thr_p (info->thread_agent, ptid_get_lwp (ptid), |
+ &th); |
if (err != TD_OK) |
/* Cannot find user-level thread. */ |
return 0; |
@@ -548,7 +534,7 @@ enable_thread_event (int event, CORE_ADDR *bp) |
td_err_e err; |
struct thread_db_info *info; |
- info = get_thread_db_info (GET_PID (inferior_ptid)); |
+ info = get_thread_db_info (ptid_get_pid (inferior_ptid)); |
/* Access an lwp we know is stopped. */ |
info->proc_handle.ptid = inferior_ptid; |
@@ -561,13 +547,13 @@ enable_thread_event (int event, CORE_ADDR *bp) |
/* Set up the breakpoint. */ |
gdb_assert (exec_bfd); |
(*bp) = (gdbarch_convert_from_func_ptr_addr |
- (target_gdbarch, |
+ (target_gdbarch (), |
/* Do proper sign extension for the target. */ |
(bfd_get_sign_extend_vma (exec_bfd) > 0 |
? (CORE_ADDR) (intptr_t) notify.u.bptaddr |
: (CORE_ADDR) (uintptr_t) notify.u.bptaddr), |
¤t_target)); |
- create_thread_event_breakpoint (target_gdbarch, *bp); |
+ create_thread_event_breakpoint (target_gdbarch (), *bp); |
return TD_OK; |
} |
@@ -610,7 +596,7 @@ enable_thread_event_reporting (void) |
td_err_e err; |
struct thread_db_info *info; |
- info = get_thread_db_info (GET_PID (inferior_ptid)); |
+ info = get_thread_db_info (ptid_get_pid (inferior_ptid)); |
/* We cannot use the thread event reporting facility if these |
functions aren't available. */ |
@@ -893,36 +879,45 @@ try_thread_db_load (const char *library) |
return 1; |
/* This library "refused" to work on current inferior. */ |
- delete_thread_db_info (GET_PID (inferior_ptid)); |
+ delete_thread_db_info (ptid_get_pid (inferior_ptid)); |
return 0; |
} |
/* Subroutine of try_thread_db_load_from_pdir to simplify it. |
- Try loading libthread_db from the same directory as OBJ. |
+ Try loading libthread_db in directory(OBJ)/SUBDIR. |
+ SUBDIR may be NULL. It may also be something like "../lib64". |
The result is true for success. */ |
static int |
-try_thread_db_load_from_pdir_1 (struct objfile *obj) |
+try_thread_db_load_from_pdir_1 (struct objfile *obj, const char *subdir) |
{ |
struct cleanup *cleanup; |
char *path, *cp; |
int result; |
+ const char *obj_name = objfile_name (obj); |
- if (obj->name[0] != '/') |
+ if (obj_name[0] != '/') |
{ |
warning (_("Expected absolute pathname for libpthread in the" |
- " inferior, but got %s."), obj->name); |
+ " inferior, but got %s."), obj_name); |
return 0; |
} |
- path = xmalloc (strlen (obj->name) + 1 + strlen (LIBTHREAD_DB_SO) + 1); |
+ path = xmalloc (strlen (obj_name) + (subdir ? strlen (subdir) + 1 : 0) |
+ + 1 + strlen (LIBTHREAD_DB_SO) + 1); |
cleanup = make_cleanup (xfree, path); |
- strcpy (path, obj->name); |
+ strcpy (path, obj_name); |
cp = strrchr (path, '/'); |
/* This should at minimum hit the first character. */ |
gdb_assert (cp != NULL); |
- strcpy (cp + 1, LIBTHREAD_DB_SO); |
+ cp[1] = '\0'; |
+ if (subdir != NULL) |
+ { |
+ strcat (cp, subdir); |
+ strcat (cp, "/"); |
+ } |
+ strcat (cp, LIBTHREAD_DB_SO); |
if (!file_is_auto_load_safe (path, _("auto-load: Loading libthread-db " |
"library \"%s\" from $pdir.\n"), |
@@ -936,11 +931,12 @@ try_thread_db_load_from_pdir_1 (struct objfile *obj) |
} |
/* Handle $pdir in libthread-db-search-path. |
- Look for libthread_db in the directory of libpthread. |
+ Look for libthread_db in directory(libpthread)/SUBDIR. |
+ SUBDIR may be NULL. It may also be something like "../lib64". |
The result is true for success. */ |
static int |
-try_thread_db_load_from_pdir (void) |
+try_thread_db_load_from_pdir (const char *subdir) |
{ |
struct objfile *obj; |
@@ -948,16 +944,17 @@ try_thread_db_load_from_pdir (void) |
return 0; |
ALL_OBJFILES (obj) |
- if (libpthread_name_p (obj->name)) |
+ if (libpthread_name_p (objfile_name (obj))) |
{ |
- if (try_thread_db_load_from_pdir_1 (obj)) |
+ if (try_thread_db_load_from_pdir_1 (obj, subdir)) |
return 1; |
/* We may have found the separate-debug-info version of |
libpthread, and it may live in a directory without a matching |
libthread_db. */ |
if (obj->separate_debug_objfile_backlink != NULL) |
- return try_thread_db_load_from_pdir_1 (obj->separate_debug_objfile_backlink); |
+ return try_thread_db_load_from_pdir_1 (obj->separate_debug_objfile_backlink, |
+ subdir); |
return 0; |
} |
@@ -1015,37 +1012,41 @@ try_thread_db_load_from_dir (const char *dir, size_t dir_len) |
static int |
thread_db_load_search (void) |
{ |
- const char *search_path = libthread_db_search_path; |
- int rc = 0; |
+ VEC (char_ptr) *dir_vec; |
+ struct cleanup *cleanups; |
+ char *this_dir; |
+ int i, rc = 0; |
+ |
+ dir_vec = dirnames_to_char_ptr_vec (libthread_db_search_path); |
+ cleanups = make_cleanup_free_char_ptr_vec (dir_vec); |
- while (*search_path) |
+ for (i = 0; VEC_iterate (char_ptr, dir_vec, i, this_dir); ++i) |
{ |
- const char *end = strchr (search_path, ':'); |
- const char *this_dir = search_path; |
+ const int pdir_len = sizeof ("$pdir") - 1; |
size_t this_dir_len; |
- if (end) |
- { |
- this_dir_len = end - search_path; |
- search_path += this_dir_len + 1; |
- } |
- else |
- { |
- this_dir_len = strlen (this_dir); |
- search_path += this_dir_len; |
- } |
+ this_dir_len = strlen (this_dir); |
- if (this_dir_len == sizeof ("$pdir") - 1 |
- && strncmp (this_dir, "$pdir", this_dir_len) == 0) |
+ if (strncmp (this_dir, "$pdir", pdir_len) == 0 |
+ && (this_dir[pdir_len] == '\0' |
+ || this_dir[pdir_len] == '/')) |
{ |
- if (try_thread_db_load_from_pdir ()) |
+ char *subdir = NULL; |
+ struct cleanup *free_subdir_cleanup |
+ = make_cleanup (null_cleanup, NULL); |
+ |
+ if (this_dir[pdir_len] == '/') |
{ |
- rc = 1; |
- break; |
+ subdir = xmalloc (strlen (this_dir)); |
+ make_cleanup (xfree, subdir); |
+ strcpy (subdir, this_dir + pdir_len + 1); |
} |
+ rc = try_thread_db_load_from_pdir (subdir); |
+ do_cleanups (free_subdir_cleanup); |
+ if (rc) |
+ break; |
} |
- else if (this_dir_len == sizeof ("$sdir") - 1 |
- && strncmp (this_dir, "$sdir", this_dir_len) == 0) |
+ else if (strcmp (this_dir, "$sdir") == 0) |
{ |
if (try_thread_db_load_from_sdir ()) |
{ |
@@ -1063,6 +1064,7 @@ thread_db_load_search (void) |
} |
} |
+ do_cleanups (cleanups); |
if (libthread_db_debug) |
printf_unfiltered (_("thread_db_load_search returning %d\n"), rc); |
return rc; |
@@ -1076,7 +1078,7 @@ has_libpthread (void) |
struct objfile *obj; |
ALL_OBJFILES (obj) |
- if (libpthread_name_p (obj->name)) |
+ if (libpthread_name_p (objfile_name (obj))) |
return 1; |
return 0; |
@@ -1090,7 +1092,7 @@ thread_db_load (void) |
{ |
struct thread_db_info *info; |
- info = get_thread_db_info (GET_PID (inferior_ptid)); |
+ info = get_thread_db_info (ptid_get_pid (inferior_ptid)); |
if (info != NULL) |
return 1; |
@@ -1201,7 +1203,7 @@ thread_db_new_objfile (struct objfile *objfile) |
of the list of shared libraries to load, and in an app of several |
thousand shared libraries, this can otherwise be painful. */ |
&& ((objfile->flags & OBJF_MAINLINE) != 0 |
- || libpthread_name_p (objfile->name))) |
+ || libpthread_name_p (objfile_name (objfile)))) |
check_for_thread_db (); |
} |
@@ -1260,16 +1262,14 @@ attach_thread (ptid_t ptid, const td_thrhandle_t *th_p, |
if (target_has_execution) |
check_thread_signals (); |
- if (ti_p->ti_state == TD_THR_UNKNOWN || ti_p->ti_state == TD_THR_ZOMBIE) |
- return 0; /* A zombie thread -- do not attach. */ |
- |
/* Under GNU/Linux, we have to attach to each and every thread. */ |
if (target_has_execution |
&& tp == NULL) |
{ |
int res; |
- res = lin_lwp_attach_lwp (BUILD_LWP (ti_p->ti_lid, GET_PID (ptid))); |
+ res = lin_lwp_attach_lwp (ptid_build (ptid_get_pid (ptid), |
+ ti_p->ti_lid, 0)); |
if (res < 0) |
{ |
/* Error, stop iterating. */ |
@@ -1297,6 +1297,8 @@ attach_thread (ptid_t ptid, const td_thrhandle_t *th_p, |
gdb_assert (ti_p->ti_tid != 0); |
private->th = *th_p; |
private->tid = ti_p->ti_tid; |
+ if (ti_p->ti_state == TD_THR_UNKNOWN || ti_p->ti_state == TD_THR_ZOMBIE) |
+ private->dying = 1; |
/* Add the thread to GDB's thread list. */ |
if (tp == NULL) |
@@ -1304,7 +1306,7 @@ attach_thread (ptid_t ptid, const td_thrhandle_t *th_p, |
else |
tp->private = private; |
- info = get_thread_db_info (GET_PID (ptid)); |
+ info = get_thread_db_info (ptid_get_pid (ptid)); |
/* Enable thread event reporting for this thread, except when |
debugging a core file. */ |
@@ -1338,12 +1340,12 @@ detach_thread (ptid_t ptid) |
} |
static void |
-thread_db_detach (struct target_ops *ops, char *args, int from_tty) |
+thread_db_detach (struct target_ops *ops, const char *args, int from_tty) |
{ |
struct target_ops *target_beneath = find_target_beneath (ops); |
struct thread_db_info *info; |
- info = get_thread_db_info (GET_PID (inferior_ptid)); |
+ info = get_thread_db_info (ptid_get_pid (inferior_ptid)); |
if (info) |
{ |
@@ -1359,7 +1361,7 @@ thread_db_detach (struct target_ops *ops, char *args, int from_tty) |
remove_thread_event_breakpoints (); |
} |
- delete_thread_db_info (GET_PID (inferior_ptid)); |
+ delete_thread_db_info (ptid_get_pid (inferior_ptid)); |
} |
target_beneath->to_detach (target_beneath, args, from_tty); |
@@ -1388,7 +1390,7 @@ check_event (ptid_t ptid) |
int loop = 0; |
struct thread_db_info *info; |
- info = get_thread_db_info (GET_PID (ptid)); |
+ info = get_thread_db_info (ptid_get_pid (ptid)); |
/* Bail out early if we're not at a thread event breakpoint. */ |
stop_pc = regcache_read_pc (regcache) |
@@ -1438,7 +1440,7 @@ check_event (ptid_t ptid) |
if (err != TD_OK) |
error (_("Cannot get thread info: %s"), thread_db_err_str (err)); |
- ptid = ptid_build (GET_PID (ptid), ti.ti_lid, 0); |
+ ptid = ptid_build (ptid_get_pid (ptid), ti.ti_lid, 0); |
switch (msg.event) |
{ |
@@ -1482,7 +1484,7 @@ thread_db_wait (struct target_ops *ops, |
|| ourstatus->kind == TARGET_WAITKIND_SIGNALLED) |
return ptid; |
- info = get_thread_db_info (GET_PID (ptid)); |
+ info = get_thread_db_info (ptid_get_pid (ptid)); |
/* If this process isn't using thread_db, we're done. */ |
if (info == NULL) |
@@ -1492,7 +1494,7 @@ thread_db_wait (struct target_ops *ops, |
{ |
/* New image, it may or may not end up using thread_db. Assume |
not unless we find otherwise. */ |
- delete_thread_db_info (GET_PID (ptid)); |
+ delete_thread_db_info (ptid_get_pid (ptid)); |
if (!thread_db_list) |
unpush_target (&thread_db_ops); |
@@ -1514,15 +1516,8 @@ thread_db_wait (struct target_ops *ops, |
if (have_threads (ptid)) |
{ |
- /* Change ptids back into the higher level PID + TID format. If |
- the thread is dead and no longer on the thread list, we will |
- get back a dead ptid. This can occur if the thread death |
- event gets postponed by other simultaneous events. In such a |
- case, we want to just ignore the event and continue on. */ |
- |
- ptid = thread_from_lwp (ptid); |
- if (GET_PID (ptid) == -1) |
- ourstatus->kind = TARGET_WAITKIND_SPURIOUS; |
+ /* Fill in the thread's user-level thread id. */ |
+ thread_from_lwp (ptid); |
} |
return ptid; |
@@ -1533,7 +1528,7 @@ thread_db_mourn_inferior (struct target_ops *ops) |
{ |
struct target_ops *target_beneath = find_target_beneath (ops); |
- delete_thread_db_info (GET_PID (inferior_ptid)); |
+ delete_thread_db_info (ptid_get_pid (inferior_ptid)); |
target_beneath->to_mourn_inferior (target_beneath); |
@@ -1567,9 +1562,6 @@ find_new_threads_callback (const td_thrhandle_t *th_p, void *data) |
error (_("find_new_threads_callback: cannot get thread info: %s"), |
thread_db_err_str (err)); |
- if (ti.ti_state == TD_THR_UNKNOWN || ti.ti_state == TD_THR_ZOMBIE) |
- return 0; /* A zombie -- ignore. */ |
- |
if (ti.ti_tid == 0) |
{ |
/* A thread ID of zero means that this is the main thread, but |
@@ -1674,10 +1666,9 @@ thread_db_find_new_threads_2 (ptid_t ptid, int until_no_new) |
{ |
td_err_e err = TD_OK; |
struct thread_db_info *info; |
- int pid = ptid_get_pid (ptid); |
int i, loop; |
- info = get_thread_db_info (GET_PID (ptid)); |
+ info = get_thread_db_info (ptid_get_pid (ptid)); |
/* Access an lwp we know is stopped. */ |
info->proc_handle.ptid = ptid; |
@@ -1757,7 +1748,7 @@ thread_db_pid_to_str (struct target_ops *ops, ptid_t ptid) |
tid = thread_info->private->tid; |
snprintf (buf, sizeof (buf), "Thread 0x%lx (LWP %ld)", |
- tid, GET_LWP (ptid)); |
+ tid, ptid_get_lwp (ptid)); |
return buf; |
} |
@@ -1809,7 +1800,7 @@ thread_db_get_thread_local_address (struct target_ops *ops, |
psaddr_t address; |
struct thread_db_info *info; |
- info = get_thread_db_info (GET_PID (ptid)); |
+ info = get_thread_db_info (ptid_get_pid (ptid)); |
/* glibc doesn't provide the needed interface. */ |
if (!info->td_thr_tls_get_addr_p) |
@@ -1895,9 +1886,9 @@ thread_db_resume (struct target_ops *ops, |
struct thread_db_info *info; |
if (ptid_equal (ptid, minus_one_ptid)) |
- info = get_thread_db_info (GET_PID (inferior_ptid)); |
+ info = get_thread_db_info (ptid_get_pid (inferior_ptid)); |
else |
- info = get_thread_db_info (GET_PID (ptid)); |
+ info = get_thread_db_info (ptid_get_pid (ptid)); |
/* This workaround is only needed for child fork lwps stopped in a |
PTRACE_O_TRACEFORK event. When the inferior is resumed, the |
@@ -1940,8 +1931,7 @@ info_auto_load_libthread_db (char *args, int from_tty) |
char *pids; |
int i; |
- while (isspace (*cs)) |
- cs++; |
+ cs = skip_spaces_const (cs); |
if (*cs) |
error (_("'info auto-load libthread-db' does not accept any parameters")); |
@@ -2071,6 +2061,8 @@ init_thread_db_ops (void) |
thread_db_ops.to_extra_thread_info = thread_db_extra_thread_info; |
thread_db_ops.to_get_ada_task_ptid = thread_db_get_ada_task_ptid; |
thread_db_ops.to_magic = OPS_MAGIC; |
+ |
+ complete_target_initialization (&thread_db_ops); |
} |
/* Provide a prototype to silence -Wmissing-prototypes. */ |
@@ -2080,7 +2072,6 @@ void |
_initialize_thread_db (void) |
{ |
init_thread_db_ops (); |
- add_target (&thread_db_ops); |
/* Defer loading of libthread_db.so until inferior is running. |
This allows gdb to load correct libthread_db for a given |
@@ -2104,14 +2095,14 @@ Setting the search path to an empty list resets it to its default value."), |
NULL, |
&setlist, &showlist); |
- add_setshow_zinteger_cmd ("libthread-db", class_maintenance, |
- &libthread_db_debug, _("\ |
+ add_setshow_zuinteger_cmd ("libthread-db", class_maintenance, |
+ &libthread_db_debug, _("\ |
Set libthread-db debugging."), _("\ |
Show libthread-db debugging."), _("\ |
When non-zero, libthread-db debugging is enabled."), |
- NULL, |
- show_libthread_db_debug, |
- &setdebuglist, &showdebuglist); |
+ NULL, |
+ show_libthread_db_debug, |
+ &setdebuglist, &showdebuglist); |
add_setshow_boolean_cmd ("libthread-db", class_support, |
&auto_load_thread_db, _("\ |