gdb/
authorJan Kratochvil <jan.kratochvil@redhat.com>
Mon, 2 Jul 2012 20:28:38 +0000 (20:28 +0000)
committerJan Kratochvil <jan.kratochvil@redhat.com>
Mon, 2 Jul 2012 20:28:38 +0000 (20:28 +0000)
* linux-thread-db.c (inferior_has_bug): New function.
(thread_db_find_new_threads_silently): Return boolean as checked by
inferior_has_bug, describe it in the comments.
(try_thread_db_load_1): Move call to thread_db_find_new_threads_silently
earlier.  Abort the initialization if it returned non-zero.
(thread_db_find_new_threads_2): Preinitialize ERR.  Check errors also
if UNTIL_NO_NEW,

gdb/testsuite/
* gdb.threads/gcore-thread.exp: Remove variable libthread_db_seen.
Wrap the test into loop for corefile and core0file.

gdb/ChangeLog
gdb/linux-thread-db.c
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.threads/gcore-thread.exp

index 49d8b3054ff0924870c74a14ee2a0886211cf812..7186f5cd244000bb57d072d5b17dfb3fbd11f34c 100644 (file)
@@ -1,3 +1,13 @@
+2012-07-02  Jan Kratochvil  <jan.kratochvil@redhat.com>
+
+       * linux-thread-db.c (inferior_has_bug): New function.
+       (thread_db_find_new_threads_silently): Return boolean as checked by
+       inferior_has_bug, describe it in the comments.
+       (try_thread_db_load_1): Move call to thread_db_find_new_threads_silently
+       earlier.  Abort the initialization if it returned non-zero.
+       (thread_db_find_new_threads_2): Preinitialize ERR.  Check errors also
+       if UNTIL_NO_NEW,
+
 2012-07-02  Doug Evans  <dje@google.com>
 
        * dwarf2read.c (maybe_queue_comp_unit): Move definition next to others
index bc8282955d27fd0176a311b69f82ddc4f9a2afb2..dff8fc2598ce2473ffc64d86836d18b0fde8a50c 100644 (file)
@@ -576,6 +576,37 @@ enable_thread_event (int event, CORE_ADDR *bp)
   return TD_OK;
 }
 
+/* Verify inferior's '\0'-terminated symbol VER_SYMBOL starts with "%d.%d" and
+   return 1 if this version is lower (and not equal) to
+   VER_MAJOR_MIN.VER_MINOR_MIN.  Return 0 in all other cases.  */
+
+static int
+inferior_has_bug (const char *ver_symbol, int ver_major_min, int ver_minor_min)
+{
+  struct minimal_symbol *version_msym;
+  CORE_ADDR version_addr;
+  char *version;
+  int err, got, retval = 0;
+
+  version_msym = lookup_minimal_symbol (ver_symbol, NULL, NULL);
+  if (version_msym == NULL)
+    return 0;
+
+  version_addr = SYMBOL_VALUE_ADDRESS (version_msym);
+  got = target_read_string (version_addr, &version, 32, &err);
+  if (err == 0 && memchr (version, 0, got) == &version[got -1])
+    {
+      int major, minor;
+
+      retval = (sscanf (version, "%d.%d", &major, &minor) == 2
+               && (major < ver_major_min
+                   || (major == ver_major_min && minor < ver_minor_min)));
+    }
+  xfree (version);
+
+  return retval;
+}
+
 static void
 enable_thread_event_reporting (void)
 {
@@ -643,9 +674,13 @@ enable_thread_event_reporting (void)
     }
 }
 
-/* Same as thread_db_find_new_threads_1, but silently ignore errors.  */
+/* Similar as thread_db_find_new_threads_1, but try to silently ignore errors
+   if appropriate.
 
-static void
+   Return 1 if the caller should abort libthread_db initialization.  Return 0
+   otherwise.  */
+
+static int
 thread_db_find_new_threads_silently (ptid_t ptid)
 {
   volatile struct gdb_exception except;
@@ -655,11 +690,36 @@ thread_db_find_new_threads_silently (ptid_t ptid)
       thread_db_find_new_threads_2 (ptid, 1);
     }
 
-  if (except.reason < 0 && libthread_db_debug)
+  if (except.reason < 0)
     {
-      exception_fprintf (gdb_stderr, except,
-                        "Warning: thread_db_find_new_threads_silently: ");
+      if (libthread_db_debug)
+       exception_fprintf (gdb_stderr, except,
+                          "Warning: thread_db_find_new_threads_silently: ");
+
+      /* There is a bug fixed between nptl 2.6.1 and 2.7 by
+          commit 7d9d8bd18906fdd17364f372b160d7ab896ce909
+        where calls to td_thr_get_info fail with TD_ERR for statically linked
+        executables if td_thr_get_info is called before glibc has initialized
+        itself.
+        
+        If the nptl bug is NOT present in the inferior and still thread_db
+        reports an error return 1.  It means the inferior has corrupted thread
+        list and GDB should fall back only to LWPs.
+
+        If the nptl bug is present in the inferior return 0 to silently ignore
+        such errors, and let gdb enumerate threads again later.  In such case
+        GDB cannot properly display LWPs if the inferior thread list is
+        corrupted.  */
+
+      if (!inferior_has_bug ("nptl_version", 2, 7))
+       {
+         exception_fprintf (gdb_stderr, except,
+                            _("Warning: couldn't activate thread debugging "
+                              "using libthread_db: "));
+         return 1;
+       }
     }
+  return 0;
 }
 
 /* Lookup a library in which given symbol resides.
@@ -762,6 +822,14 @@ try_thread_db_load_1 (struct thread_db_info *info)
   info->td_thr_event_enable_p = dlsym (info->handle, "td_thr_event_enable");
   info->td_thr_tls_get_addr_p = dlsym (info->handle, "td_thr_tls_get_addr");
 
+  if (thread_db_find_new_threads_silently (inferior_ptid) != 0)
+    {
+      /* Even if libthread_db initializes, if the thread list is
+         corrupted, we'd not manage to list any threads.  Better reject this
+         thread_db, and fall back to at least listing LWPs.  */
+      return 0;
+    }
+
   printf_unfiltered (_("[Thread debugging using libthread_db enabled]\n"));
 
   if (libthread_db_debug || *libthread_db_search_path)
@@ -785,12 +853,6 @@ try_thread_db_load_1 (struct thread_db_info *info)
   if (target_has_execution)
     enable_thread_event_reporting ();
 
-  /* There appears to be a bug in glibc-2.3.6: calls to td_thr_get_info fail
-     with TD_ERR for statically linked executables if td_thr_get_info is
-     called before glibc has initialized itself.  Silently ignore such
-     errors, and let gdb enumerate threads again later.  */
-  thread_db_find_new_threads_silently (inferior_ptid);
-
   return 1;
 }
 
@@ -1132,6 +1194,12 @@ thread_db_new_objfile (struct objfile *objfile)
      correctly.  */
 
   if (objfile != NULL
+      /* libpthread with separate debug info has its debug info file already
+        loaded (and notified without successfult thread_db initialization))
+        the time observer_notify_new_objfile is called for the library itself.
+        Static executables have their separate debug info loaded already
+        before the inferior has started.  */
+      && objfile->separate_debug_objfile_backlink == NULL
       /* Only check for thread_db if we loaded libpthread,
         or if this is the main symbol file.
         We need to check OBJF_MAINLINE to handle the case of debugging
@@ -1612,7 +1680,7 @@ find_new_threads_once (struct thread_db_info *info, int iteration,
 static void
 thread_db_find_new_threads_2 (ptid_t ptid, int until_no_new)
 {
-  td_err_e err;
+  td_err_e err = TD_OK;
   struct thread_db_info *info;
   int pid = ptid_get_pid (ptid);
   int i, loop;
@@ -1628,17 +1696,18 @@ thread_db_find_new_threads_2 (ptid_t ptid, int until_no_new)
         The 4 is a heuristic: there is an inherent race here, and I have
         seen that 2 iterations in a row are not always sufficient to
         "capture" all threads.  */
-      for (i = 0, loop = 0; loop < 4; ++i, ++loop)
-       if (find_new_threads_once (info, i, NULL) != 0)
-         /* Found some new threads.  Restart the loop from beginning.  */
-         loop = -1;
+      for (i = 0, loop = 0; loop < 4 && err == TD_OK; ++i, ++loop)
+       if (find_new_threads_once (info, i, &err) != 0)
+         {
+           /* Found some new threads.  Restart the loop from beginning.  */
+           loop = -1;
+         }
     }
   else
-    {
-      find_new_threads_once (info, 0, &err);
-      if (err != TD_OK)
-       error (_("Cannot find new threads: %s"), thread_db_err_str (err));
-    }
+    find_new_threads_once (info, 0, &err);
+
+  if (err != TD_OK)
+    error (_("Cannot find new threads: %s"), thread_db_err_str (err));
 }
 
 static void
index 246f293a56a002dec1b449cd329f1935eb20826d..34351ff5cd4465e5d50b00857fc1ebd3040a871f 100644 (file)
@@ -1,3 +1,8 @@
+2012-07-02  Jan Kratochvil  <jan.kratochvil@redhat.com>
+
+       * gdb.threads/gcore-thread.exp: Remove variable libthread_db_seen.
+       Wrap the test into loop for corefile and core0file.
+
 2012-07-02  Jan Kratochvil  <jan.kratochvil@redhat.com>
 
        * gdb.dwarf2/fission-reread.S: Remove .section attributes.
index a47f931dc9a1bb45d30664882aa56f7490d6f974..37eadd3864b9561f350f323eddd5242f8a8caf26 100644 (file)
@@ -141,11 +141,9 @@ proc load_core { corefile } {
     global gdb_prompt
     global libthread_db_seen
 
-    set libthread_db_seen 0
     gdb_test_multiple "core $corefile" \
        "re-load generated corefile" {
            -re "\\\[Thread debugging using \[^ \r\n\]* enabled\\\]\r\n" {
-               set libthread_db_seen 1
                exp_continue
            }
            -re " is not a core dump:.*\r\n$gdb_prompt $" {
@@ -168,39 +166,27 @@ proc load_core { corefile } {
     return 1
 }
 
-if ![load_core $corefile] {
-    return
-}
-
-# FIXME: now what can we test about the thread state?
-# We do not know for certain that there should be at least 
-# three threads, because who knows what kind of many-to-one
-# mapping various OS's may do?  Let's assume that there must
-# be at least two threads:
-
-gdb_test "info threads" ".*${nl}  2 ${horiz}${nl}\\* 1 .*" \
-       "corefile contains at least two threads"
-
-# One thread in the corefile should be in the "thread2" function.
-
-gdb_test "info threads" ".* thread2 .*" \
-       "a corefile thread is executing thread2"
+foreach name { corefile core0file } { with_test_prefix $name {
+    if ![load_core [subst $$name]] {
+       continue
+    }
 
-# The thread2 thread should be marked as the current thread.
+    # FIXME: now what can we test about the thread state?
+    # We do not know for certain that there should be at least 
+    # three threads, because who knows what kind of many-to-one
+    # mapping various OS's may do?  Let's assume that there must
+    # be at least two threads:
 
-gdb_test "info threads" ".*${nl}\\* ${horiz} thread2 .*" \
-       "thread2 is current thread in corefile"
+    gdb_test "info threads" ".*${nl}  2 ${horiz}${nl}\\* 1 .*" \
+           "corefile contains at least two threads"
 
+    # One thread in the corefile should be in the "thread2" function.
 
-# Test the uninitialized thread list.
+    gdb_test "info threads" ".* thread2 .*" \
+           "a corefile thread is executing thread2"
 
-if {"$core0file" != "" && [load_core $core0file]} {
-    set test "zeroed-threads cannot be listed"
+    # The thread2 thread should be marked as the current thread.
 
-    if {!$libthread_db_seen} {
-       verbose -log "No libthread_db loaded - -Wl,-z,relro compilation?"
-       xfail $test
-    } else {
-       gdb_test "info threads" "Cannot find new threads: .*" $test
-    }
-}
+    gdb_test "info threads" ".*${nl}\\* ${horiz} thread2 .*" \
+           "thread2 is current thread in corefile"
+}}