Fix breakpoints on file reloads for PIE binaries
authorAlan Hayward <alan.hayward@arm.com>
Mon, 8 Jul 2019 09:00:25 +0000 (10:00 +0100)
committerAlan Hayward <alan.hayward@arm.com>
Mon, 8 Jul 2019 09:13:46 +0000 (10:13 +0100)
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.

gdb/ChangeLog
gdb/symfile.c
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.base/break-idempotent.exp

index dfd10419042ce41a637835610bbce811e016ff6c..218bbf62234a5a0cbb2b9eeb2744636e7fc7f11a 100644 (file)
@@ -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:
index 59647bfe9d80964cfba0905856505d989f5b1db8..dc6bdf3fd4a49f7ae4268d15abc0c71742328f05 100644 (file)
@@ -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 ();
     }
 }
 
index 7631cce62a9c8cb10995d2cffd99020114444ef2..a6d6843d9692acdf9601f442cc34320c90634468 100644 (file)
@@ -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
index 902a5f818be9971422b5cfb154a2f28c7ab998da..96f91c50f906955b289b7ee7dfd65dc7c375e79a 100644 (file)
 
 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.
 
@@ -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 $" {
@@ -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 {
@@ -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"
+       }
     }
 }