aboutsummaryrefslogtreecommitdiff
path: root/gdb
diff options
context:
space:
mode:
authorPedro Alves <palves@redhat.com>2018-06-19 16:30:13 +0100
committerPedro Alves <palves@redhat.com>2018-06-19 16:30:13 +0100
commit61b04dd04ac2c64d455bc6e17f08a106305b06b3 (patch)
tree6a592d1825fc8af48f35a0e935f878fbd0ead713 /gdb
parent3a075e5628e345701902fd696b4f27941a6b87d0 (diff)
downloadbinutils-61b04dd04ac2c64d455bc6e17f08a106305b06b3.zip
binutils-61b04dd04ac2c64d455bc6e17f08a106305b06b3.tar.gz
binutils-61b04dd04ac2c64d455bc6e17f08a106305b06b3.tar.bz2
Change inline frame breakpoint skipping logic (fix gdb.gdb/selftest.exp)
Currently, gdb.gdb/selftest.exp fails if you build GDB with optimization (-O2, etc.). The reason is that after setting a breakpoint in captured_main, we stop at: ... Breakpoint 1, captured_main_1 (context=<optimized out>) at src/gdb/main.c:492 ... while selftest_setup expects a stop at captured_main. Here, captured_main_1 has been inlined into captured_main, and captured_main has been inlined into gdb_main: ... $ nm ./build/gdb/gdb | egrep ' [tT] .*captured_main|gdb_main' | c++filt 000000000061b950 T gdb_main(captured_main_args*) ... Indeed, the two inlined functions show up in the backtrace: ... (gdb) bt #0 captured_main_1 (context=<optimized out>) at main.c:492 #1 captured_main (data=<optimized out>) at main.c:1147 #2 gdb_main (args=args@entry=0x7fffffffdb80) at main.c:1173 #3 0x000000000040fea5 in main (argc=<optimized out>, argv=<optimized out>) at gdb.c:32 ... We're now stopping at captured_main_1 because commit ddfe970e6bec ("Don't elide all inlined frames") makes GDB present a stop at the innermost inlined frame if the program stopped by a user breakpoint. Now, the selftest.exp testcase explicitly asks to stop at "captured_main", not "captured_main_1", so I'm thinking that it's GDB'S behavior that should be improved. That is what this commit does, by only showing a stop at an inline frame if the user breakpoint was set in that frame's block. Before this commit: (top-gdb) b captured_main Breakpoint 1 at 0x792f99: file src/gdb/main.c, line 492. (top-gdb) r Starting program: build/gdb/gdb Breakpoint 1, captured_main_1 (context=<optimized out>) at src/gdb/main.c:492 492 lim_at_start = (char *) sbrk (0); (top-gdb) After this commit, we now instead get: (top-gdb) b captured_main Breakpoint 1 at 0x791339: file src/gdb/main.c, line 492. (top-gdb) r Starting program: build/gdb/gdb Breakpoint 1, captured_main (data=<optimized out>) at src/gdb/main.c:1147 1147 captured_main_1 (context); (top-gdb) and: (top-gdb) b captured_main_1 Breakpoint 2 at 0x791339: file src/gdb/main.c, line 492. (top-gdb) r Starting program: build/gdb/gdb Breakpoint 2, captured_main_1 (context=<optimized out>) at src/gdb/main.c:492 492 lim_at_start = (char *) sbrk (0); (top-gdb) Note that both captured_main and captured_main_1 resolved to the same address, 0x791339. That is necessary to trigger the issue in question. The gdb.base/inline-break.exp testcase currently does not exercise that, but the new test added by this commit does. That new test fails without the GDB fix and passes with the fix. No regressions on x86-64 GNU/Linux. While at it, the THIS_PC comparison in stopped_by_user_bp_inline_frame is basically a nop, so just remove it -- if a software or hardware breakpoint explains the stop, then it must be that it was installed at the current PC. gdb/ChangeLog: 2018-06-19 Pedro Alves <palves@redhat.com> * inline-frame.c (stopped_by_user_bp_inline_frame): Replace PC parameter with a block parameter. Compare location's block symbol with the frame's block instead of addresses. (skip_inline_frames): Pass the current block instead of the frame's address. Break out as soon as we determine the frame should not be skipped. gdb/testsuite/ChangeLog: 2018-06-19 Pedro Alves <palves@redhat.com> * gdb.opt/inline-break.c (func_inline_callee, func_inline_caller) (func_extern_caller): New. (main): Call func_extern_caller. * gdb.opt/inline-break.exp: Add tests for inline frame skipping logic change.
Diffstat (limited to 'gdb')
-rw-r--r--gdb/ChangeLog9
-rw-r--r--gdb/inline-frame.c23
-rw-r--r--gdb/testsuite/ChangeLog8
-rw-r--r--gdb/testsuite/gdb.opt/inline-break.c34
-rw-r--r--gdb/testsuite/gdb.opt/inline-break.exp25
5 files changed, 87 insertions, 12 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 7b108bf..93703fd 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,12 @@
+2018-06-19 Pedro Alves <palves@redhat.com>
+
+ * inline-frame.c (stopped_by_user_bp_inline_frame): Replace PC
+ parameter with a block parameter. Compare location's block symbol
+ with the frame's block instead of addresses.
+ (skip_inline_frames): Pass the current block instead of the
+ frame's address. Break out as soon as we determine the frame
+ should not be skipped.
+
2018-06-18 Tom Tromey <tom@tromey.com>
* solib-aix.c (solib_aix_get_section_offsets): Return
diff --git a/gdb/inline-frame.c b/gdb/inline-frame.c
index 1ac5835..3edd5b2 100644
--- a/gdb/inline-frame.c
+++ b/gdb/inline-frame.c
@@ -286,11 +286,10 @@ block_starting_point_at (CORE_ADDR pc, const struct block *block)
}
/* Loop over the stop chain and determine if execution stopped in an
- inlined frame because of a user breakpoint. THIS_PC is the current
- frame's PC. */
+ inlined frame because of a user breakpoint set at FRAME_BLOCK. */
static bool
-stopped_by_user_bp_inline_frame (CORE_ADDR this_pc, bpstat stop_chain)
+stopped_by_user_bp_inline_frame (const block *frame_block, bpstat stop_chain)
{
for (bpstat s = stop_chain; s != NULL; s = s->next)
{
@@ -301,9 +300,9 @@ stopped_by_user_bp_inline_frame (CORE_ADDR this_pc, bpstat stop_chain)
bp_location *loc = s->bp_location_at;
enum bp_loc_type t = loc->loc_type;
- if (loc->address == this_pc
- && (t == bp_loc_software_breakpoint
- || t == bp_loc_hardware_breakpoint))
+ if ((t == bp_loc_software_breakpoint
+ || t == bp_loc_hardware_breakpoint)
+ && frame_block == SYMBOL_BLOCK_VALUE (loc->symbol))
return true;
}
}
@@ -340,12 +339,12 @@ skip_inline_frames (ptid_t ptid, bpstat stop_chain)
{
/* Do not skip the inlined frame if execution
stopped in an inlined frame because of a user
- breakpoint. */
- if (!stopped_by_user_bp_inline_frame (this_pc, stop_chain))
- {
- skip_count++;
- last_sym = BLOCK_FUNCTION (cur_block);
- }
+ breakpoint for this inline function. */
+ if (stopped_by_user_bp_inline_frame (cur_block, stop_chain))
+ break;
+
+ skip_count++;
+ last_sym = BLOCK_FUNCTION (cur_block);
}
else
break;
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 358474b..a8f99b8 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,11 @@
+2018-06-19 Pedro Alves <palves@redhat.com>
+
+ * gdb.opt/inline-break.c (func_inline_callee, func_inline_caller)
+ (func_extern_caller): New.
+ (main): Call func_extern_caller.
+ * gdb.opt/inline-break.exp: Add tests for inline frame skipping
+ logic change.
+
2018-06-18 Weimin Pan <weimin.pan@oracle.com>
PR gdb/16841
diff --git a/gdb/testsuite/gdb.opt/inline-break.c b/gdb/testsuite/gdb.opt/inline-break.c
index 922102d..f64a81a 100644
--- a/gdb/testsuite/gdb.opt/inline-break.c
+++ b/gdb/testsuite/gdb.opt/inline-break.c
@@ -176,6 +176,38 @@ not_inline_func3 (int x)
return y + inline_func3 (x);
}
+/* The following three functions serve to exercise GDB's inline frame
+ skipping logic when setting a user breakpoint on an inline function
+ by name. */
+
+/* A static inlined function that is called by another static inlined
+ function. */
+
+static inline ATTR int
+func_inline_callee (int x)
+{
+ return x * 23;
+}
+
+/* A static inlined function that calls another static inlined
+ function. The body of the function is as simple as possible so
+ that both functions are inlined to the same PC address. */
+
+static inline ATTR int
+func_inline_caller (int x)
+{
+ return func_inline_callee (x);
+}
+
+/* An extern not-inline function that calls a static inlined
+ function. */
+
+int
+func_extern_caller (int x)
+{
+ return func_inline_caller (x);
+}
+
/* Entry point. */
int
@@ -205,5 +237,7 @@ main (int argc, char *argv[])
x = not_inline_func3 (-21);
+ func_extern_caller (1);
+
return x;
}
diff --git a/gdb/testsuite/gdb.opt/inline-break.exp b/gdb/testsuite/gdb.opt/inline-break.exp
index 008ff1a..bae7625 100644
--- a/gdb/testsuite/gdb.opt/inline-break.exp
+++ b/gdb/testsuite/gdb.opt/inline-break.exp
@@ -231,4 +231,29 @@ foreach_with_prefix cmd [list "break" "tbreak"] {
}
}
+# func_extern_caller calls func_inline_caller which calls
+# func_inline_callee. The latter two are both inline functions. Test
+# that setting a breakpoint on each of the functions reports a stop at
+# that function. This exercises the inline frame skipping logic. If
+# we set a breakpoint at function A, we want to present the stop at A,
+# even if A's entry code is an inlined call to another inline function
+# B.
+
+foreach_with_prefix func {
+ "func_extern_caller"
+ "func_inline_caller"
+ "func_inline_callee"
+} {
+ clean_restart $binfile
+
+ if {![runto main]} {
+ untested "could not run to main"
+ continue
+ }
+
+ gdb_breakpoint $func
+ gdb_test "continue" "Breakpoint .* $func .*at .*$srcfile.*" \
+ "breakpoint hit presents stop at breakpointed function"
+}
+
unset -nocomplain results