2004-01-07 Michael Chastain <mec.gnu@mindspring.com>
[deliverable/binutils-gdb.git] / gdb / thread-db.c
index bac464151fa86126c24306e9d867c6a4856de650..b135c39f160aba5b1c79da818da57caf8dfefc24 100644 (file)
@@ -240,7 +240,7 @@ thread_db_state_str (td_thr_state_e state)
 }
 \f
 /* A callback function for td_ta_thr_iter, which we use to map all
-   threads to LWPs.  
+   threads to LWPs.
 
    THP is a handle to the current thread; if INFOP is not NULL, the
    struct thread_info associated with this thread is returned in
@@ -375,6 +375,15 @@ thread_db_init (struct target_ops *target)
   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)
 {
@@ -394,47 +403,47 @@ 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;
 
@@ -456,6 +465,26 @@ thread_db_load (void)
   return 1;
 }
 
+static td_err_e
+enable_thread_event (td_thragent_t *thread_agent, int event, CORE_ADDR *bp)
+{
+  td_notify_t notify;
+  td_err_e err;
+
+  /* Get the breakpoint address for thread EVENT.  */
+  err = td_ta_event_addr_p (thread_agent, event, &notify);
+  if (err != TD_OK)
+    return err;
+
+  /* Set up the breakpoint.  */
+  (*bp) = gdbarch_convert_from_func_ptr_addr (current_gdbarch,
+                                             (CORE_ADDR) notify.u.bptaddr,
+                                             &current_target);
+  create_thread_event_breakpoint ((*bp));
+
+  return TD_OK;
+}
+
 static void
 enable_thread_event_reporting (void)
 {
@@ -489,9 +518,11 @@ enable_thread_event_reporting (void)
 
   /* Delete previous thread event breakpoints, if any.  */
   remove_thread_event_breakpoints ();
+  td_create_bp_addr = 0;
+  td_death_bp_addr = 0;
 
-  /* Get address for thread creation breakpoint.  */
-  err = td_ta_event_addr_p (thread_agent, TD_CREATE, &notify);
+  /* Set up the thread creation event.  */
+  err = enable_thread_event (thread_agent, TD_CREATE, &td_create_bp_addr);
   if (err != TD_OK)
     {
       warning ("Unable to get location for thread creation breakpoint: %s",
@@ -499,22 +530,14 @@ enable_thread_event_reporting (void)
       return;
     }
 
-  /* Set up the breakpoint.  */
-  td_create_bp_addr = (CORE_ADDR) notify.u.bptaddr;
-  create_thread_event_breakpoint (td_create_bp_addr);
-
-  /* Get address for thread death breakpoint.  */
-  err = td_ta_event_addr_p (thread_agent, TD_DEATH, &notify);
+  /* Set up the thread death event.  */
+  err = enable_thread_event (thread_agent, TD_DEATH, &td_death_bp_addr);
   if (err != TD_OK)
     {
       warning ("Unable to get location for thread death breakpoint: %s",
               thread_db_err_str (err));
       return;
     }
-
-  /* Set up the breakpoint.  */
-  td_death_bp_addr = (CORE_ADDR) notify.u.bptaddr;
-  create_thread_event_breakpoint (td_death_bp_addr);
 }
 
 static void
@@ -587,6 +610,30 @@ thread_db_new_objfile (struct objfile *objfile)
 {
   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)
@@ -624,6 +671,8 @@ thread_db_new_objfile (struct objfile *objfile)
       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;
@@ -775,64 +824,73 @@ check_event (ptid_t ptid)
   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
@@ -945,7 +1003,7 @@ thread_db_store_registers (int regno)
 
   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);
@@ -1011,6 +1069,18 @@ thread_db_mourn_inferior (void)
   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
This page took 0.027009 seconds and 4 git commands to generate.