binutils-gdb/gdb/blockframe.c
Pedro Alves cd2bb70994 "break LINENO/*ADDRESS", inline functions and "info break" output
While experimenting with the previous patch, I noticed this inconsistency
in GDB's output:

  (gdb) b 32
  Breakpoint 1 at 0x40062f: file inline-break.c, line 32.                  (1)
  (gdb) r
  ....
  Breakpoint 1, func1 (x=1) at inline-break.c:32                           (2)
  32        return x * 23; /* break here */
  (gdb) info breakpoints
  Num     Type           Disp Enb Address    What
  1       breakpoint     keep y   0x40062f   in main at inline-break.c:32  (3)
	  breakpoint already hit 1 time
  (gdb)

Notice that when the breakpoint as set, GDB showed "inline-break.c,
line 32" (1), the same line number that was specified in the command.

When we run to the breakpoint, we present the stop at the same line
number, and correctly show "func1" as the function name (2).

But in "info break" output (3), notice that we say "in main", not "in
func1".

The same thing happens if you set a breakpoint by address.  I.e.:

  (gdb) b *0x40062f
  Breakpoint 2 at 0x40062f: file inline-break.c, line 32.
  (gdb) info breakpoints
  Num     Type           Disp Enb Address            What
  2       breakpoint     keep y   0x000000000040062f in main at inline-break.c:32
   (gdb) r
   ....
  Breakpoint 2, func1 (x=1) at inline-break.c:32
  32        return x * 23; /* break here */

The problem is that the breakpoints were set at an inline function,
but when we set such a breakpoint by line number or address, we don't
record the functions symbol in the sal, and as consequence the
breakpoint location does not have an associated symbol either.

Then, in print_breakpoint_location, if the location does not have a
symbol, we call find_pc_sect_function to find one, and this is what
finds "main", because find_pc_sect_function uses
block_linkage_function:

  /* Return the symbol for the function which contains a specified
     lexical block, described by a struct block BL.  The return value
     will not be an inlined function; the containing function will be
     returned instead.  */

  struct symbol *
  block_linkage_function (const struct block *bl)

To fix this, this commit adds an alternative to find_pc_sect_function
that uses block_containing_function instead:

  /* Return the symbol for the function which contains a specified
     block, described by a struct block BL.  The return value will be
     the closest enclosing function, which might be an inline
     function.  */

  struct symbol *
  block_containing_function (const struct block *bl)

(It seems odd to me that block_linkage_function says "the CONTAINING
function will be returned", and then block_containing_function says it
returns "the closest enclosing function".  Something seems reversed
here.  Still, I've kept the same nomenclature and copied the comments,
so that at least there's consistency.  Maybe we should fix that up
somehow.)

Then I wondered, why make print_breakpoint_location look up the symbol
every time it is called, instead of just always storing the symbol
when the location is created, since the location already stores the
symbol in some cases.  So to find which cases might be missing setting
the symbol in the sal which is used to create the breakpoint location,
I added an assertion to print_breakpoint_location, and ran the
testsuite.  That caught a few places, unsurprisingly:

 - setting a breakpoint by line number
 - setting a breapoint by address
 - ifunc resolving

Those are all fixed by this commit.  I decided not to add the
assertion to block_linkage_function and leave the existing "if (sym)"
check in place, because it's plausible that we have symtabs with line
info but no symbols.  I.e., that would not be a GDB bug, but
a peculiarity of debug info input.

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

	* blockframe.c (find_pc_sect_containing_function): New function.
	* breakpoint.c (print_breakpoint_location): Don't call
	find_pc_sect_function.
	* linespec.c (create_sals_line_offset): Record the location's
	symbol in the sal.
	* linespec.c (convert_address_location_to_sals): Fill in sal's
	symbol with find_pc_sect_containing_function.
	* symtab.c (find_function_start_sal): Rename to ...
	(find_function_start_sal_1): ... this.
	(find_function_start_sal): Reimplement as wrapper around
	find_function_start_sal_1, and use
	find_pc_sect_containing_function to fill in the sal's symbol.
	(find_function_start_sal(symbol*, bool)): Adjust.
	* symtab.h (find_pc_function, find_pc_sect_function): Adjust
	comments.
	(find_pc_sect_containing_function): Declare.

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

	* gdb.opt/inline-break.exp (line number, address): Add "info
	break" tests.
2018-06-29 19:37:20 +01:00

382 lines
10 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* Get info from stack frames; convert between frames, blocks,
functions and pc values.
Copyright (C) 1986-2018 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "defs.h"
#include "symtab.h"
#include "bfd.h"
#include "objfiles.h"
#include "frame.h"
#include "gdbcore.h"
#include "value.h"
#include "target.h"
#include "inferior.h"
#include "annotate.h"
#include "regcache.h"
#include "dummy-frame.h"
#include "command.h"
#include "gdbcmd.h"
#include "block.h"
#include "inline-frame.h"
/* Return the innermost lexical block in execution in a specified
stack frame. The frame address is assumed valid.
If ADDR_IN_BLOCK is non-zero, set *ADDR_IN_BLOCK to the exact code
address we used to choose the block. We use this to find a source
line, to decide which macro definitions are in scope.
The value returned in *ADDR_IN_BLOCK isn't necessarily the frame's
PC, and may not really be a valid PC at all. For example, in the
caller of a function declared to never return, the code at the
return address will never be reached, so the call instruction may
be the very last instruction in the block. So the address we use
to choose the block is actually one byte before the return address
--- hopefully pointing us at the call instruction, or its delay
slot instruction. */
const struct block *
get_frame_block (struct frame_info *frame, CORE_ADDR *addr_in_block)
{
CORE_ADDR pc;
const struct block *bl;
int inline_count;
if (!get_frame_address_in_block_if_available (frame, &pc))
return NULL;
if (addr_in_block)
*addr_in_block = pc;
bl = block_for_pc (pc);
if (bl == NULL)
return NULL;
inline_count = frame_inlined_callees (frame);
while (inline_count > 0)
{
if (block_inlined_p (bl))
inline_count--;
bl = BLOCK_SUPERBLOCK (bl);
gdb_assert (bl != NULL);
}
return bl;
}
CORE_ADDR
get_pc_function_start (CORE_ADDR pc)
{
const struct block *bl;
struct bound_minimal_symbol msymbol;
bl = block_for_pc (pc);
if (bl)
{
struct symbol *symbol = block_linkage_function (bl);
if (symbol)
{
bl = SYMBOL_BLOCK_VALUE (symbol);
return BLOCK_START (bl);
}
}
msymbol = lookup_minimal_symbol_by_pc (pc);
if (msymbol.minsym)
{
CORE_ADDR fstart = BMSYMBOL_VALUE_ADDRESS (msymbol);
if (find_pc_section (fstart))
return fstart;
}
return 0;
}
/* Return the symbol for the function executing in frame FRAME. */
struct symbol *
get_frame_function (struct frame_info *frame)
{
const struct block *bl = get_frame_block (frame, 0);
if (bl == NULL)
return NULL;
while (BLOCK_FUNCTION (bl) == NULL && BLOCK_SUPERBLOCK (bl) != NULL)
bl = BLOCK_SUPERBLOCK (bl);
return BLOCK_FUNCTION (bl);
}
/* Return the function containing pc value PC in section SECTION.
Returns 0 if function is not known. */
struct symbol *
find_pc_sect_function (CORE_ADDR pc, struct obj_section *section)
{
const struct block *b = block_for_pc_sect (pc, section);
if (b == 0)
return 0;
return block_linkage_function (b);
}
/* Return the function containing pc value PC.
Returns 0 if function is not known.
Backward compatibility, no section */
struct symbol *
find_pc_function (CORE_ADDR pc)
{
return find_pc_sect_function (pc, find_pc_mapped_section (pc));
}
/* See symtab.h. */
struct symbol *
find_pc_sect_containing_function (CORE_ADDR pc, struct obj_section *section)
{
const block *bl = block_for_pc_sect (pc, section);
if (bl == nullptr)
return nullptr;
return block_containing_function (bl);
}
/* These variables are used to cache the most recent result
of find_pc_partial_function. */
static CORE_ADDR cache_pc_function_low = 0;
static CORE_ADDR cache_pc_function_high = 0;
static const char *cache_pc_function_name = 0;
static struct obj_section *cache_pc_function_section = NULL;
/* Clear cache, e.g. when symbol table is discarded. */
void
clear_pc_function_cache (void)
{
cache_pc_function_low = 0;
cache_pc_function_high = 0;
cache_pc_function_name = (char *) 0;
cache_pc_function_section = NULL;
}
/* Finds the "function" (text symbol) that is smaller than PC but
greatest of all of the potential text symbols in SECTION. Sets
*NAME and/or *ADDRESS conditionally if that pointer is non-null.
If ENDADDR is non-null, then set *ENDADDR to be the end of the
function (exclusive), but passing ENDADDR as non-null means that
the function might cause symbols to be read. This function either
succeeds or fails (not halfway succeeds). If it succeeds, it sets
*NAME, *ADDRESS, and *ENDADDR to real information and returns 1.
If it fails, it sets *NAME, *ADDRESS and *ENDADDR to zero and
returns 0. */
/* Backward compatibility, no section argument. */
int
find_pc_partial_function (CORE_ADDR pc, const char **name, CORE_ADDR *address,
CORE_ADDR *endaddr)
{
struct obj_section *section;
struct symbol *f;
struct bound_minimal_symbol msymbol;
struct compunit_symtab *compunit_symtab = NULL;
struct objfile *objfile;
CORE_ADDR mapped_pc;
/* To ensure that the symbol returned belongs to the correct setion
(and that the last [random] symbol from the previous section
isn't returned) try to find the section containing PC. First try
the overlay code (which by default returns NULL); and second try
the normal section code (which almost always succeeds). */
section = find_pc_overlay (pc);
if (section == NULL)
section = find_pc_section (pc);
mapped_pc = overlay_mapped_address (pc, section);
if (mapped_pc >= cache_pc_function_low
&& mapped_pc < cache_pc_function_high
&& section == cache_pc_function_section)
goto return_cached_value;
msymbol = lookup_minimal_symbol_by_pc_section (mapped_pc, section);
ALL_OBJFILES (objfile)
{
if (objfile->sf)
{
compunit_symtab
= objfile->sf->qf->find_pc_sect_compunit_symtab (objfile, msymbol,
mapped_pc, section,
0);
}
if (compunit_symtab != NULL)
break;
}
if (compunit_symtab != NULL)
{
/* Checking whether the msymbol has a larger value is for the
"pathological" case mentioned in print_frame_info. */
f = find_pc_sect_function (mapped_pc, section);
if (f != NULL
&& (msymbol.minsym == NULL
|| (BLOCK_START (SYMBOL_BLOCK_VALUE (f))
>= BMSYMBOL_VALUE_ADDRESS (msymbol))))
{
cache_pc_function_low = BLOCK_START (SYMBOL_BLOCK_VALUE (f));
cache_pc_function_high = BLOCK_END (SYMBOL_BLOCK_VALUE (f));
cache_pc_function_name = SYMBOL_LINKAGE_NAME (f);
cache_pc_function_section = section;
goto return_cached_value;
}
}
/* Not in the normal symbol tables, see if the pc is in a known
section. If it's not, then give up. This ensures that anything
beyond the end of the text seg doesn't appear to be part of the
last function in the text segment. */
if (!section)
msymbol.minsym = NULL;
/* Must be in the minimal symbol table. */
if (msymbol.minsym == NULL)
{
/* No available symbol. */
if (name != NULL)
*name = 0;
if (address != NULL)
*address = 0;
if (endaddr != NULL)
*endaddr = 0;
return 0;
}
cache_pc_function_low = BMSYMBOL_VALUE_ADDRESS (msymbol);
cache_pc_function_name = MSYMBOL_LINKAGE_NAME (msymbol.minsym);
cache_pc_function_section = section;
cache_pc_function_high = minimal_symbol_upper_bound (msymbol);
return_cached_value:
if (address)
{
if (pc_in_unmapped_range (pc, section))
*address = overlay_unmapped_address (cache_pc_function_low, section);
else
*address = cache_pc_function_low;
}
if (name)
*name = cache_pc_function_name;
if (endaddr)
{
if (pc_in_unmapped_range (pc, section))
{
/* Because the high address is actually beyond the end of
the function (and therefore possibly beyond the end of
the overlay), we must actually convert (high - 1) and
then add one to that. */
*endaddr = 1 + overlay_unmapped_address (cache_pc_function_high - 1,
section);
}
else
*endaddr = cache_pc_function_high;
}
return 1;
}
/* See symtab.h. */
struct type *
find_function_type (CORE_ADDR pc)
{
struct symbol *sym = find_pc_function (pc);
if (sym != NULL && BLOCK_START (SYMBOL_BLOCK_VALUE (sym)) == pc)
return SYMBOL_TYPE (sym);
return NULL;
}
/* See symtab.h. */
struct type *
find_gnu_ifunc_target_type (CORE_ADDR resolver_funaddr)
{
struct type *resolver_type = find_function_type (resolver_funaddr);
if (resolver_type != NULL)
{
/* Get the return type of the resolver. */
struct type *resolver_ret_type
= check_typedef (TYPE_TARGET_TYPE (resolver_type));
/* If we found a pointer to function, then the resolved type
is the type of the pointed-to function. */
if (TYPE_CODE (resolver_ret_type) == TYPE_CODE_PTR)
{
struct type *resolved_type
= TYPE_TARGET_TYPE (resolver_ret_type);
if (TYPE_CODE (check_typedef (resolved_type)) == TYPE_CODE_FUNC)
return resolved_type;
}
}
return NULL;
}
/* Return the innermost stack frame that is executing inside of BLOCK and is
at least as old as the selected frame. Return NULL if there is no
such frame. If BLOCK is NULL, just return NULL. */
struct frame_info *
block_innermost_frame (const struct block *block)
{
struct frame_info *frame;
if (block == NULL)
return NULL;
frame = get_selected_frame_if_set ();
if (frame == NULL)
frame = get_current_frame ();
while (frame != NULL)
{
const struct block *frame_block = get_frame_block (frame, NULL);
if (frame_block != NULL && contained_in (frame_block, block))
return frame;
frame = get_prev_frame (frame);
}
return NULL;
}