old-cross-binutils/gdb/testsuite/gdb.threads/multiple-step-overs.c

113 lines
2.4 KiB
C
Raw Normal View History

Handle multiple step-overs. This test fails with current mainline. If the program stopped for a breakpoint in thread 1, and then the user switches to thread 2, and resumes the program, GDB first switches back to thread 1 to step it over the breakpoint, in order to make progress. However, that logic only considers the last reported event, assuming only one thread needs that stepping over dance. That's actually not true when we play with scheduler-locking. The patch adds an example to the testsuite of multiple threads needing a step-over before the stepping thread can be resumed. With current mainline, the program re-traps the same breakpoint it had already trapped before. E.g.: Breakpoint 2, main () at ../../../src/gdb/testsuite/gdb.threads/multiple-step-overs.c:99 99 wait_threads (); /* set wait-threads breakpoint here */ (gdb) PASS: gdb.threads/multiple-step-overs.exp: step: continue to breakpoint: run to breakpoint info threads Id Target Id Frame 3 Thread 0x7ffff77c9700 (LWP 4310) "multiple-step-o" 0x00000000004007ca in child_function_3 (arg=0x1) at ../../../src/gdb/testsuite/gdb.threads/multiple-step-overs.c:43 2 Thread 0x7ffff7fca700 (LWP 4309) "multiple-step-o" 0x0000000000400827 in child_function_2 (arg=0x0) at ../../../src/gdb/testsuite/gdb.threads/multiple-step-overs.c:60 * 1 Thread 0x7ffff7fcb740 (LWP 4305) "multiple-step-o" main () at ../../../src/gdb/testsuite/gdb.threads/multiple-step-overs.c:99 (gdb) PASS: gdb.threads/multiple-step-overs.exp: step: info threads shows all threads set scheduler-locking on (gdb) PASS: gdb.threads/multiple-step-overs.exp: step: set scheduler-locking on break 44 Breakpoint 3 at 0x4007d3: file ../../../src/gdb/testsuite/gdb.threads/multiple-step-overs.c, line 44. (gdb) break 61 Breakpoint 4 at 0x40082d: file ../../../src/gdb/testsuite/gdb.threads/multiple-step-overs.c, line 61. (gdb) thread 3 [Switching to thread 3 (Thread 0x7ffff77c9700 (LWP 4310))] #0 0x00000000004007ca in child_function_3 (arg=0x1) at ../../../src/gdb/testsuite/gdb.threads/multiple-step-overs.c:43 43 (*myp) ++; (gdb) PASS: gdb.threads/multiple-step-overs.exp: step: thread 3 continue Continuing. Breakpoint 3, child_function_3 (arg=0x1) at ../../../src/gdb/testsuite/gdb.threads/multiple-step-overs.c:44 44 callme (); /* set breakpoint thread 3 here */ (gdb) PASS: gdb.threads/multiple-step-overs.exp: step: continue to breakpoint: run to breakpoint in thread 3 p *myp = 0 $1 = 0 (gdb) PASS: gdb.threads/multiple-step-overs.exp: step: unbreak loop in thread 3 thread 2 [Switching to thread 2 (Thread 0x7ffff7fca700 (LWP 4309))] #0 0x0000000000400827 in child_function_2 (arg=0x0) at ../../../src/gdb/testsuite/gdb.threads/multiple-step-overs.c:60 60 (*myp) ++; (gdb) PASS: gdb.threads/multiple-step-overs.exp: step: thread 2 continue Continuing. Breakpoint 4, child_function_2 (arg=0x0) at ../../../src/gdb/testsuite/gdb.threads/multiple-step-overs.c:61 61 callme (); /* set breakpoint thread 2 here */ (gdb) PASS: gdb.threads/multiple-step-overs.exp: step: continue to breakpoint: run to breakpoint in thread 2 p *myp = 0 $2 = 0 (gdb) PASS: gdb.threads/multiple-step-overs.exp: step: unbreak loop in thread 2 thread 1 [Switching to thread 1 (Thread 0x7ffff7fcb740 (LWP 4305))] #0 main () at ../../../src/gdb/testsuite/gdb.threads/multiple-step-overs.c:99 99 wait_threads (); /* set wait-threads breakpoint here */ (gdb) PASS: gdb.threads/multiple-step-overs.exp: step: thread 1 set scheduler-locking off (gdb) PASS: gdb.threads/multiple-step-overs.exp: step: set scheduler-locking off At this point all thread are stopped for a breakpoint that needs stepping over. (gdb) step Breakpoint 2, main () at ../../../src/gdb/testsuite/gdb.threads/multiple-step-overs.c:99 99 wait_threads (); /* set wait-threads breakpoint here */ (gdb) FAIL: gdb.threads/multiple-step-overs.exp: step But that "step" retriggers the same breakpoint instead of making progress. The patch teaches GDB to step over all breakpoints of all threads before resuming the stepping thread. Tested on x86_64 Fedora 17, against pristine mainline, and also my branch that implements software single-stepping on x86. gdb/ 2014-03-20 Pedro Alves <palves@redhat.com> * infrun.c (prepare_to_proceed): Delete. (thread_still_needs_step_over): New function. (find_thread_needs_step_over): New function. (proceed): If the current thread needs a step-over, set its steping_over_breakpoint flag. Adjust to use find_thread_needs_step_over instead of prepare_to_proceed. (process_event_stop_test): For BPSTAT_WHAT_STOP_NOISY and BPSTAT_WHAT_STOP_SILENT, assume the thread stopped for a breakpoint. (switch_back_to_stepped_thread): Step over breakpoints of all threads not the stepping thread, before switching back to the stepping thread. gdb/testsuite/ 2014-03-20 Pedro Alves <palves@redhat.com> * gdb.threads/multiple-step-overs.c: New file. * gdb.threads/multiple-step-overs.exp: New file. * gdb.threads/signal-while-stepping-over-bp-other-thread.exp: Adjust expected infrun debug output.
2014-03-20 13:26:32 +00:00
/* This testcase is part of GDB, the GNU debugger.
Copyright 2009-2015 Free Software Foundation, Inc.
Handle multiple step-overs. This test fails with current mainline. If the program stopped for a breakpoint in thread 1, and then the user switches to thread 2, and resumes the program, GDB first switches back to thread 1 to step it over the breakpoint, in order to make progress. However, that logic only considers the last reported event, assuming only one thread needs that stepping over dance. That's actually not true when we play with scheduler-locking. The patch adds an example to the testsuite of multiple threads needing a step-over before the stepping thread can be resumed. With current mainline, the program re-traps the same breakpoint it had already trapped before. E.g.: Breakpoint 2, main () at ../../../src/gdb/testsuite/gdb.threads/multiple-step-overs.c:99 99 wait_threads (); /* set wait-threads breakpoint here */ (gdb) PASS: gdb.threads/multiple-step-overs.exp: step: continue to breakpoint: run to breakpoint info threads Id Target Id Frame 3 Thread 0x7ffff77c9700 (LWP 4310) "multiple-step-o" 0x00000000004007ca in child_function_3 (arg=0x1) at ../../../src/gdb/testsuite/gdb.threads/multiple-step-overs.c:43 2 Thread 0x7ffff7fca700 (LWP 4309) "multiple-step-o" 0x0000000000400827 in child_function_2 (arg=0x0) at ../../../src/gdb/testsuite/gdb.threads/multiple-step-overs.c:60 * 1 Thread 0x7ffff7fcb740 (LWP 4305) "multiple-step-o" main () at ../../../src/gdb/testsuite/gdb.threads/multiple-step-overs.c:99 (gdb) PASS: gdb.threads/multiple-step-overs.exp: step: info threads shows all threads set scheduler-locking on (gdb) PASS: gdb.threads/multiple-step-overs.exp: step: set scheduler-locking on break 44 Breakpoint 3 at 0x4007d3: file ../../../src/gdb/testsuite/gdb.threads/multiple-step-overs.c, line 44. (gdb) break 61 Breakpoint 4 at 0x40082d: file ../../../src/gdb/testsuite/gdb.threads/multiple-step-overs.c, line 61. (gdb) thread 3 [Switching to thread 3 (Thread 0x7ffff77c9700 (LWP 4310))] #0 0x00000000004007ca in child_function_3 (arg=0x1) at ../../../src/gdb/testsuite/gdb.threads/multiple-step-overs.c:43 43 (*myp) ++; (gdb) PASS: gdb.threads/multiple-step-overs.exp: step: thread 3 continue Continuing. Breakpoint 3, child_function_3 (arg=0x1) at ../../../src/gdb/testsuite/gdb.threads/multiple-step-overs.c:44 44 callme (); /* set breakpoint thread 3 here */ (gdb) PASS: gdb.threads/multiple-step-overs.exp: step: continue to breakpoint: run to breakpoint in thread 3 p *myp = 0 $1 = 0 (gdb) PASS: gdb.threads/multiple-step-overs.exp: step: unbreak loop in thread 3 thread 2 [Switching to thread 2 (Thread 0x7ffff7fca700 (LWP 4309))] #0 0x0000000000400827 in child_function_2 (arg=0x0) at ../../../src/gdb/testsuite/gdb.threads/multiple-step-overs.c:60 60 (*myp) ++; (gdb) PASS: gdb.threads/multiple-step-overs.exp: step: thread 2 continue Continuing. Breakpoint 4, child_function_2 (arg=0x0) at ../../../src/gdb/testsuite/gdb.threads/multiple-step-overs.c:61 61 callme (); /* set breakpoint thread 2 here */ (gdb) PASS: gdb.threads/multiple-step-overs.exp: step: continue to breakpoint: run to breakpoint in thread 2 p *myp = 0 $2 = 0 (gdb) PASS: gdb.threads/multiple-step-overs.exp: step: unbreak loop in thread 2 thread 1 [Switching to thread 1 (Thread 0x7ffff7fcb740 (LWP 4305))] #0 main () at ../../../src/gdb/testsuite/gdb.threads/multiple-step-overs.c:99 99 wait_threads (); /* set wait-threads breakpoint here */ (gdb) PASS: gdb.threads/multiple-step-overs.exp: step: thread 1 set scheduler-locking off (gdb) PASS: gdb.threads/multiple-step-overs.exp: step: set scheduler-locking off At this point all thread are stopped for a breakpoint that needs stepping over. (gdb) step Breakpoint 2, main () at ../../../src/gdb/testsuite/gdb.threads/multiple-step-overs.c:99 99 wait_threads (); /* set wait-threads breakpoint here */ (gdb) FAIL: gdb.threads/multiple-step-overs.exp: step But that "step" retriggers the same breakpoint instead of making progress. The patch teaches GDB to step over all breakpoints of all threads before resuming the stepping thread. Tested on x86_64 Fedora 17, against pristine mainline, and also my branch that implements software single-stepping on x86. gdb/ 2014-03-20 Pedro Alves <palves@redhat.com> * infrun.c (prepare_to_proceed): Delete. (thread_still_needs_step_over): New function. (find_thread_needs_step_over): New function. (proceed): If the current thread needs a step-over, set its steping_over_breakpoint flag. Adjust to use find_thread_needs_step_over instead of prepare_to_proceed. (process_event_stop_test): For BPSTAT_WHAT_STOP_NOISY and BPSTAT_WHAT_STOP_SILENT, assume the thread stopped for a breakpoint. (switch_back_to_stepped_thread): Step over breakpoints of all threads not the stepping thread, before switching back to the stepping thread. gdb/testsuite/ 2014-03-20 Pedro Alves <palves@redhat.com> * gdb.threads/multiple-step-overs.c: New file. * gdb.threads/multiple-step-overs.exp: New file. * gdb.threads/signal-while-stepping-over-bp-other-thread.exp: Adjust expected infrun debug output.
2014-03-20 13:26:32 +00:00
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 <http://www.gnu.org/licenses/>. */
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
unsigned int args[2];
pthread_barrier_t barrier;
pthread_t child_thread_2, child_thread_3;
Add test for PR18214 and PR18216 - multiple step-overs with queued signals Both PRs are triggered by the same use case. PR18214 is about software single-step targets. On those, the 'resume' code that detects that we're stepping over a breakpoint and delivering a signal at the same time: /* Currently, our software single-step implementation leads to different results than hardware single-stepping in one situation: when stepping into delivering a signal which has an associated signal handler, hardware single-step will stop at the first instruction of the handler, while software single-step will simply skip execution of the handler. ... Fortunately, we can at least fix this particular issue. We detect here the case where we are about to deliver a signal while software single-stepping with breakpoints removed. In this situation, we revert the decisions to remove all breakpoints and insert single- step breakpoints, and instead we install a step-resume breakpoint at the current address, deliver the signal without stepping, and once we arrive back at the step-resume breakpoint, actually step over the breakpoint we originally wanted to step over. */ doesn't handle the case of _another_ thread also needing to step over a breakpoint. Because the other thread is just resumed at the PC where it had stopped and a breakpoint is still inserted there, the thread immediately re-traps the same breakpoint. This test exercises that. On software single-step targets, it fails like this: KFAIL: gdb.threads/multiple-step-overs.exp: displaced=off: signal thr3: continue to sigusr1_handler KFAIL: gdb.threads/multiple-step-overs.exp: displaced=off: signal thr2: continue to sigusr1_handler gdb.log (simplified): (gdb) continue Continuing. Breakpoint 4, child_function_2 (arg=0x0) at src/gdb/testsuite/gdb.threads/multiple-step-overs.c:66 66 callme (); /* set breakpoint thread 2 here */ (gdb) thread 3 (gdb) queue-signal SIGUSR1 (gdb) thread 1 [Switching to thread 1 (Thread 0x7ffff7fc1740 (LWP 24824))] #0 main () at src/gdb/testsuite/gdb.threads/multiple-step-overs.c:106 106 wait_threads (); /* set wait-threads breakpoint here */ (gdb) break sigusr1_handler Breakpoint 5 at 0x400837: file src/gdb/testsuite/gdb.threads/multiple-step-overs.c, line 31. (gdb) continue Continuing. [Switching to Thread 0x7ffff7fc0700 (LWP 24828)] Breakpoint 4, child_function_2 (arg=0x0) at src/gdb/testsuite/gdb.threads/multiple-step-overs.c:66 66 callme (); /* set breakpoint thread 2 here */ (gdb) KFAIL: gdb.threads/multiple-step-overs.exp: displaced=off: signal thr3: continue to sigusr1_handler For good measure, I made the test try displaced stepping too. And then I found it crashes GDB on x86-64 (a hardware step target), but only when displaced stepping... : KFAIL: gdb.threads/multiple-step-overs.exp: displaced=on: signal thr1: continue to sigusr1_handler (PRMS: gdb/18216) KFAIL: gdb.threads/multiple-step-overs.exp: displaced=on: signal thr2: continue to sigusr1_handler (PRMS: gdb/18216) KFAIL: gdb.threads/multiple-step-overs.exp: displaced=on: signal thr3: continue to sigusr1_handler (PRMS: gdb/18216) Program terminated with signal SIGSEGV, Segmentation fault. #0 0x000000000062a83a in process_event_stop_test (ecs=0x7fff847eeee0) at src/gdb/infrun.c:4964 4964 if (sr_bp->loc->permanent Setting up the environment for debugging gdb. Breakpoint 1 at 0x79fcfc: file src/gdb/common/errors.c, line 54. Breakpoint 2 at 0x50a26c: file src/gdb/cli/cli-cmds.c, line 217. (top-gdb) p sr_bp $1 = (struct breakpoint *) 0x0 (top-gdb) bt #0 0x000000000062a83a in process_event_stop_test (ecs=0x7fff847eeee0) at src/gdb/infrun.c:4964 #1 0x000000000062a1af in handle_signal_stop (ecs=0x7fff847eeee0) at src/gdb/infrun.c:4715 #2 0x0000000000629097 in handle_inferior_event (ecs=0x7fff847eeee0) at src/gdb/infrun.c:4165 #3 0x0000000000627482 in fetch_inferior_event (client_data=0x0) at src/gdb/infrun.c:3298 #4 0x000000000064ad7b in inferior_event_handler (event_type=INF_REG_EVENT, client_data=0x0) at src/gdb/inf-loop.c:56 #5 0x00000000004c375f in handle_target_event (error=0, client_data=0x0) at src/gdb/linux-nat.c:4658 #6 0x0000000000648c47 in handle_file_event (file_ptr=0x2e0eaa0, ready_mask=1) at src/gdb/event-loop.c:658 The all-stop-non-stop series fixes this, but meanwhile, this augments the multiple-step-overs.exp test to cover this, KFAILed. gdb/testsuite/ChangeLog: 2015-04-08 Pedro Alves <palves@redhat.com> PR gdb/18214 PR gdb/18216 * gdb.threads/multiple-step-overs.c (sigusr1_handler): New function. (main): Install it as SIGUSR1 handler. * gdb.threads/multiple-step-overs.exp (setup): Remove 'prefix' parameter. Always use "setup" as prefix. Toggle "set displaced-stepping" off/on depending on global. Don't switch to thread 1 here. (top level): Add displaced stepping "off/on" test axis. Update "setup" calls. Wrap each subtest with with_test_prefix. Test continuing with a queued signal in each thread.
2015-04-08 18:59:03 +00:00
void
sigusr1_handler (int signo)
{
}
Handle multiple step-overs. This test fails with current mainline. If the program stopped for a breakpoint in thread 1, and then the user switches to thread 2, and resumes the program, GDB first switches back to thread 1 to step it over the breakpoint, in order to make progress. However, that logic only considers the last reported event, assuming only one thread needs that stepping over dance. That's actually not true when we play with scheduler-locking. The patch adds an example to the testsuite of multiple threads needing a step-over before the stepping thread can be resumed. With current mainline, the program re-traps the same breakpoint it had already trapped before. E.g.: Breakpoint 2, main () at ../../../src/gdb/testsuite/gdb.threads/multiple-step-overs.c:99 99 wait_threads (); /* set wait-threads breakpoint here */ (gdb) PASS: gdb.threads/multiple-step-overs.exp: step: continue to breakpoint: run to breakpoint info threads Id Target Id Frame 3 Thread 0x7ffff77c9700 (LWP 4310) "multiple-step-o" 0x00000000004007ca in child_function_3 (arg=0x1) at ../../../src/gdb/testsuite/gdb.threads/multiple-step-overs.c:43 2 Thread 0x7ffff7fca700 (LWP 4309) "multiple-step-o" 0x0000000000400827 in child_function_2 (arg=0x0) at ../../../src/gdb/testsuite/gdb.threads/multiple-step-overs.c:60 * 1 Thread 0x7ffff7fcb740 (LWP 4305) "multiple-step-o" main () at ../../../src/gdb/testsuite/gdb.threads/multiple-step-overs.c:99 (gdb) PASS: gdb.threads/multiple-step-overs.exp: step: info threads shows all threads set scheduler-locking on (gdb) PASS: gdb.threads/multiple-step-overs.exp: step: set scheduler-locking on break 44 Breakpoint 3 at 0x4007d3: file ../../../src/gdb/testsuite/gdb.threads/multiple-step-overs.c, line 44. (gdb) break 61 Breakpoint 4 at 0x40082d: file ../../../src/gdb/testsuite/gdb.threads/multiple-step-overs.c, line 61. (gdb) thread 3 [Switching to thread 3 (Thread 0x7ffff77c9700 (LWP 4310))] #0 0x00000000004007ca in child_function_3 (arg=0x1) at ../../../src/gdb/testsuite/gdb.threads/multiple-step-overs.c:43 43 (*myp) ++; (gdb) PASS: gdb.threads/multiple-step-overs.exp: step: thread 3 continue Continuing. Breakpoint 3, child_function_3 (arg=0x1) at ../../../src/gdb/testsuite/gdb.threads/multiple-step-overs.c:44 44 callme (); /* set breakpoint thread 3 here */ (gdb) PASS: gdb.threads/multiple-step-overs.exp: step: continue to breakpoint: run to breakpoint in thread 3 p *myp = 0 $1 = 0 (gdb) PASS: gdb.threads/multiple-step-overs.exp: step: unbreak loop in thread 3 thread 2 [Switching to thread 2 (Thread 0x7ffff7fca700 (LWP 4309))] #0 0x0000000000400827 in child_function_2 (arg=0x0) at ../../../src/gdb/testsuite/gdb.threads/multiple-step-overs.c:60 60 (*myp) ++; (gdb) PASS: gdb.threads/multiple-step-overs.exp: step: thread 2 continue Continuing. Breakpoint 4, child_function_2 (arg=0x0) at ../../../src/gdb/testsuite/gdb.threads/multiple-step-overs.c:61 61 callme (); /* set breakpoint thread 2 here */ (gdb) PASS: gdb.threads/multiple-step-overs.exp: step: continue to breakpoint: run to breakpoint in thread 2 p *myp = 0 $2 = 0 (gdb) PASS: gdb.threads/multiple-step-overs.exp: step: unbreak loop in thread 2 thread 1 [Switching to thread 1 (Thread 0x7ffff7fcb740 (LWP 4305))] #0 main () at ../../../src/gdb/testsuite/gdb.threads/multiple-step-overs.c:99 99 wait_threads (); /* set wait-threads breakpoint here */ (gdb) PASS: gdb.threads/multiple-step-overs.exp: step: thread 1 set scheduler-locking off (gdb) PASS: gdb.threads/multiple-step-overs.exp: step: set scheduler-locking off At this point all thread are stopped for a breakpoint that needs stepping over. (gdb) step Breakpoint 2, main () at ../../../src/gdb/testsuite/gdb.threads/multiple-step-overs.c:99 99 wait_threads (); /* set wait-threads breakpoint here */ (gdb) FAIL: gdb.threads/multiple-step-overs.exp: step But that "step" retriggers the same breakpoint instead of making progress. The patch teaches GDB to step over all breakpoints of all threads before resuming the stepping thread. Tested on x86_64 Fedora 17, against pristine mainline, and also my branch that implements software single-stepping on x86. gdb/ 2014-03-20 Pedro Alves <palves@redhat.com> * infrun.c (prepare_to_proceed): Delete. (thread_still_needs_step_over): New function. (find_thread_needs_step_over): New function. (proceed): If the current thread needs a step-over, set its steping_over_breakpoint flag. Adjust to use find_thread_needs_step_over instead of prepare_to_proceed. (process_event_stop_test): For BPSTAT_WHAT_STOP_NOISY and BPSTAT_WHAT_STOP_SILENT, assume the thread stopped for a breakpoint. (switch_back_to_stepped_thread): Step over breakpoints of all threads not the stepping thread, before switching back to the stepping thread. gdb/testsuite/ 2014-03-20 Pedro Alves <palves@redhat.com> * gdb.threads/multiple-step-overs.c: New file. * gdb.threads/multiple-step-overs.exp: New file. * gdb.threads/signal-while-stepping-over-bp-other-thread.exp: Adjust expected infrun debug output.
2014-03-20 13:26:32 +00:00
void
callme (void)
{
}
void *
child_function_3 (void *arg)
{
int my_number = (long) arg;
volatile int *myp = (int *) &args[my_number];
pthread_barrier_wait (&barrier);
while (*myp > 0)
{
(*myp) ++;
callme (); /* set breakpoint thread 3 here */
}
pthread_exit (NULL);
}
void *
child_function_2 (void *arg)
{
int my_number = (long) arg;
volatile int *myp = (int *) &args[my_number];
pthread_barrier_wait (&barrier);
while (*myp > 0)
{
(*myp) ++;
callme (); /* set breakpoint thread 2 here */
}
pthread_exit (NULL);
}
static int
wait_threads (void)
{
return 1; /* in wait_threads */
}
int
main ()
{
int res;
long i;
Add test for PR18214 and PR18216 - multiple step-overs with queued signals Both PRs are triggered by the same use case. PR18214 is about software single-step targets. On those, the 'resume' code that detects that we're stepping over a breakpoint and delivering a signal at the same time: /* Currently, our software single-step implementation leads to different results than hardware single-stepping in one situation: when stepping into delivering a signal which has an associated signal handler, hardware single-step will stop at the first instruction of the handler, while software single-step will simply skip execution of the handler. ... Fortunately, we can at least fix this particular issue. We detect here the case where we are about to deliver a signal while software single-stepping with breakpoints removed. In this situation, we revert the decisions to remove all breakpoints and insert single- step breakpoints, and instead we install a step-resume breakpoint at the current address, deliver the signal without stepping, and once we arrive back at the step-resume breakpoint, actually step over the breakpoint we originally wanted to step over. */ doesn't handle the case of _another_ thread also needing to step over a breakpoint. Because the other thread is just resumed at the PC where it had stopped and a breakpoint is still inserted there, the thread immediately re-traps the same breakpoint. This test exercises that. On software single-step targets, it fails like this: KFAIL: gdb.threads/multiple-step-overs.exp: displaced=off: signal thr3: continue to sigusr1_handler KFAIL: gdb.threads/multiple-step-overs.exp: displaced=off: signal thr2: continue to sigusr1_handler gdb.log (simplified): (gdb) continue Continuing. Breakpoint 4, child_function_2 (arg=0x0) at src/gdb/testsuite/gdb.threads/multiple-step-overs.c:66 66 callme (); /* set breakpoint thread 2 here */ (gdb) thread 3 (gdb) queue-signal SIGUSR1 (gdb) thread 1 [Switching to thread 1 (Thread 0x7ffff7fc1740 (LWP 24824))] #0 main () at src/gdb/testsuite/gdb.threads/multiple-step-overs.c:106 106 wait_threads (); /* set wait-threads breakpoint here */ (gdb) break sigusr1_handler Breakpoint 5 at 0x400837: file src/gdb/testsuite/gdb.threads/multiple-step-overs.c, line 31. (gdb) continue Continuing. [Switching to Thread 0x7ffff7fc0700 (LWP 24828)] Breakpoint 4, child_function_2 (arg=0x0) at src/gdb/testsuite/gdb.threads/multiple-step-overs.c:66 66 callme (); /* set breakpoint thread 2 here */ (gdb) KFAIL: gdb.threads/multiple-step-overs.exp: displaced=off: signal thr3: continue to sigusr1_handler For good measure, I made the test try displaced stepping too. And then I found it crashes GDB on x86-64 (a hardware step target), but only when displaced stepping... : KFAIL: gdb.threads/multiple-step-overs.exp: displaced=on: signal thr1: continue to sigusr1_handler (PRMS: gdb/18216) KFAIL: gdb.threads/multiple-step-overs.exp: displaced=on: signal thr2: continue to sigusr1_handler (PRMS: gdb/18216) KFAIL: gdb.threads/multiple-step-overs.exp: displaced=on: signal thr3: continue to sigusr1_handler (PRMS: gdb/18216) Program terminated with signal SIGSEGV, Segmentation fault. #0 0x000000000062a83a in process_event_stop_test (ecs=0x7fff847eeee0) at src/gdb/infrun.c:4964 4964 if (sr_bp->loc->permanent Setting up the environment for debugging gdb. Breakpoint 1 at 0x79fcfc: file src/gdb/common/errors.c, line 54. Breakpoint 2 at 0x50a26c: file src/gdb/cli/cli-cmds.c, line 217. (top-gdb) p sr_bp $1 = (struct breakpoint *) 0x0 (top-gdb) bt #0 0x000000000062a83a in process_event_stop_test (ecs=0x7fff847eeee0) at src/gdb/infrun.c:4964 #1 0x000000000062a1af in handle_signal_stop (ecs=0x7fff847eeee0) at src/gdb/infrun.c:4715 #2 0x0000000000629097 in handle_inferior_event (ecs=0x7fff847eeee0) at src/gdb/infrun.c:4165 #3 0x0000000000627482 in fetch_inferior_event (client_data=0x0) at src/gdb/infrun.c:3298 #4 0x000000000064ad7b in inferior_event_handler (event_type=INF_REG_EVENT, client_data=0x0) at src/gdb/inf-loop.c:56 #5 0x00000000004c375f in handle_target_event (error=0, client_data=0x0) at src/gdb/linux-nat.c:4658 #6 0x0000000000648c47 in handle_file_event (file_ptr=0x2e0eaa0, ready_mask=1) at src/gdb/event-loop.c:658 The all-stop-non-stop series fixes this, but meanwhile, this augments the multiple-step-overs.exp test to cover this, KFAILed. gdb/testsuite/ChangeLog: 2015-04-08 Pedro Alves <palves@redhat.com> PR gdb/18214 PR gdb/18216 * gdb.threads/multiple-step-overs.c (sigusr1_handler): New function. (main): Install it as SIGUSR1 handler. * gdb.threads/multiple-step-overs.exp (setup): Remove 'prefix' parameter. Always use "setup" as prefix. Toggle "set displaced-stepping" off/on depending on global. Don't switch to thread 1 here. (top level): Add displaced stepping "off/on" test axis. Update "setup" calls. Wrap each subtest with with_test_prefix. Test continuing with a queued signal in each thread.
2015-04-08 18:59:03 +00:00
signal (SIGUSR1, sigusr1_handler);
Handle multiple step-overs. This test fails with current mainline. If the program stopped for a breakpoint in thread 1, and then the user switches to thread 2, and resumes the program, GDB first switches back to thread 1 to step it over the breakpoint, in order to make progress. However, that logic only considers the last reported event, assuming only one thread needs that stepping over dance. That's actually not true when we play with scheduler-locking. The patch adds an example to the testsuite of multiple threads needing a step-over before the stepping thread can be resumed. With current mainline, the program re-traps the same breakpoint it had already trapped before. E.g.: Breakpoint 2, main () at ../../../src/gdb/testsuite/gdb.threads/multiple-step-overs.c:99 99 wait_threads (); /* set wait-threads breakpoint here */ (gdb) PASS: gdb.threads/multiple-step-overs.exp: step: continue to breakpoint: run to breakpoint info threads Id Target Id Frame 3 Thread 0x7ffff77c9700 (LWP 4310) "multiple-step-o" 0x00000000004007ca in child_function_3 (arg=0x1) at ../../../src/gdb/testsuite/gdb.threads/multiple-step-overs.c:43 2 Thread 0x7ffff7fca700 (LWP 4309) "multiple-step-o" 0x0000000000400827 in child_function_2 (arg=0x0) at ../../../src/gdb/testsuite/gdb.threads/multiple-step-overs.c:60 * 1 Thread 0x7ffff7fcb740 (LWP 4305) "multiple-step-o" main () at ../../../src/gdb/testsuite/gdb.threads/multiple-step-overs.c:99 (gdb) PASS: gdb.threads/multiple-step-overs.exp: step: info threads shows all threads set scheduler-locking on (gdb) PASS: gdb.threads/multiple-step-overs.exp: step: set scheduler-locking on break 44 Breakpoint 3 at 0x4007d3: file ../../../src/gdb/testsuite/gdb.threads/multiple-step-overs.c, line 44. (gdb) break 61 Breakpoint 4 at 0x40082d: file ../../../src/gdb/testsuite/gdb.threads/multiple-step-overs.c, line 61. (gdb) thread 3 [Switching to thread 3 (Thread 0x7ffff77c9700 (LWP 4310))] #0 0x00000000004007ca in child_function_3 (arg=0x1) at ../../../src/gdb/testsuite/gdb.threads/multiple-step-overs.c:43 43 (*myp) ++; (gdb) PASS: gdb.threads/multiple-step-overs.exp: step: thread 3 continue Continuing. Breakpoint 3, child_function_3 (arg=0x1) at ../../../src/gdb/testsuite/gdb.threads/multiple-step-overs.c:44 44 callme (); /* set breakpoint thread 3 here */ (gdb) PASS: gdb.threads/multiple-step-overs.exp: step: continue to breakpoint: run to breakpoint in thread 3 p *myp = 0 $1 = 0 (gdb) PASS: gdb.threads/multiple-step-overs.exp: step: unbreak loop in thread 3 thread 2 [Switching to thread 2 (Thread 0x7ffff7fca700 (LWP 4309))] #0 0x0000000000400827 in child_function_2 (arg=0x0) at ../../../src/gdb/testsuite/gdb.threads/multiple-step-overs.c:60 60 (*myp) ++; (gdb) PASS: gdb.threads/multiple-step-overs.exp: step: thread 2 continue Continuing. Breakpoint 4, child_function_2 (arg=0x0) at ../../../src/gdb/testsuite/gdb.threads/multiple-step-overs.c:61 61 callme (); /* set breakpoint thread 2 here */ (gdb) PASS: gdb.threads/multiple-step-overs.exp: step: continue to breakpoint: run to breakpoint in thread 2 p *myp = 0 $2 = 0 (gdb) PASS: gdb.threads/multiple-step-overs.exp: step: unbreak loop in thread 2 thread 1 [Switching to thread 1 (Thread 0x7ffff7fcb740 (LWP 4305))] #0 main () at ../../../src/gdb/testsuite/gdb.threads/multiple-step-overs.c:99 99 wait_threads (); /* set wait-threads breakpoint here */ (gdb) PASS: gdb.threads/multiple-step-overs.exp: step: thread 1 set scheduler-locking off (gdb) PASS: gdb.threads/multiple-step-overs.exp: step: set scheduler-locking off At this point all thread are stopped for a breakpoint that needs stepping over. (gdb) step Breakpoint 2, main () at ../../../src/gdb/testsuite/gdb.threads/multiple-step-overs.c:99 99 wait_threads (); /* set wait-threads breakpoint here */ (gdb) FAIL: gdb.threads/multiple-step-overs.exp: step But that "step" retriggers the same breakpoint instead of making progress. The patch teaches GDB to step over all breakpoints of all threads before resuming the stepping thread. Tested on x86_64 Fedora 17, against pristine mainline, and also my branch that implements software single-stepping on x86. gdb/ 2014-03-20 Pedro Alves <palves@redhat.com> * infrun.c (prepare_to_proceed): Delete. (thread_still_needs_step_over): New function. (find_thread_needs_step_over): New function. (proceed): If the current thread needs a step-over, set its steping_over_breakpoint flag. Adjust to use find_thread_needs_step_over instead of prepare_to_proceed. (process_event_stop_test): For BPSTAT_WHAT_STOP_NOISY and BPSTAT_WHAT_STOP_SILENT, assume the thread stopped for a breakpoint. (switch_back_to_stepped_thread): Step over breakpoints of all threads not the stepping thread, before switching back to the stepping thread. gdb/testsuite/ 2014-03-20 Pedro Alves <palves@redhat.com> * gdb.threads/multiple-step-overs.c: New file. * gdb.threads/multiple-step-overs.exp: New file. * gdb.threads/signal-while-stepping-over-bp-other-thread.exp: Adjust expected infrun debug output.
2014-03-20 13:26:32 +00:00
/* Call these early so that PLTs for these are resolved soon,
instead of in the threads. RTLD_NOW should work as well. */
usleep (0);
pthread_barrier_init (&barrier, NULL, 1);
pthread_barrier_wait (&barrier);
pthread_barrier_init (&barrier, NULL, 2);
i = 0;
args[i] = 1;
res = pthread_create (&child_thread_2,
NULL, child_function_2, (void *) i);
pthread_barrier_wait (&barrier);
callme ();
i = 1;
args[i] = 1;
res = pthread_create (&child_thread_3,
NULL, child_function_3, (void *) i);
pthread_barrier_wait (&barrier);
wait_threads (); /* set wait-threads breakpoint here */
pthread_join (child_thread_2, NULL);
pthread_join (child_thread_3, NULL);
exit(EXIT_SUCCESS);
}