aboutsummaryrefslogtreecommitdiff
path: root/gdb/testsuite/gdb.arch
diff options
context:
space:
mode:
authorPedro Alves <palves@redhat.com>2014-11-12 10:10:49 +0000
committerPedro Alves <palves@redhat.com>2014-11-12 10:39:00 +0000
commitaf48d08f97fa678571a42be35a8a77b61e36d7d7 (patch)
tree37b1528627c562f4e573a258021fc3de92c7476e /gdb/testsuite/gdb.arch
parent1a853c5224e2b8fedfac6d029365522b83080b40 (diff)
downloadgdb-af48d08f97fa678571a42be35a8a77b61e36d7d7.zip
gdb-af48d08f97fa678571a42be35a8a77b61e36d7d7.tar.gz
gdb-af48d08f97fa678571a42be35a8a77b61e36d7d7.tar.bz2
fix skipping permanent breakpoints
The gdb.arch/i386-bp_permanent.exp test is currently failing an assertion recently added: (gdb) stepi ../../src/gdb/infrun.c:2237: internal-error: resume: Assertion `sig != GDB_SIGNAL_0' failed. A problem internal to GDB has been detected, further debugging may prove unreliable. Quit this debugging session? (y or n) FAIL: gdb.arch/i386-bp_permanent.exp: Single stepping past permanent breakpoint. (GDB internal error) The assertion expects that the only reason we currently need to step a breakpoint instruction is when we have a signal to deliver. But when stepping a permanent breakpoint (with or without a signal) we also reach this code. The assertion is correct and the permanent breakpoints skipping code is wrong. Consider the case of the user doing "step/stepi" when stopped at a permanent breakpoint. GDB's `resume' calls the gdbarch_skip_permanent_breakpoint hook and then happily continues stepping: /* Normally, by the time we reach `resume', the breakpoints are either removed or inserted, as appropriate. The exception is if we're sitting at a permanent breakpoint; we need to step over it, but permanent breakpoints can't be removed. So we have to test for it here. */ if (breakpoint_here_p (aspace, pc) == permanent_breakpoint_here) { gdbarch_skip_permanent_breakpoint (gdbarch, regcache); } But since gdbarch_skip_permanent_breakpoint already advanced the PC manually, this ends up executing the instruction that is _after_ the breakpoint instruction. The user-visible result is that a single-step steps two instructions. The gdb.arch/i386-bp_permanent.exp test is actually ensuring that that's indeed how things work. It runs to an int3 instruction, does "stepi", and checks that "leave" was executed with that "stepi". Like this: (gdb) b *0x0804848c Breakpoint 2 at 0x804848c (gdb) c Continuing. Breakpoint 2, 0x0804848c in standard () (gdb) disassemble Dump of assembler code for function standard: 0x08048488 <+0>: push %ebp 0x08048489 <+1>: mov %esp,%ebp 0x0804848b <+3>: push %edi => 0x0804848c <+4>: int3 0x0804848d <+5>: leave 0x0804848e <+6>: ret 0x0804848f <+7>: nop (gdb) si 0x0804848e in standard () (gdb) disassemble Dump of assembler code for function standard: 0x08048488 <+0>: push %ebp 0x08048489 <+1>: mov %esp,%ebp 0x0804848b <+3>: push %edi 0x0804848c <+4>: int3 0x0804848d <+5>: leave => 0x0804848e <+6>: ret 0x0804848f <+7>: nop End of assembler dump. (gdb) One would instead expect that a stepi at 0x0804848c stops at 0x0804848d, _before_ the "leave" is executed. This commit changes GDB this way. Care is taken to make stepping into a signal handler when the step starts at a permanent breakpoint instruction work correctly. The patch adjusts gdb.arch/i386-bp_permanent.exp in this direction, and also makes it work on x86_64 (currently it only works on i*86). The patch also adds a new gdb.base/bp-permanent.exp test that exercises many different code paths related to stepping permanent breakpoints, including the stepping with signals cases. The test uses "hack/trick" to make it work on all (or most) platforms -- it doesn't really hard code a breakpoint instruction. Tested on x86_64 Fedora 20, native and gdbserver. gdb/ 2014-11-12 Pedro Alves <palves@redhat.com> * infrun.c (resume): Clear the thread's 'stepped_breakpoint' flag. Rewrite stepping over a permanent breakpoint. (thread_still_needs_step_over, proceed): Don't set stepping_over_breakpoint for permanent breakpoints. (handle_signal_stop): Don't clear stepped_breakpoint. Also pull single-step breakpoints out of the target on hardware step targets. (process_event_stop_test): If stepping a permanent breakpoint doesn't hit the step-resume breakpoint, delete the step-resume breakpoint. (switch_back_to_stepped_thread): Also check if the stepped thread has advanced already on hardware step targets. (currently_stepping): Return true if the thread stepped a breakpoint. gdb/testsuite/ 2014-11-12 Pedro Alves <palves@redhat.com> * gdb.arch/i386-bp_permanent.c: New file. * gdb.arch/i386-bp_permanent.exp: Don't skip on x86_64. (srcfile): Set to i386-bp_permanent.c. (top level): Adjust to work in both 32-bit and 64-bit modes. Test that stepi does not execute the 'leave' instruction, instead of testing it does execute. * gdb.base/bp-permanent.c: New file. * gdb.base/bp-permanent.exp: New file.
Diffstat (limited to 'gdb/testsuite/gdb.arch')
-rw-r--r--gdb/testsuite/gdb.arch/i386-bp_permanent.c57
-rw-r--r--gdb/testsuite/gdb.arch/i386-bp_permanent.exp49
2 files changed, 78 insertions, 28 deletions
diff --git a/gdb/testsuite/gdb.arch/i386-bp_permanent.c b/gdb/testsuite/gdb.arch/i386-bp_permanent.c
new file mode 100644
index 0000000..dc36d89
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/i386-bp_permanent.c
@@ -0,0 +1,57 @@
+/* Copyright (C) 2003-2014 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ 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/>. */
+
+#ifdef SYMBOL_PREFIX
+#define SYMBOL(str) SYMBOL_PREFIX #str
+#else
+#define SYMBOL(str) #str
+#endif
+
+int
+main (void)
+{
+ standard ();
+ return 0;
+}
+
+/* A normal prologue. */
+
+#ifdef __x86_64__
+asm(".text\n"
+ " .align 8\n"
+ SYMBOL (standard) ":\n"
+ " push %rbp\n"
+ " mov %rsp, %rbp\n"
+ " push %rdi\n"
+ " int3\n"
+ " leaveq\n"
+ " retq\n");
+
+#else
+
+asm(".text\n"
+ " .align 8\n"
+ " .global " SYMBOL(standard) "\n"
+ SYMBOL (standard) ":\n"
+ " pushl %ebp\n"
+ " movl %esp, %ebp\n"
+ " pushl %edi\n"
+ " int3\n"
+ " leave\n"
+ " ret\n");
+
+#endif
diff --git a/gdb/testsuite/gdb.arch/i386-bp_permanent.exp b/gdb/testsuite/gdb.arch/i386-bp_permanent.exp
index 6be1626..833b4ed 100644
--- a/gdb/testsuite/gdb.arch/i386-bp_permanent.exp
+++ b/gdb/testsuite/gdb.arch/i386-bp_permanent.exp
@@ -18,13 +18,13 @@
# Test stepping over permanent breakpoints on i386.
-if { ![is_x86_like_target] } then {
+if { ![istarget "i?86-*-*"] && ![istarget "x86_64-*-*"] } then {
verbose "Skipping skip over permanent breakpoint on i386 tests."
return
}
set testfile "i386-bp_permanent"
-set srcfile i386-prologue.c
+set srcfile i386-bp_permanent.c
set binfile ${objdir}/${subdir}/${testfile}
# some targets have leading underscores on assembly symbols.
@@ -51,14 +51,12 @@ if ![runto_main] then {
return -1
}
-set function standard
+set function "standard"
set retcode [gdb_test_multiple "disassemble $function" "Disassemble function '$function'" {
- -re ".*($hex) <\\+0>.*($hex) <\\+4>.*($hex) <\\+5>.*($hex) <\\+6>.*$gdb_prompt $" {
- set function_start $expect_out(1,string)
- set address $expect_out(2,string)
- set address1 $expect_out(3,string)
- set address2 $expect_out(4,string)
+ -re "($hex) <\\+0>.*($hex) <\\+$decimal>.*int3.*($hex) <\\+$decimal>.*leave.*$gdb_prompt $" {
+ set address_bp $expect_out(2,string)
+ set address_after_bp $expect_out(3,string)
}
}]
@@ -67,30 +65,25 @@ if {$retcode != 0} {
return -1
}
-gdb_breakpoint "*$function_start"
+gdb_breakpoint "*$address_bp"
-gdb_breakpoint "*$address"
+gdb_test "continue" "Breakpoint .*, $address_bp in $function.*" \
+ "stop at permanent breakpoint"
-gdb_test "continue" "Breakpoint .*, $function_start in $function.*" \
- "Stop at the '$function' start breakpoint (fetching esp)."
-
-# We want to fetch esp at the start of '$function' function to make sure
-# skip_permanent_breakpoint implementation really skips only the perm.
-# breakpoint. If, for whatever reason, 'leave' instruction doesn't get
-# executed, esp will not have this value.
-set start_esp 0
-gdb_test_multiple "print \$esp" "Fetch esp value." {
+# We want to fetch the stack pointer at the start of '$function'
+# function to make sure the skip_permanent_breakpoint implementation
+# really skips only the permanent breakpoint. If, for whatever
+# reason, the 'leave' instruction executes, the stack pointer will not
+# have this value.
+set start_sp 0
+gdb_test_multiple "print \$sp" "fetch stack pointer value" {
-re "\\\$1.*($hex).*$gdb_prompt $" {
- set start_esp $expect_out(1,string)
+ set start_sp $expect_out(1,string)
}
}
-gdb_test "continue" "Breakpoint .*, $address in $function.*" \
- "Stop at permanent breakpoint."
-
-gdb_test "stepi" "$address1|$address2 in $function.*" \
- "Single stepping past permanent breakpoint."
-
-gdb_test "print \$esp" ".*$start_esp.*" \
- "ESP value does not match - step_permanent_breakpoint wrong."
+gdb_test "stepi" "$address_after_bp in $function.*" \
+ "single-step past permanent breakpoint"
+gdb_test "print \$sp" ".*$start_sp.*" \
+ "stack pointer value matches"