target_beneath = target;
}
+static void *
+verbose_dlsym (void *handle, const char *name)
+{
+ void *sym = dlsym (handle, name);
+ if (sym == NULL)
+ warning ("Symbol \"%s\" not found in libthread_db: %s", name, dlerror ());
+ return sym;
+}
+
static int
thread_db_load (void)
{
/* Initialize pointers to the dynamic library functions we will use.
Essential functions first. */
- td_init_p = dlsym (handle, "td_init");
+ td_init_p = verbose_dlsym (handle, "td_init");
if (td_init_p == NULL)
return 0;
- td_ta_new_p = dlsym (handle, "td_ta_new");
+ td_ta_new_p = verbose_dlsym (handle, "td_ta_new");
if (td_ta_new_p == NULL)
return 0;
- td_ta_map_id2thr_p = dlsym (handle, "td_ta_map_id2thr");
+ td_ta_map_id2thr_p = verbose_dlsym (handle, "td_ta_map_id2thr");
if (td_ta_map_id2thr_p == NULL)
return 0;
- td_ta_map_lwp2thr_p = dlsym (handle, "td_ta_map_lwp2thr");
+ td_ta_map_lwp2thr_p = verbose_dlsym (handle, "td_ta_map_lwp2thr");
if (td_ta_map_lwp2thr_p == NULL)
return 0;
- td_ta_thr_iter_p = dlsym (handle, "td_ta_thr_iter");
+ td_ta_thr_iter_p = verbose_dlsym (handle, "td_ta_thr_iter");
if (td_ta_thr_iter_p == NULL)
return 0;
- td_thr_validate_p = dlsym (handle, "td_thr_validate");
+ td_thr_validate_p = verbose_dlsym (handle, "td_thr_validate");
if (td_thr_validate_p == NULL)
return 0;
- td_thr_get_info_p = dlsym (handle, "td_thr_get_info");
+ td_thr_get_info_p = verbose_dlsym (handle, "td_thr_get_info");
if (td_thr_get_info_p == NULL)
return 0;
- td_thr_getfpregs_p = dlsym (handle, "td_thr_getfpregs");
+ td_thr_getfpregs_p = verbose_dlsym (handle, "td_thr_getfpregs");
if (td_thr_getfpregs_p == NULL)
return 0;
- td_thr_getgregs_p = dlsym (handle, "td_thr_getgregs");
+ td_thr_getgregs_p = verbose_dlsym (handle, "td_thr_getgregs");
if (td_thr_getgregs_p == NULL)
return 0;
- td_thr_setfpregs_p = dlsym (handle, "td_thr_setfpregs");
+ td_thr_setfpregs_p = verbose_dlsym (handle, "td_thr_setfpregs");
if (td_thr_setfpregs_p == NULL)
return 0;
- td_thr_setgregs_p = dlsym (handle, "td_thr_setgregs");
+ td_thr_setgregs_p = verbose_dlsym (handle, "td_thr_setgregs");
if (td_thr_setgregs_p == NULL)
return 0;
{
td_err_e err;
+ /* First time through, report that libthread_db was successfuly
+ loaded. Can't print this in in thread_db_load as, at that stage,
+ the interpreter and it's console haven't started. The real
+ problem here is that libthread_db is loaded too early - it should
+ only be loaded when there is a program to debug. */
+ {
+ static int dejavu;
+ if (!dejavu)
+ {
+ Dl_info info;
+ const char *library = NULL;
+ /* Try dladdr. */
+ if (dladdr ((*td_ta_new_p), &info) != 0)
+ library = info.dli_fname;
+ /* Try dlinfo? */
+ if (library == NULL)
+ /* Paranoid - don't let a NULL path slip through. */
+ library = LIBTHREAD_DB_SO;
+ printf_unfiltered ("Using host libthread_db library \"%s\".\n",
+ library);
+ dejavu = 1;
+ }
+ }
+
/* Don't attempt to use thread_db on targets which can not run
(core files). */
if (objfile == NULL || !target_has_execution)
break;
case TD_OK:
+ printf_unfiltered ("[Thread debugging using libthread_db enabled]\n");
+
/* The thread library was detected. Activate the thread_db target. */
push_target (&thread_db_ops);
using_thread_db = 1;
td_thrinfo_t ti;
td_err_e err;
CORE_ADDR stop_pc;
+ int loop = 0;
/* Bail out early if we're not at a thread event breakpoint. */
stop_pc = read_pc_pid (ptid) - DECR_PC_AFTER_BREAK;
if (stop_pc != td_create_bp_addr && stop_pc != td_death_bp_addr)
return;
- err = td_ta_event_getmsg_p (thread_agent, &msg);
- if (err != TD_OK)
+ /* If we are at a create breakpoint, we do not know what new lwp
+ was created and cannot specifically locate the event message for it.
+ We have to call td_ta_event_getmsg() to get
+ the latest message. Since we have no way of correlating whether
+ the event message we get back corresponds to our breakpoint, we must
+ loop and read all event messages, processing them appropriately.
+ This guarantees we will process the correct message before continuing
+ from the breakpoint.
+
+ Currently, death events are not enabled. If they are enabled,
+ the death event can use the td_thr_event_getmsg() interface to
+ get the message specifically for that lwp and avoid looping
+ below. */
+
+ loop = 1;
+
+ do
{
- if (err == TD_NOMSG)
- return;
+ err = td_ta_event_getmsg_p (thread_agent, &msg);
+ if (err != TD_OK)
+ {
+ if (err == TD_NOMSG)
+ return;
- error ("Cannot get thread event message: %s", thread_db_err_str (err));
- }
+ error ("Cannot get thread event message: %s",
+ thread_db_err_str (err));
+ }
- err = td_thr_get_info_p (msg.th_p, &ti);
- if (err != TD_OK)
- error ("check_event: cannot get thread info: %s",
- thread_db_err_str (err));
+ err = td_thr_get_info_p (msg.th_p, &ti);
+ if (err != TD_OK)
+ error ("Cannot get thread info: %s", thread_db_err_str (err));
- ptid = BUILD_THREAD (ti.ti_tid, GET_PID (ptid));
+ ptid = BUILD_THREAD (ti.ti_tid, GET_PID (ptid));
- switch (msg.event)
- {
- case TD_CREATE:
-#if 0
- /* FIXME: kettenis/2000-08-26: Since we use td_ta_event_getmsg,
- there is no guarantee that the breakpoint will match the
- event. Should we use td_thr_event_getmsg instead? */
+ switch (msg.event)
+ {
+ case TD_CREATE:
- if (stop_pc != td_create_bp_addr)
- error ("Thread creation event doesn't match breakpoint.");
-#endif
+ /* We may already know about this thread, for instance when the
+ user has issued the `info threads' command before the SIGTRAP
+ for hitting the thread creation breakpoint was reported. */
+ if (!in_thread_list (ptid))
+ attach_thread (ptid, msg.th_p, &ti, 1);
- /* We may already know about this thread, for instance when the
- user has issued the `info threads' command before the SIGTRAP
- for hitting the thread creation breakpoint was reported. */
- if (!in_thread_list (ptid))
- attach_thread (ptid, msg.th_p, &ti, 1);
- return;
+ break;
- case TD_DEATH:
-#if 0
- /* FIXME: See TD_CREATE. */
+ case TD_DEATH:
- if (stop_pc != td_death_bp_addr)
- error ("Thread death event doesn't match breakpoint.");
-#endif
+ if (!in_thread_list (ptid))
+ error ("Spurious thread death event.");
- if (!in_thread_list (ptid))
- error ("Spurious thread death event.");
+ detach_thread (ptid, 1);
- detach_thread (ptid, 1);
- return;
+ break;
- default:
- error ("Spurious thread event.");
+ default:
+ error ("Spurious thread event.");
+ }
}
+ while (loop);
}
static ptid_t
if (regno != -1)
{
- char *raw = alloca (max_register_size (current_gdbarch));
+ char raw[MAX_REGISTER_SIZE];
deprecated_read_register_gen (regno, raw);
thread_db_fetch_registers (-1);
proc_handle.pid = 0;
target_beneath->to_mourn_inferior ();
+
+ /* Detach thread_db target ops if not dealing with a statically
+ linked threaded program. This allows a corefile to be debugged
+ after finishing debugging of a threaded program. At present,
+ debugging a statically-linked threaded program is broken, but
+ the check is added below in the event that it is fixed in the
+ future. */
+ if (!keep_thread_db)
+ {
+ unpush_target (&thread_db_ops);
+ using_thread_db = 0;
+ }
}
static int