From 83e97ed023e828a7d924b765661374272c7f7eb4 Mon Sep 17 00:00:00 2001 From: Pedro Alves Date: Thu, 6 Aug 2015 12:33:20 +0100 Subject: [PATCH] Test for PR18749: problems if whole process dies while (ptrace-) stopped This adds a kfailed test that has the whole process exit just while several threads continuously step over a breakpoint. Usually, the process exits just while GDB or GDBserver is handling the breakpoint hit. In other words, the process disappears while the event thread is (ptrace-) stopped. This exposes several issues in GDB and GDBserver. Errors, crashes, etc. I fixed some of these issues recently, but there's a lot more to do. It's a bit like playing whack-a-mole at the moment. You fix an issue, which then exposes several others. E.g., with the native target, you get (among other errors): (...) [New Thread 0x7ffff47b9700 (LWP 18077)] [New Thread 0x7ffff3fb8700 (LWP 18078)] [New Thread 0x7ffff37b7700 (LWP 18079)] Cannot find user-level thread for LWP 18076: generic error (gdb) KFAIL: gdb.threads/process-dies-while-handling-bp.exp: non_stop=on: cond_bp_target=1: inferior 1 exited (prompt) (PRMS: gdb/18749) gdb/testsuite/ChangeLog: 2015-08-06 Pedro Alves PR gdb/18749 * gdb.threads/process-dies-while-handling-bp.c: New file. * gdb.threads/process-dies-while-handling-bp.exp: New file. --- gdb/testsuite/ChangeLog | 6 + .../gdb.threads/process-dies-while-handling-bp.c | 73 ++++++++++ .../gdb.threads/process-dies-while-handling-bp.exp | 147 +++++++++++++++++++++ 3 files changed, 226 insertions(+) create mode 100644 gdb/testsuite/gdb.threads/process-dies-while-handling-bp.c create mode 100644 gdb/testsuite/gdb.threads/process-dies-while-handling-bp.exp diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index ad63b02..eccdddb 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,5 +1,11 @@ 2015-08-06 Pedro Alves + PR gdb/18749 + * gdb.threads/process-dies-while-handling-bp.c: New file. + * gdb.threads/process-dies-while-handling-bp.exp: New file. + +2015-08-06 Pedro Alves + * gdb.threads/forking-threads-plus-breakpoint.exp: New file. * gdb.threads/forking-threads-plus-breakpoint.c: New file. diff --git a/gdb/testsuite/gdb.threads/process-dies-while-handling-bp.c b/gdb/testsuite/gdb.threads/process-dies-while-handling-bp.c new file mode 100644 index 0000000..16963fa --- /dev/null +++ b/gdb/testsuite/gdb.threads/process-dies-while-handling-bp.c @@ -0,0 +1,73 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2015 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 +#include + +/* Number of threads. Each thread continuously steps over a + breakpoint. */ +#define NTHREADS 10 + +pthread_t threads[NTHREADS]; + +pthread_barrier_t barrier; + +/* Used to create a conditional breakpoint that always fails. */ +volatile int zero; + +static void * +thread_func (void *arg) +{ + pthread_barrier_wait (&barrier); + + while (1) + { + usleep (1); /* set break here */ + } + + return NULL; +} + +int +main (void) +{ + int ret; + int i; + + /* Don't run forever. */ + alarm (180); + + pthread_barrier_init (&barrier, NULL, NTHREADS + 1); + + /* Start the threads that constantly hits a conditional breakpoint + that needs to be stepped over. */ + for (i = 0; i < NTHREADS; i++) + { + ret = pthread_create (&threads[i], NULL, thread_func, NULL); + assert (ret == 0); + } + + /* Wait until all threads are up and running. */ + pthread_barrier_wait (&barrier); + + /* Let them start hitting the breakpoint. */ + usleep (100); + + /* Exit abruptly. */ + return 0; +} diff --git a/gdb/testsuite/gdb.threads/process-dies-while-handling-bp.exp b/gdb/testsuite/gdb.threads/process-dies-while-handling-bp.exp new file mode 100644 index 0000000..84e5890 --- /dev/null +++ b/gdb/testsuite/gdb.threads/process-dies-while-handling-bp.exp @@ -0,0 +1,147 @@ +# Copyright (C) 2015 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 . + +# This test spawns a few threads that constantly trip on a breakpoint +# that does not cause a user-visible stop. While one of those +# breakpoints is being handled, the main thread exits the whole +# process. The result is that the current thread for which GDB is +# handling the event disappears too and any attempt to access +# register/memory now errors out. GDB and GDBserver should be able to +# handle this scenario gracefully. +# +# See https://sourceware.org/bugzilla/show_bug.cgi?id=18749 + +standard_testfile + +set linenum [gdb_get_line_number "set break here"] + +if {[build_executable "failed to prepare" $testfile $srcfile {debug pthreads}] == -1} { + return -1 +} + +# The test proper. If COND_BP_TARGET is true, then test with +# conditional breakpoints evaluated on the target side, if possible. + +proc do_test { non_stop cond_bp_target } { + global GDBFLAGS + global gdb_prompt + global binfile + global linenum + + set saved_gdbflags $GDBFLAGS + set GDBFLAGS [concat $GDBFLAGS " -ex \"set non-stop $non_stop\""] + clean_restart $binfile + set GDBFLAGS $saved_gdbflags + + if ![runto_main] then { + fail "Can't run to main" + return 0 + } + + # Whether it's known that the test fails. + set should_kfail 0 + + if {![gdb_is_target_remote]} { + set should_kfail 1 + } else { + if {!$cond_bp_target} { + # Leaving breakpoint evaluation to GDB exposes failures + # similar to native debugging. + gdb_test_no_output "set remote conditional-breakpoints-packet off" + set should_kfail 1 + } else { + set test "show remote conditional-breakpoints-packet" + gdb_test_multiple $test $test { + -re "currently enabled\.\r\n$gdb_prompt $" { + pass $test + } + -re "currently disabled\.\r\n$gdb_prompt $" { + unsupported "no support for target-side conditional breakpoints" + return + } + } + set should_kfail 1 + } + } + + gdb_test "break $linenum if zero == 1" \ + "Breakpoint .*" \ + "set breakpoint that evals false" + + set test "continue &" + gdb_test_multiple $test $test { + -re "$gdb_prompt " { + pass $test + } + } + + set ok 0 + + # Setup the kfail upfront in order to also catch GDB internal + # errors. + if {$should_kfail} { + setup_kfail "gdb/18749" "*-*-*" + } + + set test "inferior 1 exited" + gdb_test_multiple "" $test { + -re "Inferior 1 \(\[^\r\n\]+\) exited normally" { + set ok 1 + + # Clear the kfail to avoid a PASS -> KPASS dance across + # runs. + clear_kfail "*-*-linux*" + + pass $test + } + -re "$gdb_prompt " { + # Several errors end up at the top level, and printing the + # prompt. + fail "$test (prompt)" + } + -re "Cannot access memory" { + fail "$test (memory error)" + } + eof { + fail "$test (GDB died)" + } + } + + if {!$ok} { + # No use testing further. + return + } + + gdb_test "info threads" "No threads\." \ + "no threads left" +} + +# Wrapper for foreach that calls with_test_prefix on each iteration, +# including the iterator's current value in the prefix. + +proc foreach_with_prefix {var list body} { + upvar 1 $var myvar + foreach myvar $list { + with_test_prefix "$var=$myvar" { + uplevel 1 $body + } + } +} + +foreach_with_prefix non_stop {"on" "off"} { + foreach_with_prefix cond_bp_target {1 0} { + do_test $non_stop $cond_bp_target + } +} -- 2.7.4