Fix running to breakpoint set in inline function by lineno/address
authorPedro Alves <palves@redhat.com>
Fri, 29 Jun 2018 18:31:49 +0000 (19:31 +0100)
committerPedro Alves <palves@redhat.com>
Fri, 29 Jun 2018 18:35:13 +0000 (19:35 +0100)
Commit 61b04dd04ac2 ("Change inline frame breakpoint skipping logic
(fix gdb.gdb/selftest.exp)") caused a GDB crash when you set a
breakpoint by line number in an inline function, and then run to the
breakpoint:

    $ gdb -q test Reading symbols from test...done.
    (gdb) b inline-break.c:32
    Breakpoint 1 at 0x40062f: file inline-break.c, line 32.
    (gdb) run
    Starting program: /[...]/test
    [1]    75618 segmentation fault  /[...]/gdb -q test

The problem occurs because we assume that a bp_location's symbol is
not NULL, which is not true when we set the breakpoint with a linespec
location:

    Program received signal SIGSEGV, Segmentation fault.
    0x00000000006f42bb in stopped_by_user_bp_inline_frame (
        stop_chain=<optimized out>, frame_block=<optimized out>)
        at gdb/inline-frame.c:305
    305       && frame_block == SYMBOL_BLOCK_VALUE (loc->symbol))
    (gdb) p loc->symbol
    $1 = (const symbol *) 0x0

The same thing happens if you run to a breakpoint set in an inline
function by address:

  (gdb) b *0x40062f
  Breakpoint 3 at 0x40062f: file inline-break.c, line 32.

To fix this, add a null pointer check, to avoid the crash, and make it
so that if there's no symbol for the location, then we present the
stop at the inline function.  This preserves the previous behavior
when e.g., setting a breakpoint by address, with "b *ADDRESS".

gdb/ChangeLog:
2018-06-29  Pedro Alves  <palves@redhat.com>

* inline-frame.c (stopped_by_user_bp_inline_frame): Return
true if the the location has no symbol.

gdb/testsuite/ChangeLog:
2018-06-29  Pedro Alves  <palves@redhat.com>

* gdb.opt/inline-break.c (func1): Add "break here" marker.
* gdb.opt/inline-break.exp: Test setting breakpoints by line
number and address and running to them.

gdb/ChangeLog
gdb/inline-frame.c
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.opt/inline-break.c
gdb/testsuite/gdb.opt/inline-break.exp

index 4c04d0ba728162618475073e223948c33d9dc67f..3ed5cf3d2627993567527eb504bab381c4a60811 100644 (file)
@@ -1,3 +1,8 @@
+2018-06-29  Pedro Alves  <palves@redhat.com>
+
+       * inline-frame.c (stopped_by_user_bp_inline_frame): Return
+       true if the the location has no symbol.
+
 2018-06-28  Tom Tromey  <tom@tromey.com>
 
        * NEWS: Mention --enable-codesign.
index 896b0004e4a381c24cb9042841d80dd6b5813d3f..c6caf9d0c6ef937f676e641a4e7df322a903ab8e 100644 (file)
@@ -300,10 +300,18 @@ stopped_by_user_bp_inline_frame (const block *frame_block, bpstat stop_chain)
          bp_location *loc = s->bp_location_at;
          enum bp_loc_type t = loc->loc_type;
 
-         if ((t == bp_loc_software_breakpoint
-              || t == bp_loc_hardware_breakpoint)
-             && frame_block == SYMBOL_BLOCK_VALUE (loc->symbol))
-           return true;
+         if (t == bp_loc_software_breakpoint
+             || t == bp_loc_hardware_breakpoint)
+           {
+             /* If the location has a function symbol, check whether
+                the frame was for that inlined function.  If it has
+                no function symbol, then assume it is.  I.e., default
+                to presenting the stop at the innermost inline
+                function.  */
+             if (loc->symbol == nullptr
+                 || frame_block == SYMBOL_BLOCK_VALUE (loc->symbol))
+               return true;
+           }
        }
     }
 
index d16f33a42d452297183bad22c60efd6bfb6f57e5..3d93d321ef0f6f7951fc8056c9404fe6489c2632 100644 (file)
@@ -1,3 +1,9 @@
+2018-06-29  Pedro Alves  <palves@redhat.com>
+
+       * gdb.opt/inline-break.c (func1): Add "break here" marker.
+       * gdb.opt/inline-break.exp: Test setting breakpoints by line
+       number and address and running to them.
+
 2018-06-29  Richard Bunt  <richard.bunt@arm.com>
 
        * gdb.base/watchpoint-hw-attach.exp: Remove unstable output.
index f64a81af93904452a73537691c9ef75b50b406c6..d4779299fa2543615d4708e5af34b2c0872789f7 100644 (file)
@@ -29,7 +29,7 @@
 static inline ATTR int
 func1 (int x)
 {
-  return x * 23;
+  return x * 23; /* break here */
 }
 
 /* A non-static inlined function that is called once.  */
index bae7625490584c6a91c3493b2b2fab75170521c8..46ef6f1bef882e3b69ced4d83264fda240e99557 100644 (file)
@@ -256,4 +256,46 @@ foreach_with_prefix func {
        "breakpoint hit presents stop at breakpointed function"
 }
 
+# Test setting a breakpoint in an inline function by line number and
+# by address, and that GDB presents the stop there.
+
+set line [gdb_get_line_number "break here"]
+
+with_test_prefix "line number" {
+    clean_restart $binfile
+
+    if {![runto main]} {
+       untested "could not run to main"
+       continue
+    }
+
+    # Set the breakpoint by line number, and check that GDB reports
+    # the breakpoint location being the inline function.
+    gdb_test "break $srcfile:$line" ".*Breakpoint .* at .*: file .*$srcfile, line $line."
+    gdb_test "continue" "Breakpoint .*, func1 \\(x=1\\) at .*$srcfile:$line.*break here.*" \
+       "breakpoint hit presents stop at inlined function"
+
+    # Save the PC for the following by-address test.
+    set address [get_hexadecimal_valueof "\$pc" "0"]
+}
+
+# Test setting a breakpoint in an inline function by address, and that
+# GDB presents the stop there.
+
+with_test_prefix "address" {
+
+    clean_restart $binfile
+
+    if {![runto main]} {
+       untested "could not run to main"
+       continue
+    }
+
+    # Set the breakpoint by address, and check that GDB reports the
+    # breakpoint location being the inline function.
+    gdb_test "break *$address" ".*Breakpoint .* at $address: file .*$srcfile, line $line."
+    gdb_test "continue" "Breakpoint .*, func1 \\(x=1\\) at .*$srcfile:$line.*break here.*" \
+       "breakpoint hit presents stop at inlined function"
+}
+
 unset -nocomplain results