Jumbo update to address several issues.
Go back to activating thread debugging in new_objfile(), as well as several other places, so that thread operations such as wait() can be handled inside of the child_ops.create_inferior(). This addresses spurious SIGTRAPs at the start of debugging threaded programs. Make use of the libpthread_dbg suspend/resume interface to implement single-thread stepping. Be a little more sensible about the way IS_LWP and IS_THREAD work. Don't try to look up mutex data for a spinlock sync object (ugh, unions).
This commit is contained in:
parent
52efc390bf
commit
066d05318f
|
@ -31,6 +31,7 @@
|
||||||
#include "symtab.h"
|
#include "symtab.h"
|
||||||
#include "symfile.h"
|
#include "symfile.h"
|
||||||
#include "objfiles.h"
|
#include "objfiles.h"
|
||||||
|
#include "solib.h"
|
||||||
#include "gdbthread.h"
|
#include "gdbthread.h"
|
||||||
#include "bfd.h"
|
#include "bfd.h"
|
||||||
#include "elf-bfd.h"
|
#include "elf-bfd.h"
|
||||||
|
@ -53,13 +54,17 @@ typedef struct fpreg fpregset_t;
|
||||||
|
|
||||||
/* nbsd_thread_present indicates that new_objfile has spotted
|
/* nbsd_thread_present indicates that new_objfile has spotted
|
||||||
libpthread and that post_attach() or create_inferior() should fire
|
libpthread and that post_attach() or create_inferior() should fire
|
||||||
up thread debugging. */
|
up thread debugging if it isn't already active. */
|
||||||
static int nbsd_thread_present = 0;
|
static int nbsd_thread_present = 0;
|
||||||
|
|
||||||
/* nbsd_thread_active indicates that thread debugging is up and running, and
|
/* nbsd_thread_active indicates that thread debugging is up and running, and
|
||||||
in particular that main_ta and main_ptid are valid. */
|
in particular that main_ta and main_ptid are valid. */
|
||||||
static int nbsd_thread_active = 0;
|
static int nbsd_thread_active = 0;
|
||||||
|
|
||||||
|
/* nbsd_thread_core indicates that we're working on a corefile, not a
|
||||||
|
live process. */
|
||||||
|
static int nbsd_thread_core = 0;
|
||||||
|
|
||||||
static ptid_t main_ptid; /* Real process ID */
|
static ptid_t main_ptid; /* Real process ID */
|
||||||
|
|
||||||
static ptid_t cached_thread;
|
static ptid_t cached_thread;
|
||||||
|
@ -85,7 +90,8 @@ static void nbsd_find_new_threads PARAMS ((void));
|
||||||
#define GET_LWP(ptid) ptid_get_lwp (ptid)
|
#define GET_LWP(ptid) ptid_get_lwp (ptid)
|
||||||
#define GET_THREAD(ptid) ptid_get_tid (ptid)
|
#define GET_THREAD(ptid) ptid_get_tid (ptid)
|
||||||
|
|
||||||
#define IS_THREAD(ptid) (GET_LWP (ptid) == 0)
|
#define IS_LWP(ptid) (GET_LWP (ptid) != 0)
|
||||||
|
#define IS_THREAD(ptid) (GET_THREAD (ptid) != 0)
|
||||||
|
|
||||||
#define BUILD_LWP(lwp, ptid) ptid_build (GET_PID(ptid), lwp, 0)
|
#define BUILD_LWP(lwp, ptid) ptid_build (GET_PID(ptid), lwp, 0)
|
||||||
#define BUILD_THREAD(tid, ptid) ptid_build (GET_PID(ptid), 0, tid)
|
#define BUILD_THREAD(tid, ptid) ptid_build (GET_PID(ptid), 0, tid)
|
||||||
|
@ -96,7 +102,7 @@ static const char *syncnames[] = {"unknown",
|
||||||
"mutex",
|
"mutex",
|
||||||
"cond var",
|
"cond var",
|
||||||
"spinlock",
|
"spinlock",
|
||||||
"joining thread"};
|
"thread"};
|
||||||
|
|
||||||
struct string_map
|
struct string_map
|
||||||
{
|
{
|
||||||
|
@ -137,58 +143,46 @@ td_err_string (int errcode)
|
||||||
static void
|
static void
|
||||||
nbsd_thread_activate (void)
|
nbsd_thread_activate (void)
|
||||||
{
|
{
|
||||||
int val;
|
|
||||||
ptid_t ptid;
|
|
||||||
|
|
||||||
val = td_open (&nbsd_thread_callbacks, NULL, &main_ta);
|
|
||||||
if (val != 0)
|
|
||||||
error ("nbsd_thread_activate: td_open: %s",
|
|
||||||
td_err_string (val));
|
|
||||||
|
|
||||||
main_ptid = inferior_ptid;
|
|
||||||
nbsd_thread_active = 1;
|
nbsd_thread_active = 1;
|
||||||
|
main_ptid = inferior_ptid;
|
||||||
|
cached_thread = minus_one_ptid;
|
||||||
nbsd_find_new_threads ();
|
nbsd_find_new_threads ();
|
||||||
ptid = find_active_thread ();
|
inferior_ptid = find_active_thread ();
|
||||||
if (ptid_equal (ptid, minus_one_ptid))
|
|
||||||
error ("No active thread found\n");
|
|
||||||
inferior_ptid = ptid;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
nbsd_thread_deactivate (void)
|
nbsd_thread_deactivate (void)
|
||||||
{
|
{
|
||||||
|
td_close (main_ta);
|
||||||
|
|
||||||
inferior_ptid = main_ptid;
|
inferior_ptid = main_ptid;
|
||||||
main_ptid = minus_one_ptid;
|
main_ptid = minus_one_ptid;
|
||||||
cached_thread = main_ptid;
|
cached_thread = main_ptid;
|
||||||
nbsd_thread_active = 0;
|
nbsd_thread_active = 0;
|
||||||
|
nbsd_thread_present = 0;
|
||||||
init_thread_list ();
|
init_thread_list ();
|
||||||
|
|
||||||
td_close (main_ta);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
nbsd_thread_attach (char *args, int from_tty)
|
nbsd_thread_attach (char *args, int from_tty)
|
||||||
{
|
{
|
||||||
|
nbsd_thread_core = 0;
|
||||||
|
|
||||||
|
if (nbsd_thread_present && !nbsd_thread_active)
|
||||||
|
push_target(&nbsd_thread_ops);
|
||||||
|
|
||||||
child_ops.to_attach (args, from_tty);
|
child_ops.to_attach (args, from_tty);
|
||||||
|
|
||||||
push_target (&nbsd_thread_ops);
|
/* seems like a good place to activate, but isn't. Let it happen in
|
||||||
|
nbsd_thread_post_attach(), after a wait has occurred. */
|
||||||
/* Must get symbols from solibs before libthread_db can run! */
|
|
||||||
SOLIB_ADD ((char *) 0, from_tty, (struct target_ops *) 0, auto_solib_add);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Attach to process PID, then initialize for debugging it
|
|
||||||
and wait for the trace-trap that results from attaching. */
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
nbsd_thread_post_attach (int pid)
|
nbsd_thread_post_attach (int pid)
|
||||||
{
|
{
|
||||||
int val;
|
|
||||||
|
|
||||||
child_ops.to_post_attach (pid);
|
child_ops.to_post_attach (pid);
|
||||||
|
|
||||||
if (nbsd_thread_present)
|
if (nbsd_thread_present && !nbsd_thread_active)
|
||||||
nbsd_thread_activate ();
|
nbsd_thread_activate ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,22 +198,110 @@ nbsd_thread_post_attach (int pid)
|
||||||
static void
|
static void
|
||||||
nbsd_thread_detach (char *args, int from_tty)
|
nbsd_thread_detach (char *args, int from_tty)
|
||||||
{
|
{
|
||||||
|
nbsd_thread_deactivate ();
|
||||||
if (nbsd_thread_active)
|
|
||||||
nbsd_thread_deactivate ();
|
|
||||||
unpush_target (&nbsd_thread_ops);
|
unpush_target (&nbsd_thread_ops);
|
||||||
|
/* Ordinairly, gdb caches solib information, but this means that it
|
||||||
|
won't call the new_obfile hook on a reattach. Clear the symbol file
|
||||||
|
cache so that attach -> detach -> attach works. */
|
||||||
|
clear_solib();
|
||||||
|
symbol_file_clear(0);
|
||||||
child_ops.to_detach (args, from_tty);
|
child_ops.to_detach (args, from_tty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int nsusp;
|
||||||
|
static int nsuspalloc;
|
||||||
|
static td_thread_t **susp;
|
||||||
|
|
||||||
|
static int
|
||||||
|
thread_resume_suspend_cb (td_thread_t *th, void *arg)
|
||||||
|
{
|
||||||
|
int val;
|
||||||
|
ptid_t *pt = arg;
|
||||||
|
td_thread_info_t ti;
|
||||||
|
|
||||||
|
if (td_thr_info (th, &ti) != 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if ((ti.thread_id != GET_THREAD (*pt)) &&
|
||||||
|
(ti.thread_type == TD_TYPE_USER) &&
|
||||||
|
(ti.thread_state != TD_STATE_SUSPENDED) &&
|
||||||
|
(ti.thread_state != TD_STATE_ZOMBIE))
|
||||||
|
{
|
||||||
|
val = td_thr_suspend(th);
|
||||||
|
if (val != 0)
|
||||||
|
error ("thread_resume_suspend_cb: td_thr_suspend(%p): %s", th,
|
||||||
|
td_err_string (val));
|
||||||
|
|
||||||
|
if (nsusp == nsuspalloc)
|
||||||
|
{
|
||||||
|
if (nsuspalloc == 0)
|
||||||
|
{
|
||||||
|
nsuspalloc = 32;
|
||||||
|
susp = malloc (nsuspalloc * sizeof(td_thread_t *));
|
||||||
|
if (susp == NULL)
|
||||||
|
error ("thread_resume_suspend_cb: out of memory\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
static td_thread_t **newsusp;
|
||||||
|
nsuspalloc *= 2;
|
||||||
|
newsusp = realloc (susp, nsuspalloc * sizeof(td_thread_t *));
|
||||||
|
if (newsusp == NULL)
|
||||||
|
error ("thread_resume_suspend_cb: out of memory\n");
|
||||||
|
susp = newsusp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
susp[nsusp] = th;
|
||||||
|
nsusp++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
nbsd_thread_resume (ptid_t ptid, int step, enum target_signal signo)
|
nbsd_thread_resume (ptid_t ptid, int step, enum target_signal signo)
|
||||||
{
|
{
|
||||||
child_ops.to_resume (ptid, step, signo);
|
|
||||||
|
/* If a particular ptid is specified, then gdb wants to resume or
|
||||||
|
step just that thread. If it isn't on a processor, then it needs
|
||||||
|
to be put on one, and nothing else can be on the runnable
|
||||||
|
list. */
|
||||||
|
if (GET_PID (ptid) != -1)
|
||||||
|
{
|
||||||
|
int i, val;
|
||||||
|
|
||||||
|
val = td_thr_iter (main_ta, thread_resume_suspend_cb, &ptid);
|
||||||
|
if (val != 0)
|
||||||
|
error ("nbsd_thread_resume td_thr_iter: %s", td_err_string (val));
|
||||||
|
|
||||||
|
child_ops.to_resume (ptid, step, signo);
|
||||||
|
|
||||||
|
/* can't un-suspend just yet, child may not be stopped */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
child_ops.to_resume (ptid, step, signo);
|
||||||
|
|
||||||
cached_thread = minus_one_ptid;
|
cached_thread = minus_one_ptid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
nbsd_thread_unsuspend(void)
|
||||||
|
{
|
||||||
|
int i, val;
|
||||||
|
|
||||||
|
for (i = 0; i < nsusp; i++)
|
||||||
|
{
|
||||||
|
td_thread_info_t ti;
|
||||||
|
td_thr_info(susp[i], &ti);
|
||||||
|
val = td_thr_resume(susp[i]);
|
||||||
|
if (val != 0)
|
||||||
|
error ("nbsd_thread_resume: td_thr_suspend(%p): %s", susp[i],
|
||||||
|
td_err_string (val));
|
||||||
|
}
|
||||||
|
nsusp = 0;
|
||||||
|
}
|
||||||
|
|
||||||
static ptid_t
|
static ptid_t
|
||||||
find_active_thread (void)
|
find_active_thread (void)
|
||||||
{
|
{
|
||||||
|
@ -269,6 +351,8 @@ nbsd_thread_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
|
||||||
|
|
||||||
rtnval = child_ops.to_wait (ptid, ourstatus);
|
rtnval = child_ops.to_wait (ptid, ourstatus);
|
||||||
|
|
||||||
|
nbsd_thread_unsuspend();
|
||||||
|
|
||||||
if (nbsd_thread_active && (ourstatus->kind != TARGET_WAITKIND_EXITED))
|
if (nbsd_thread_active && (ourstatus->kind != TARGET_WAITKIND_EXITED))
|
||||||
{
|
{
|
||||||
rtnval = find_active_thread ();
|
rtnval = find_active_thread ();
|
||||||
|
@ -447,7 +531,7 @@ nbsd_thread_new_objfile (struct objfile *objfile)
|
||||||
|
|
||||||
if (!objfile)
|
if (!objfile)
|
||||||
{
|
{
|
||||||
nbsd_thread_present = 0;
|
nbsd_thread_active = 0;
|
||||||
goto quit;
|
goto quit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -456,7 +540,7 @@ nbsd_thread_new_objfile (struct objfile *objfile)
|
||||||
goto quit;
|
goto quit;
|
||||||
|
|
||||||
/* Don't do anything if we've already fired up the debugging library */
|
/* Don't do anything if we've already fired up the debugging library */
|
||||||
if (nbsd_thread_present)
|
if (nbsd_thread_active)
|
||||||
goto quit;
|
goto quit;
|
||||||
|
|
||||||
/* Now, initialize the thread debugging library. This needs to be
|
/* Now, initialize the thread debugging library. This needs to be
|
||||||
|
@ -470,16 +554,22 @@ nbsd_thread_new_objfile (struct objfile *objfile)
|
||||||
warning ("target_new_objfile: td_open: %s", td_err_string (val));
|
warning ("target_new_objfile: td_open: %s", td_err_string (val));
|
||||||
goto quit;
|
goto quit;
|
||||||
}
|
}
|
||||||
td_close (main_ta);
|
|
||||||
nbsd_thread_present = 1;
|
nbsd_thread_present = 1;
|
||||||
|
|
||||||
|
if ((nbsd_thread_core == 0) &&
|
||||||
|
!ptid_equal (inferior_ptid, null_ptid))
|
||||||
|
{
|
||||||
|
push_target (&nbsd_thread_ops);
|
||||||
|
nbsd_thread_activate();
|
||||||
|
}
|
||||||
|
|
||||||
quit:
|
quit:
|
||||||
/* Call predecessor on chain, if any. */
|
/* Call predecessor on chain, if any. */
|
||||||
if (target_new_objfile_chain)
|
if (target_new_objfile_chain)
|
||||||
target_new_objfile_chain (objfile);
|
target_new_objfile_chain (objfile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
nbsd_thread_alive (ptid_t ptid)
|
nbsd_thread_alive (ptid_t ptid)
|
||||||
{
|
{
|
||||||
|
@ -501,7 +591,7 @@ nbsd_thread_alive (ptid_t ptid)
|
||||||
val = 1;
|
val = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else if (IS_LWP (ptid))
|
||||||
{
|
{
|
||||||
struct ptrace_lwpinfo pl;
|
struct ptrace_lwpinfo pl;
|
||||||
pl.pl_lwpid = GET_LWP (ptid);
|
pl.pl_lwpid = GET_LWP (ptid);
|
||||||
|
@ -511,6 +601,8 @@ nbsd_thread_alive (ptid_t ptid)
|
||||||
else
|
else
|
||||||
val = 1;
|
val = 1;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
val = child_ops.to_thread_alive (ptid);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
val = child_ops.to_thread_alive (ptid);
|
val = child_ops.to_thread_alive (ptid);
|
||||||
|
@ -603,29 +695,15 @@ nbsd_thread_can_run (void)
|
||||||
static void
|
static void
|
||||||
nbsd_thread_create_inferior (char *exec_file, char *allargs, char **env)
|
nbsd_thread_create_inferior (char *exec_file, char *allargs, char **env)
|
||||||
{
|
{
|
||||||
int val;
|
nbsd_thread_core = 0;
|
||||||
|
|
||||||
push_target (&nbsd_thread_ops);
|
if (nbsd_thread_present && !nbsd_thread_active)
|
||||||
|
push_target(&nbsd_thread_ops);
|
||||||
|
|
||||||
child_ops.to_create_inferior (exec_file, allargs, env);
|
child_ops.to_create_inferior (exec_file, allargs, env);
|
||||||
|
|
||||||
if (!nbsd_thread_active && nbsd_thread_present && GET_PID(inferior_ptid) != 0)
|
if (nbsd_thread_present && !nbsd_thread_active)
|
||||||
{
|
nbsd_thread_activate();
|
||||||
nbsd_thread_activate ();
|
|
||||||
#if 0
|
|
||||||
/* This is gross. Due to the the differences in when the thread
|
|
||||||
library gets initialized (static vs. dynamic binaries,
|
|
||||||
mostly) and calls back to nbsd_thread_wait(), there's no
|
|
||||||
decent way for the child_ops.to_create_inferior() routine to
|
|
||||||
call back to us to start threads and find the right current
|
|
||||||
thread before it prints out a stack frame. So we print out
|
|
||||||
another stack frame here, after activating, to make sure that
|
|
||||||
the user sees what we think is interesing. */
|
|
||||||
flush_cached_frames ();
|
|
||||||
select_frame (get_current_frame ());
|
|
||||||
show_and_print_stack_frame (selected_frame, -1, 1);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -759,10 +837,12 @@ nbsd_thread_examine_cmd (char *exp, int from_tty)
|
||||||
if (from_tty)
|
if (from_tty)
|
||||||
*exp = 0;
|
*exp = 0;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
return;
|
||||||
|
|
||||||
if ((ret = td_map_pth2thr (main_ta, (pthread_t) addr, &th)) != 0)
|
if ((ret = td_map_pth2thr (main_ta, (pthread_t) addr, &th)) != 0)
|
||||||
error ("nbsd_thread_examine_command: td_map_pth2thr: %s",
|
error ("nbsd_thread_examine_command: td_map_pth2thr: %s",
|
||||||
td_err_string (ret));
|
td_err_string (ret));
|
||||||
|
|
||||||
info_cb (th, NULL);
|
info_cb (th, NULL);
|
||||||
}
|
}
|
||||||
|
@ -791,6 +871,8 @@ nbsd_thread_sync_cmd (char *exp, int from_tty)
|
||||||
if (from_tty)
|
if (from_tty)
|
||||||
*exp = 0;
|
*exp = 0;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
return;
|
||||||
|
|
||||||
if ((ret = td_map_addr2sync (main_ta, (caddr_t)addr, &ts)) != 0)
|
if ((ret = td_map_addr2sync (main_ta, (caddr_t)addr, &ts)) != 0)
|
||||||
error ("nbsd_thread_sync_cmd: td_map_addr2sync: %s", td_err_string (ret));
|
error ("nbsd_thread_sync_cmd: td_map_addr2sync: %s", td_err_string (ret));
|
||||||
|
@ -815,10 +897,7 @@ nbsd_thread_sync_cmd (char *exp, int from_tty)
|
||||||
if (!tsi.sync_data.spin.locked)
|
if (!tsi.sync_data.spin.locked)
|
||||||
printf_filtered (" unlocked ");
|
printf_filtered (" unlocked ");
|
||||||
else
|
else
|
||||||
{
|
printf_filtered (" locked (waiters not tracked)");
|
||||||
td_thr_info (tsi.sync_data.mutex.owner, &ti);
|
|
||||||
printf_filtered (" locked (waiters not tracked)");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (tsi.sync_type == TD_SYNC_JOIN)
|
else if (tsi.sync_type == TD_SYNC_JOIN)
|
||||||
{
|
{
|
||||||
|
@ -887,6 +966,8 @@ nbsd_core_open (char *filename, int from_tty)
|
||||||
td_thread_t *thread;
|
td_thread_t *thread;
|
||||||
td_thread_info_t ti;
|
td_thread_info_t ti;
|
||||||
|
|
||||||
|
nbsd_thread_core = 1;
|
||||||
|
|
||||||
orig_core_ops.to_open (filename, from_tty);
|
orig_core_ops.to_open (filename, from_tty);
|
||||||
|
|
||||||
if (nbsd_thread_present)
|
if (nbsd_thread_present)
|
||||||
|
@ -901,7 +982,7 @@ nbsd_core_open (char *filename, int from_tty)
|
||||||
nbsd_find_new_threads ();
|
nbsd_find_new_threads ();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
error ("target_new_objfile: td_open: %s", td_err_string (val));
|
error ("nbsd_core_open: td_open: %s", td_err_string (val));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1138,8 +1219,8 @@ init_nbsd_core_ops (void)
|
||||||
nbsd_core_ops.to_doc = "NetBSD pthread support for core files.";
|
nbsd_core_ops.to_doc = "NetBSD pthread support for core files.";
|
||||||
nbsd_core_ops.to_open = nbsd_core_open;
|
nbsd_core_ops.to_open = nbsd_core_open;
|
||||||
nbsd_core_ops.to_close = nbsd_core_close;
|
nbsd_core_ops.to_close = nbsd_core_close;
|
||||||
nbsd_core_ops.to_attach = nbsd_thread_attach;
|
nbsd_core_ops.to_attach = 0;
|
||||||
nbsd_core_ops.to_post_attach = nbsd_thread_post_attach;
|
nbsd_core_ops.to_post_attach = 0;
|
||||||
nbsd_core_ops.to_detach = nbsd_core_detach;
|
nbsd_core_ops.to_detach = nbsd_core_detach;
|
||||||
/* nbsd_core_ops.to_resume = 0; */
|
/* nbsd_core_ops.to_resume = 0; */
|
||||||
/* nbsd_core_ops.to_wait = 0; */
|
/* nbsd_core_ops.to_wait = 0; */
|
||||||
|
|
Loading…
Reference in New Issue