From 22fd09ae995556cc1b898afe3d5901eb161d1102 Mon Sep 17 00:00:00 2001 From: Jan Kratochvil Date: Thu, 21 Aug 2014 20:36:20 +0200 Subject: [PATCH] Fix 'gcore' with exited threads Program received signal SIGABRT, Aborted. [...] (gdb) gcore foobar Couldn't get registers: No such process. (gdb) info threads [...] (gdb) gcore foobar Saved corefile foobar (gdb) gcore tries to access the exited thread: [Thread 0x7ffff7fce700 (LWP 6895) exited] ptrace(PTRACE_GETREGS, 6895, 0, 0x7fff18167dd0) = -1 ESRCH (No such process) Without the TRY_CATCH protection testsuite FAILs for: gcore .../gdb/testsuite/gdb.threads/gcore-thread0.test Cannot find new threads: debugger service failed (gdb) FAIL: gdb.threads/gcore-thread.exp: save a zeroed-threads corefile + core .../gdb/testsuite/gdb.threads/gcore-thread0.test ".../gdb/testsuite/gdb.threads/gcore-thread0.test" is not a core dump: File format not recognized (gdb) FAIL: gdb.threads/gcore-thread.exp: core0file: re-load generated corefile (bad file format) Maybe the TRY_CATCH could be more inside update_thread_list(). Similar update_thread_list() call is IMO missing in procfs_make_note_section() but I do not have where to verify that change. gdb/ChangeLog 2014-08-21 Jan Kratochvil * linux-tdep.c (linux_corefile_thread_callback): Ignore THREAD_EXITED. (linux_make_corefile_notes): call update_thread_list, protected against exceptions. gdb/testsuite/ChangeLog 2014-08-21 Jan Kratochvil * gdb.threads/gcore-stale-thread.c: New file. * gdb.threads/gcore-stale-thread.exp: New file. --- gdb/ChangeLog | 6 +++ gdb/linux-tdep.c | 12 +++++ gdb/testsuite/ChangeLog | 5 +++ gdb/testsuite/gdb.threads/gcore-stale-thread.c | 48 ++++++++++++++++++++ gdb/testsuite/gdb.threads/gcore-stale-thread.exp | 57 ++++++++++++++++++++++++ 5 files changed, 128 insertions(+) create mode 100644 gdb/testsuite/gdb.threads/gcore-stale-thread.c create mode 100644 gdb/testsuite/gdb.threads/gcore-stale-thread.exp diff --git a/gdb/ChangeLog b/gdb/ChangeLog index bf7f618..e8f652f 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,9 @@ +2014-08-21 Jan Kratochvil + + * linux-tdep.c (linux_corefile_thread_callback): Ignore THREAD_EXITED. + (linux_make_corefile_notes): call update_thread_list, protected against + exceptions. + 2014-08-21 Pedro Alves * infcmd.c (attach_command): Remove comment. diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c index d0f1106..dae59c5 100644 --- a/gdb/linux-tdep.c +++ b/gdb/linux-tdep.c @@ -1194,6 +1194,11 @@ linux_corefile_thread_callback (struct thread_info *info, void *data) { struct linux_corefile_thread_data *args = data; + /* It can be current thread + which cannot be removed by update_thread_list. */ + if (info->state == THREAD_EXITED) + return 0; + if (ptid_get_pid (info->ptid) == args->pid) { struct cleanup *old_chain; @@ -1445,6 +1450,7 @@ linux_make_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, int *note_size, char *note_data = NULL; gdb_byte *auxv; int auxv_len; + volatile struct gdb_exception e; if (linux_fill_prpsinfo (&prpsinfo)) { @@ -1468,6 +1474,12 @@ linux_make_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, int *note_size, } /* Thread register information. */ + TRY_CATCH (e, RETURN_MASK_ERROR) + { + update_thread_list (); + } + if (e.reason < 0) + exception_print (gdb_stderr, e); thread_args.gdbarch = gdbarch; thread_args.pid = ptid_get_pid (inferior_ptid); thread_args.obfd = obfd; diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 31c64ff..8689b5e 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2014-08-21 Jan Kratochvil + + * gdb.threads/gcore-stale-thread.c: New file. + * gdb.threads/gcore-stale-thread.exp: New file. + 2014-08-21 Pedro Alves * gdb.base/gcore-buffer-overflow.exp: Remove "help gcore" test. diff --git a/gdb/testsuite/gdb.threads/gcore-stale-thread.c b/gdb/testsuite/gdb.threads/gcore-stale-thread.c new file mode 100644 index 0000000..944acba --- /dev/null +++ b/gdb/testsuite/gdb.threads/gcore-stale-thread.c @@ -0,0 +1,48 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2014 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include +#include + +static pthread_t main_thread; + +static void * +start (void *arg) +{ + int i; + + i = pthread_join (main_thread, NULL); + assert (i == 0); + + return arg; /* break-here */ +} + +int +main (void) +{ + pthread_t thread; + int i; + + main_thread = pthread_self (); + + i = pthread_create (&thread, NULL, start, NULL); + assert (i == 0); + + pthread_exit (NULL); + assert (0); + return 0; +} diff --git a/gdb/testsuite/gdb.threads/gcore-stale-thread.exp b/gdb/testsuite/gdb.threads/gcore-stale-thread.exp new file mode 100644 index 0000000..291c56f --- /dev/null +++ b/gdb/testsuite/gdb.threads/gcore-stale-thread.exp @@ -0,0 +1,57 @@ +# Copyright 2014 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +standard_testfile +set corefile [standard_output_file ${testfile}.core] + +if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable debug] != ""} { + return -1 +} + +clean_restart ${testfile} + +gdb_test_no_output "set non-stop on" + +if { ! [ runto_main ] } then { + return -1 +} + +gdb_test_multiple "info threads" "threads are supported" { + -re ".* main .*\r\n$gdb_prompt $" { + # OK, threads are supported. + } + -re "\r\n$gdb_prompt $" { + unsupported "gdb does not support threads on this target" + return -1 + } +} + +gdb_breakpoint ${srcfile}:[gdb_get_line_number "break-here"] +# gdb_continue_to_breakpoint does not work as it uses "$gdb_prompt $" regex +# which does not work due to the output: (gdb) [Thread ... exited] +set name "continue to breakpoint: break-here" +gdb_test_multiple "continue" $name { + -re "Breakpoint .* (at|in) .* break-here .*\r\n$gdb_prompt " { + pass $name + } +} + +gdb_gcore_cmd "$corefile" "save a corefile" + +# Do not run "info threads" before "gcore" as it could workaround the bug +# by discarding non-current exited threads. +gdb_test "info threads" \ + {The current thread has terminated\. See `help thread'\.} \ + "exited thread is current due to non-stop" -- 2.7.4