diff options
author | Pedro Alves <palves@redhat.com> | 2014-10-15 20:18:31 +0100 |
---|---|---|
committer | Pedro Alves <palves@redhat.com> | 2014-10-15 20:18:31 +0100 |
commit | 7c16b83e0521a007e4d86fc30e334b41b01668b4 (patch) | |
tree | 4b2b8fbdaf92625694dfa3b894e7b74665dd718a /gdb/testsuite/gdb.base | |
parent | 0cbcdb96eaba80fe8e94ccc2b6f1f382a467a04e (diff) | |
download | gdb-7c16b83e0521a007e4d86fc30e334b41b01668b4.zip gdb-7c16b83e0521a007e4d86fc30e334b41b01668b4.tar.gz gdb-7c16b83e0521a007e4d86fc30e334b41b01668b4.tar.bz2 |
Put single-step breakpoints on the bp_location chain
This patch makes single-step breakpoints "real" breakpoints on the
global location list.
There are several benefits to this:
- It removes the currently limitation that only 2 single-step
breakpoints can be inserted. See an example here of a discussion
around a case that wants more than 2, possibly unbounded:
https://sourceware.org/ml/gdb-patches/2014-03/msg00663.html
- makes software single-step work on read-only code regions.
The logic to convert a software breakpoint to a hardware breakpoint
if the memory map says the breakpoint address is in read only memory
is in insert_bp_location. Because software single-step breakpoints
bypass all that go and straight to target_insert_breakpoint, we
can't software single-step over read only memory. This patch
removes that limitation, and adds a test that makes sure that works,
by forcing a code region to read-only with "mem LOW HIGH ro" and
then stepping through that.
- Fixes PR breakpoints/9649
This is an assertion failure in insert_single_step_breakpoint in
breakpoint.c, because we may leave stale single-step breakpoints
behind on error.
The tests for stepping through read-only regions exercise the root
cause of the bug, which is that we leave single-step breakpoints
behind if we fail to insert any single-step breakpoint. Deleting
the single-step breakpoints in resume_cleanups,
delete_just_stopped_threads_infrun_breakpoints, and
fetch_inferior_event fixes this. Without that, we'd no longer hit
the assertion, as that code is deleted, but we'd instead run into
errors/warnings trying to insert/remove the stale breakpoints on
next resume.
- Paves the way to have multiple threads software single-stepping at
the same time, leaving update_global_location_list to worry about
duplicate locations.
- Makes the moribund location machinery aware of software single-step
breakpoints, paving the way to enable software single-step on
non-stop, instead of forcing serialized displaced stepping for all
single steps.
- It's generaly cleaner.
We no longer have to play games with single-step breakpoints
inserted at the same address as regular breakpoints, like we
recently had to do for 7.8. See this discussion:
https://sourceware.org/ml/gdb-patches/2014-06/msg00052.html.
Tested on x86_64 Fedora 20, on top of my 'single-step breakpoints on
x86' series.
gdb/
2014-10-15 Pedro Alves <palves@redhat.com>
PR breakpoints/9649
* breakpoint.c (single_step_breakpoints, single_step_gdbarch):
Delete array globals.
(single_step_breakpoints): New global.
(breakpoint_xfer_memory): Remove special handling for single-step
breakpoints.
(update_breakpoints_after_exec): Delete bp_single_step
breakpoints.
(detach_breakpoints): Remove special handling for single-step
breakpoints.
(breakpoint_init_inferior): Delete bp_single_step breakpoints.
(bpstat_stop_status): Add comment.
(bpstat_what, bptype_string, print_one_breakpoint_location)
(adjust_breakpoint_address, init_bp_location): Handle
bp_single_step.
(new_single_step_breakpoint): New function.
(set_momentary_breakpoint, bkpt_remove_location): Remove special
handling for single-step breakpoints.
(insert_single_step_breakpoint, single_step_breakpoints_inserted)
(remove_single_step_breakpoints, cancel_single_step_breakpoints):
Rewrite.
(detach_single_step_breakpoints, find_single_step_breakpoint):
Delete functions.
(breakpoint_has_location_inserted_here): New function.
(single_step_breakpoint_inserted_here_p): Rewrite.
* breakpoint.h: Remove FIXME.
(enum bptype) <bp_single_step>: New enum value.
(insert_single_step_breakpoint): Update comment.
* infrun.c (resume_cleanups)
(delete_step_thread_step_resume_breakpoint): Remove single-step
breakpoints.
(fetch_inferior_event): Install a cleanup that removes infrun
breakpoints.
(switch_back_to_stepped_thread) <expect thread advanced also>:
Clear step-over info.
gdb/testsuite/
2014-10-15 Pedro Alves <palves@redhat.com>
PR breakpoints/9649
* gdb.base/breakpoint-in-ro-region.c (main): Add more instructions.
* gdb.base/breakpoint-in-ro-region.exp
(probe_target_hardware_step): New procedure.
(top level): Probe hardware stepping and hardware breakpoint
support. Test stepping through a read-only region, with both
"breakpoint auto-hw" on and off and both "always-inserted" on and
off.
Diffstat (limited to 'gdb/testsuite/gdb.base')
-rw-r--r-- | gdb/testsuite/gdb.base/breakpoint-in-ro-region.c | 9 | ||||
-rw-r--r-- | gdb/testsuite/gdb.base/breakpoint-in-ro-region.exp | 104 |
2 files changed, 113 insertions, 0 deletions
diff --git a/gdb/testsuite/gdb.base/breakpoint-in-ro-region.c b/gdb/testsuite/gdb.base/breakpoint-in-ro-region.c index 696a67d..2a999b1 100644 --- a/gdb/testsuite/gdb.base/breakpoint-in-ro-region.c +++ b/gdb/testsuite/gdb.base/breakpoint-in-ro-region.c @@ -23,6 +23,15 @@ main (void) i = 0; i = 0; i = 0; + i = 0; + i = 0; + i = 0; + i = 0; + i = 0; + i = 0; + i = 0; + i = 0; + i = 0; return 0; } diff --git a/gdb/testsuite/gdb.base/breakpoint-in-ro-region.exp b/gdb/testsuite/gdb.base/breakpoint-in-ro-region.exp index 8eacefa..1991aa5 100644 --- a/gdb/testsuite/gdb.base/breakpoint-in-ro-region.exp +++ b/gdb/testsuite/gdb.base/breakpoint-in-ro-region.exp @@ -27,6 +27,28 @@ if ![runto main] { delete_breakpoints +# Probe for hardware stepping. + +proc probe_target_hardware_step {} { + global gdb_prompt + + set hw_step 0 + + gdb_test_no_output "set debug target 1" + set test "probe target hardware step" + gdb_test_multiple "si" $test { + -re "to_resume \\(\[^\r\n\]+, step, .*$gdb_prompt $" { + set hw_step 1 + pass $test + } + -re "$gdb_prompt $" { + pass $test + } + } + gdb_test "set debug target 0" "->to_log_command.*\\).*" + return $hw_step +} + # Get the bounds of a function, and write them to FUNC_LO (inclusive), # FUNC_HI (exclusive). Return true on success and false on failure. proc get_function_bounds {function func_lo func_hi} { @@ -108,6 +130,7 @@ proc get_next_insn {} { return $next } +set hw_step [probe_target_hardware_step] if ![get_function_bounds "main" main_lo main_hi] { # Can't do the following tests if main's bounds are unknown. @@ -140,3 +163,84 @@ gdb_test "p /x *(char *) $main_lo = 1" \ gdb_test "break *$main_lo" \ "Cannot insert breakpoint .*Cannot set software breakpoint at read-only address $main_lo.*" \ "inserting software breakpoint in read-only memory fails" + +delete_breakpoints + +set supports_hbreak 0 +set test "probe hbreak support" +gdb_test_multiple "hbreak *$main_lo" $test { + -re "You may have requested too many.*$gdb_prompt $" { + pass "$test (no support)" + } + -re "No hardware breakpoint support.*$gdb_prompt $" { + pass "$test (no support)" + } + -re "$gdb_prompt $" { + pass "$test (support)" + set supports_hbreak 1 + } +} + +delete_breakpoints + +# Check that the "auto-hw on/off" setting affects single-step +# breakpoints as expected, by stepping through the read-only region. +# If the target does hardware stepping, we won't exercise that aspect, +# but we should be able to step through the region without seeing the +# hardware breakpoint or read-only address errors. +proc test_single_step { always_inserted auto_hw } { + global gdb_prompt + global decimal + global supports_hbreak + global hw_step + + gdb_test_no_output "set breakpoint always-inserted $always_inserted" + gdb_test_no_output "set breakpoint auto-hw $auto_hw" + + # Get the address of the current instruction so we know where SI is + # starting from. + set curr_insn [get_curr_insn] + + # Get the address of the next instruction so we know where SI should + # land. + set next_insn [get_next_insn] + + set test "step in ro region" + gdb_test_multiple "si" $test { + -re "Could not insert hardware breakpoints.*$gdb_prompt $" { + gdb_assert {!$hw_step && $auto_hw == "on" && !$supports_hbreak} \ + "$test (cannot insert hw break)" + } + -re "Cannot set software breakpoint at read-only address $next_insn.*$gdb_prompt $" { + gdb_assert {!$hw_step && $auto_hw == "off"} \ + "$test (cannot insert sw break)" + } + -re "^si\r\nNote: automatically using hardware breakpoints for read-only addresses\.\r\n${decimal}\[ \t\]+i = 0;\r\n$gdb_prompt $" { + gdb_assert {!$hw_step && $auto_hw == "on" && $supports_hbreak} \ + "$test (auto-hw)" + } + -re "^si\r\n${decimal}\[ \t\]+i = 0;\r\n$gdb_prompt $" { + gdb_assert {$hw_step || ($auto_hw == "on" && $supports_hbreak)} \ + "$test (no error)" + } + } + + gdb_test "maint info breakpoints 0" \ + "No breakpoint or watchpoint matching '0'\." \ + "single-step breakpoint is not left behind" + + # Confirm the thread really advanced. + if {$hw_step || ($auto_hw == "on" && $supports_hbreak)} { + gdb_test "p /x \$pc" " = $next_insn" "thread advanced" + } else { + gdb_test "p /x \$pc" " = $curr_insn" "thread did not advance" + } +} + +foreach always_inserted {"off" "on"} { + foreach auto_hw {"off" "on"} { + with_test_prefix "always-inserted $always_inserted: auto-hw $auto_hw" { + test_single_step $always_inserted $auto_hw + } + } +} |