aboutsummaryrefslogtreecommitdiff
path: root/gdb
diff options
context:
space:
mode:
authorJan Kratochvil <jan.kratochvil@redhat.com>2012-07-02 20:28:38 +0000
committerJan Kratochvil <jan.kratochvil@redhat.com>2012-07-02 20:28:38 +0000
commitfcb4437118d0bbc82cf56f76d00c44c0220c0005 (patch)
tree9ee61b56376d07324026d6d4fc3400436b668758 /gdb
parent0f3c2347e62bde314690425592d9f141f929ef2e (diff)
downloadgdb-fcb4437118d0bbc82cf56f76d00c44c0220c0005.zip
gdb-fcb4437118d0bbc82cf56f76d00c44c0220c0005.tar.gz
gdb-fcb4437118d0bbc82cf56f76d00c44c0220c0005.tar.bz2
gdb/
* 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.
Diffstat (limited to 'gdb')
-rw-r--r--gdb/ChangeLog10
-rw-r--r--gdb/linux-thread-db.c111
-rw-r--r--gdb/testsuite/ChangeLog5
-rw-r--r--gdb/testsuite/gdb.threads/gcore-thread.exp50
4 files changed, 123 insertions, 53 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 49d8b30..7186f5c 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -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
diff --git a/gdb/linux-thread-db.c b/gdb/linux-thread-db.c
index bc82829..dff8fc2 100644
--- a/gdb/linux-thread-db.c
+++ b/gdb/linux-thread-db.c
@@ -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
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 246f293..34351ff 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,5 +1,10 @@
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.
Change CU pointer size to 4 bytes, adjust .8byte to .4byte. Remove
.note.GNU-stack.
diff --git a/gdb/testsuite/gdb.threads/gcore-thread.exp b/gdb/testsuite/gdb.threads/gcore-thread.exp
index a47f931..37eadd3 100644
--- a/gdb/testsuite/gdb.threads/gcore-thread.exp
+++ b/gdb/testsuite/gdb.threads/gcore-thread.exp
@@ -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"
+}}