Use containing function when reporting breakpoint location.

Message ID 1489179553-4273-1-git-send-email-keiths@redhat.com
State New, archived
Headers

Commit Message

Keith Seitz March 10, 2017, 8:59 p.m. UTC
  print_breakpoint_location currently uses find_pc_sect_function, which always
returns the linkage symbol.  This essentially means that it skips over any
inline frames.  Thus, when a breakpoint is set in an inlined function,
"info break" may report the calling function as the location of the
breakpoint.

While pedantically true, it is a little misleading to users:

(gdb) b inline_func
Breakpoint 1 at 0x400434: file test.c, line 5.
(gdb) inf br
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x0000000000400434 in main at test.c:5

With this patch, print_breakpoint_location now calls a new variation of
find_pc_sect_function, find_pc_sect_containing_function, which does not
skip over inlined functions, and the breakpoint location is now reported
"correctly":

(gdb) inf br
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x0000000000400434 in inline_func at test.c:5

gdb/ChangeLog

	* blockframe.c (find_pc_sect_containing_function): New function.
	* breakpoint.c (print_breakpoint_location): Use
	find_pc_sect_containing_function to avoid skipping inline frames.
	* symtab.h (find_pc_sect_containing_function): Declare.

gdb/testsuite/ChangeLog

	* gdb.opt/inline-break.exp (break_info_1): New procedure.
	Use break_info_1 to test "info break" for all breakpoints.
---
 gdb/ChangeLog                          |  7 ++++
 gdb/blockframe.c                       | 12 ++++++
 gdb/breakpoint.c                       |  2 +-
 gdb/symtab.h                           |  7 ++++
 gdb/testsuite/ChangeLog                |  5 +++
 gdb/testsuite/gdb.opt/inline-break.exp | 75 ++++++++++++++++++++++++++++++++++
 6 files changed, 107 insertions(+), 1 deletion(-)
  

Patch

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index e4c4432..87dc913 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,10 @@ 
+2017-MM-DD  Keith Seitz  <keiths@redhat.com>
+
+	* blockframe.c (find_pc_sect_containing_function): New function.
+	* breakpoint.c (print_breakpoint_location): Use
+	find_pc_sect_containing_function to avoid skipping inline frames.
+	* symtab.h (find_pc_sect_containing_function): Declare.
+
 2017-03-10  Keith Seitz  <keiths@redhat.com>
 
 	PR c++/8218
diff --git a/gdb/blockframe.c b/gdb/blockframe.c
index 5ba993c..c602d6b 100644
--- a/gdb/blockframe.c
+++ b/gdb/blockframe.c
@@ -142,6 +142,18 @@  find_pc_sect_function (CORE_ADDR pc, struct obj_section *section)
   return block_linkage_function (b);
 }
 
+/* See description in symtab.h.  */
+
+struct symbol *
+find_pc_sect_containing_function (CORE_ADDR pc, struct obj_section *section)
+{
+  const struct block *b = block_for_pc_sect (pc, section);
+
+  if (b == NULL)
+    return NULL;
+  return block_containing_function (b);
+}
+
 /* Return the function containing pc value PC.
    Returns 0 if function is not known.  
    Backward compatibility, no section */
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index ab6e9c8..c470f96 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -6154,7 +6154,7 @@  print_breakpoint_location (struct breakpoint *b,
   else if (loc && loc->symtab)
     {
       struct symbol *sym 
-	= find_pc_sect_function (loc->address, loc->section);
+	= find_pc_sect_containing_function (loc->address, loc->section);
       if (sym)
 	{
 	  uiout->text ("in ");
diff --git a/gdb/symtab.h b/gdb/symtab.h
index d8c665c..b16cb18 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -1336,6 +1336,13 @@  extern struct symbol *find_pc_function (CORE_ADDR);
 
 extern struct symbol *find_pc_sect_function (CORE_ADDR, struct obj_section *);
 
+/* Return the function containing pc value PC in section SECTION.
+   Returns NULL if function is not known.  Unlike find_pc_sect_function,
+   this function does not skip inline frames.  */
+
+extern struct symbol *find_pc_sect_containing_function (CORE_ADDR,
+							struct obj_section *);
+
 extern int find_pc_partial_function_gnu_ifunc (CORE_ADDR pc, const char **name,
 					       CORE_ADDR *address,
 					       CORE_ADDR *endaddr,
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 0718d76..b32136c 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,8 @@ 
+2017-MM-DD  Keith Seitz  <keiths@redhat.com>
+
+	* gdb.opt/inline-break.exp (break_info_1): New procedure.
+	Use break_info_1 to test "info break" for all breakpoints.
+
 2017-03-10  Keith Seitz  <keiths@redhat.com>
 
 	PR c++/8128
diff --git a/gdb/testsuite/gdb.opt/inline-break.exp b/gdb/testsuite/gdb.opt/inline-break.exp
index 7be3a34..ff15f1a 100644
--- a/gdb/testsuite/gdb.opt/inline-break.exp
+++ b/gdb/testsuite/gdb.opt/inline-break.exp
@@ -24,6 +24,61 @@  if { [prepare_for_testing "failed to prepare" $testfile $srcfile \
     return -1
 }
 
+# Return a string that may be used to match the output of "info break NUM".
+#
+# Optional arguments:
+#
+# source  - the name of the source file
+# func    - the name of the function
+# disp    - the breakpoint disposition
+# enabled - breakpoint enable state
+# locs    - number of locations
+# line    - source line number (ignored without -source)
+
+proc break_info_1 {num args} {
+    global decimal
+
+    # Column delimiter
+    set c {[\t ]+}
+
+    # Row delimiter
+    set end {[\r\n \t]+}
+
+    # Table header
+    set header "[join [list Num Type Disp Enb Address What] ${c}]"
+
+    # Get/configure any optional parameters.
+    parse_args [list {source ""} {func ".*"} {disp "keep"} \
+		    {enabled "y"} {locs 1} [list line $decimal]]
+
+    if {$source != ""} {
+	set source "/$source:$line"
+    }
+
+    # Result starts with the standard header.
+    set result "$header${end}"
+
+    # Set up for multi-location breakpoint marker.
+    if {$locs == 1} {
+	set multi ".*"
+    } else {
+	set multi "<MULTIPLE>${end}"
+    }
+    append result "[join [list $num breakpoint $disp $enabled $multi] $c]"
+
+    # Add sub-location info.
+    if {$locs > 1} {
+	for {set i 1} {$i <= $locs} {incr i} {
+	    append result "[join [list $num.$i $enabled] $c].*"
+	}
+    }
+
+    #  Add function/source file info.
+    append result "in $func at .*$source${end}"
+
+    return $result
+}
+
 #
 # func1 is a static inlined function that is called once.
 # The result should be a single-location breakpoint.
@@ -111,3 +166,23 @@  gdb_test "print func1" \
 #
 gdb_test "print func2" \
     "\\\$.* = {int \\(int\\)} .* <func2>"
+
+# Test that "info break" reports the location of the breakpoints "inside"
+# the inlined functions
+
+set i 0
+set results([incr i]) [break_info_1 1 -source $srcfile -func "func1"]
+set results([incr i]) [break_info_1 2 -locs 2 -source $srcfile -func "func2"]
+set results([incr i]) [break_info_1 3 -source $srcfile -func "func3b"]
+set results([incr i]) [break_info_1 4 -locs 2 -source $srcfile -func "func4b"]
+set results([incr i]) [break_info_1 5 -locs 2 -source $srcfile -func "func5b"]
+set results([incr i]) [break_info_1 6 -locs 3 -source $srcfile -func "func6b"]
+set results([incr i]) [break_info_1 7 -locs 2 -source $srcfile -func "func7b"]
+set results([incr i]) [break_info_1 8 -locs 3 -source $srcfile -func "func8b"]
+
+for {set i 1} {$i <= [llength [array names results]]} {incr i} {
+    send_log "Expecting: $results($i)\n"
+    gdb_test "info break $i" $results($i)
+}
+
+unset -nocomplain results