Skip to content

Commit

Permalink
Fix breakpoints on file reloads for PIE binaries
Browse files Browse the repository at this point in the history
When a binary is built using PIE, reloading the file will cause GDB to error
on restart.  For example:
gdb ./a.out
(gdb) break main
(gdb) run
(gdb) file ./a.out
(gdb) continue

Will cause GDB to error with:
Continuing.
Warning:
Cannot insert breakpoint 1.
Cannot access memory at address 0x9e0
Command aborted.

This is due to the symbol offsets not being relocated after reloading the file.

Fix is to ensure solib_create_inferior_hook is called, in the same manner as
infrun.c:follow_exec().

Expand the idempotent test to cover PIE scenarios.

gdb/ChangeLog:

	* symfile.c (symbol_file_command): Call solib_create_inferior_hook.

gdb/testsuite/ChangeLog:

	* gdb.base/break-idempotent.exp: Test both PIE and non PIE.
  • Loading branch information
a74nh committed Jul 8, 2019
1 parent 62a4795 commit ea142fb
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 30 deletions.
4 changes: 4 additions & 0 deletions gdb/ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
2019-08-04 Alan Hayward <alan.hayward@arm.com>

* symfile.c (symbol_file_command): Call solib_create_inferior_hook.

2019-07-04 Tom Tromey <tom@tromey.com>

PR tui/24724:
Expand Down
12 changes: 12 additions & 0 deletions gdb/symfile.c
Original file line number Diff line number Diff line change
Expand Up @@ -1672,7 +1672,19 @@ symbol_file_command (const char *args, int from_tty)

validate_readnow_readnever (flags);

/* Set SYMFILE_DEFER_BP_RESET because the proper displacement for a PIE
(Position Independent Executable) main symbol file will only be
computed by the solib_create_inferior_hook below. Without it,
breakpoint_re_set would fail to insert the breakpoints with the zero
displacement. */
add_flags |= SYMFILE_DEFER_BP_RESET;

symbol_file_add_main_1 (name, add_flags, flags, offset);

solib_create_inferior_hook (from_tty);

/* Now it's safe to re-add the breakpoints. */
breakpoint_re_set ();
}
}

Expand Down
4 changes: 4 additions & 0 deletions gdb/testsuite/ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
2019-07-08 Alan Hayward <alan.hayward@arm.com>

* gdb.base/break-idempotent.exp: Test both PIE and non PIE.

2019-07-04 Pedro Alves <palves@redhat.com>

* lib/gdb.exp (foreach_with_prefix): Don't return early if
Expand Down
66 changes: 36 additions & 30 deletions gdb/testsuite/gdb.base/break-idempotent.exp
Original file line number Diff line number Diff line change
Expand Up @@ -36,23 +36,6 @@

standard_testfile

if {[prepare_for_testing "failed to prepare" $testfile $srcfile debug]} {
return -1
}

if ![runto_main] then {
fail "can't run to main"
return 0
}

if [is_remote host] {
set arg [remote_download host $binfile]
if { $arg == "" } {
perror "download failed"
return -1
}
}

# Force a breakpoint re-set in GDB. Currently this is done by
# reloading symbols with the "file" command.

Expand All @@ -62,11 +45,11 @@ proc force_breakpoint_re_set {} {
set test "file \$binfile"
gdb_test_multiple "file $binfile" $test {
-re "Are you sure you want to change the file. .*y or n. $" {
send_gdb "y\n"
send_gdb "y\n" optional
exp_continue
}
-re "Load new symbol table from \".*\".*y or n. $" {
send_gdb "y\n"
send_gdb "y\n" optional
exp_continue
}
-re "Reading symbols from.*$gdb_prompt $" {
Expand Down Expand Up @@ -123,7 +106,7 @@ proc set_breakpoint { break_command } {
proc test_break { always_inserted break_command } {
set cmd [lindex [split "$break_command"] 0]

with_test_prefix "always-inserted $always_inserted: $cmd" {
with_test_prefix "$cmd" {
delete_breakpoints

if ![runto_main] then {
Expand Down Expand Up @@ -163,20 +146,43 @@ proc test_break { always_inserted break_command } {
}
}

foreach always_inserted { "off" "on" } {
test_break $always_inserted "break"
# The testcase uses the "file" command to force breakpoint re-set in
# GDB. Test both with and without PIE, as GDB used to mishandle
# breakpoint re-set when reloading PIEs.
foreach_with_prefix pie { "nopie" "pie" } {

set opts {debug}
lappend opts $pie

if {![skip_hw_breakpoint_tests]} {
test_break $always_inserted "hbreak"
set binfile [standard_output_file $testfile-$pie]

if {[prepare_for_testing "failed to prepare" $binfile $srcfile $opts]} {
continue
}

if {![skip_hw_watchpoint_tests]} {
test_break $always_inserted "watch"
if [is_remote host] {
set arg [remote_download host $binfile]
if { $arg == "" } {
untested "download failed"
continue
}
}

if {![skip_hw_watchpoint_access_tests]
&& ![skip_hw_watchpoint_multi_tests]} {
test_break $always_inserted "rwatch"
test_break $always_inserted "awatch"
foreach_with_prefix always_inserted { "off" "on" } {
test_break $always_inserted "break"

if {![skip_hw_breakpoint_tests]} {
test_break $always_inserted "hbreak"
}

if {![skip_hw_watchpoint_tests]} {
test_break $always_inserted "watch"
}

if {![skip_hw_watchpoint_access_tests]
&& ![skip_hw_watchpoint_multi_tests]} {
test_break $always_inserted "rwatch"
test_break $always_inserted "awatch"
}
}
}

0 comments on commit ea142fb

Please sign in to comment.