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:
nathanw 2004-07-20 21:33:44 +00:00
parent 52efc390bf
commit 066d05318f
1 changed files with 147 additions and 66 deletions

View File

@ -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; */