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.
|
|
|
|
|
2015-01-01 09:32:14 +00:00
|
|
|
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);
|
|
|
|
}
|