* 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.
This commit is contained in:
Jan Kratochvil 2012-07-02 20:28:38 +00:00
parent 0f3c2347e6
commit fcb4437118
4 changed files with 128 additions and 58 deletions

View 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

View 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

View 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.

View 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"
# The thread2 thread should be marked as the current thread.
gdb_test "info threads" ".*${nl}\\* ${horiz} thread2 .*" \
"thread2 is current thread in corefile"
# Test the uninitialized thread list.
if {"$core0file" != "" && [load_core $core0file]} {
set test "zeroed-threads cannot be listed"
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
foreach name { corefile core0file } { with_test_prefix $name {
if ![load_core [subst $$name]] {
continue
}
}
# 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"
# The thread2 thread should be marked as the current thread.
gdb_test "info threads" ".*${nl}\\* ${horiz} thread2 .*" \
"thread2 is current thread in corefile"
}}