diff options
-rw-r--r-- | gdb/ChangeLog | 28 | ||||
-rw-r--r-- | gdb/thread-db.c | 126 |
2 files changed, 108 insertions, 46 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 0576b00..160b19f 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,31 @@ +2000-12-27 Mark Kettenis <kettenis@gnu.org> + + Fix debugging programs statically linked against the thread library. + * thread-db.c: Various comment fixes and additions. + Include "bfd.h", "symfile.h" and "objfiles.h". + (keep_thread_db): New variable. + (find_new_threads_callback): Remove prototype. + (thread_db_find_new_threads): New prototype. + (thread_db_push_target, thread_db_unpush_target): Remove + functions. + (deactivate_target): New function. + (thread_db_new_objfile): If OBJFILE == NULL, force deactivation of + target vector. Activate target vector directly instead of calling + thread_db_push_target. Set keep_thread_db if thread library is + detected in the main symbol file. Only enable thread event + reporting if there actually is a child process. Likewise for + detecting new threads, done by calling thread_db_find_new_threads + instead of iterating over the threads ourselves. + (thread_db_detach): Call deactivate_target instead of + thread_db_unpush_target. + (thread_db_wait): Bail out early if we're not debugging the + multi-threaded child process yet. + (thread_db_post_startup_inferior): New function. + (thread_db_mourn_inferior): Call deactivate_target instead of + thread_db_unpush_target. + (init_thread_db_ops): Add thread_db_post_startup_inferior to + thread_db_ops. + 2000-12-22 Mark Kettenis <kettenis@gnu.org> * solib.c (solib_open): If path is relative, look for it diff --git a/gdb/thread-db.c b/gdb/thread-db.c index 0296149..ed27861 100644 --- a/gdb/thread-db.c +++ b/gdb/thread-db.c @@ -25,8 +25,11 @@ #include "gdb_proc_service.h" #include "gdb_thread_db.h" +#include "bfd.h" #include "gdbthread.h" #include "inferior.h" +#include "symfile.h" +#include "objfiles.h" #include "target.h" #ifndef LIBTHREAD_DB_SO @@ -52,6 +55,9 @@ static void (*target_new_objfile_chain) (struct objfile *objfile); /* Non-zero if we're using this module's target vector. */ static int using_thread_db; +/* Non-zero if we musn't deactivate this module's target vector. */ +static int keep_thread_db; + /* Non-zero if we have determined the signals used by the threads library. */ static int thread_signals; @@ -110,7 +116,7 @@ static CORE_ADDR td_create_bp_addr; static CORE_ADDR td_death_bp_addr; /* Prototypes for local functions. */ -static int find_new_threads_callback (const td_thrhandle_t *th_p, void *data); +static void thread_db_find_new_threads (void); /* Building process ids. */ @@ -499,23 +505,17 @@ disable_thread_signals (void) } static void -thread_db_push_target (void) -{ - using_thread_db = 1; - - /* Push this target vector. */ - push_target (&thread_db_ops); - - enable_thread_event_reporting (); -} - -static void -thread_db_unpush_target (void) +deactivate_target (void) { - /* Unpush this target vector. */ - unpush_target (&thread_db_ops); + /* Forget about the child's process ID. We shouldn't need it + anymore. */ + proc_handle.pid = 0; - using_thread_db = 0; + if (! keep_thread_db) + { + using_thread_db = 0; + unpush_target (&thread_db_ops); + } } static void @@ -523,39 +523,61 @@ thread_db_new_objfile (struct objfile *objfile) { td_err_e err; + if (objfile == NULL) + { + /* All symbols have been discarded. If the thread_db target is + active, deactivate it now, even if the application was linked + statically against the thread library. */ + keep_thread_db = 0; + if (using_thread_db) + deactivate_target (); + + goto quit; + } + if (using_thread_db) /* Nothing to do. The thread library was already detected and the target vector was already activated. */ goto quit; - if (objfile == NULL) - /* Un-interesting object file. */ - goto quit; - - /* Initialize the structure that identifies the child process. */ + /* Initialize the structure that identifies the child process. Note + that at this point there is no guarantee that we actually have a + child process. */ proc_handle.pid = GET_PID (inferior_pid); - /* Now attempt to open a connection to the thread library running in - the child process. */ + /* Now attempt to open a connection to the thread library. */ err = td_ta_new_p (&proc_handle, &thread_agent); switch (err) { case TD_NOLIBTHREAD: - /* No thread library found in the child process, probably - because the child process isn't running yet. */ + /* No thread library was detected. */ break; case TD_OK: - /* The thread library was detected in the child; we go live now! */ - thread_db_push_target (); - - /* Find all user-space threads. */ - err = td_ta_thr_iter_p (thread_agent, find_new_threads_callback, - &inferior_pid, TD_THR_ANY_STATE, - TD_THR_LOWEST_PRIORITY, TD_SIGNO_MASK, - TD_THR_ANY_USER_FLAGS); - if (err != TD_OK) - error ("Finding new threads failed: %s", thread_db_err_str (err)); + /* The thread library was detected. Activate the thread_db target. */ + push_target (&thread_db_ops); + using_thread_db = 1; + + /* If the thread library was detected in the main symbol file + itself, we assume that the program was statically linked + against the thread library and well have to keep this + module's target vector activated until forever... Well, at + least until all symbols have been discarded anyway (see + above). */ + if (objfile == symfile_objfile) + { + gdb_assert (proc_handle.pid == 0); + keep_thread_db = 1; + } + + /* We can only poke around if there actually is a child process. + If there is no child process alive, postpone the steps below + until one has been created. */ + if (proc_handle.pid != 0) + { + enable_thread_event_reporting (); + thread_db_find_new_threads (); + } break; default: @@ -610,7 +632,7 @@ static void thread_db_detach (char *args, int from_tty) { disable_thread_event_reporting (); - thread_db_unpush_target (); + deactivate_target (); target_beneath->to_detach (args, from_tty); } @@ -709,6 +731,12 @@ thread_db_wait (int pid, struct target_waitstatus *ourstatus) pid = target_beneath->to_wait (pid, ourstatus); + if (proc_handle.pid == 0) + /* The current child process isn't the actual multi-threaded + program yet, so don't try to do any special thread-specific + post-processing and bail out early. */ + return pid; + if (ourstatus->kind == TARGET_WAITKIND_EXITED) return -1; @@ -834,24 +862,29 @@ thread_db_kill (void) static void thread_db_create_inferior (char *exec_file, char *allargs, char **env) { - /* We never want to actually create the inferior! If this is ever - called, it means we were on the target stack when the user said - "run". But we don't want to be on the new inferior's target - stack until the libthread_db connection is ready to be made. So - we unpush ourselves from the stack, and then invoke - find_default_create_inferior, which will invoke the appropriate - process_stratum target to do the create. */ + target_beneath->to_create_inferior (exec_file, allargs, env); +} - thread_db_unpush_target (); +static void +thread_db_post_startup_inferior (int pid) +{ + if (proc_handle.pid == 0) + { + /* The child process is now the actual multi-threaded + program. Snatch its process ID... */ + proc_handle.pid = GET_PID (pid); - find_default_create_inferior (exec_file, allargs, env); + /* ...and perform the remaining initialization steps. */ + enable_thread_event_reporting (); + thread_db_find_new_threads(); + } } static void thread_db_mourn_inferior (void) { remove_thread_event_breakpoints (); - thread_db_unpush_target (); + deactivate_target (); target_beneath->to_mourn_inferior (); } @@ -967,6 +1000,7 @@ init_thread_db_ops (void) thread_db_ops.to_xfer_memory = thread_db_xfer_memory; thread_db_ops.to_kill = thread_db_kill; thread_db_ops.to_create_inferior = thread_db_create_inferior; + thread_db_ops.to_post_startup_inferior = thread_db_post_startup_inferior; thread_db_ops.to_mourn_inferior = thread_db_mourn_inferior; thread_db_ops.to_thread_alive = thread_db_thread_alive; thread_db_ops.to_find_new_threads = thread_db_find_new_threads; |