mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-27 20:14:06 +08:00
Introduce find_function_entry_range_from_pc and use it in infrun.c
An earlier version of this patch used the returned block in conjunction with BLOCK_ENTRY_PC to set stop_func_start in fill_in_stop_func() in infrun.c. While I think this was the correct thing to do, changes to find_inferior_partial_function could potentially end up with stop_func_end < stop_func_start, which is definitely wrong. For this case, we want to set both stop_func_start and stop_func_end to the start and end of the range containing the function's entry pc. I think that this functionality will be useful in many other places too - it probably ought to be used in all of the various prologue analyzers in GDB. The change to infrun.c was simple: the call to find_pc_partial_function was replaced with a call to find_function_entry_range_from_pc. The difference between these two functions is that find_pc_partial_entry_function will (potentially) return the start and end address corresponding to the range in which PC is found, but find_function_entry_range_from_pc will (again, potentially) return the start and end address of the range containing the entry pc. find_pc_partial_function has the property that *ADDRESS <= PC < *ENDADDR. This condition does not necessarily hold for the outputs of find_function_entry_range_from_pc. It should be noted that for functions which contain only a single range, the outputs of find_pc_partial_function and find_function_entry_range_from_pc are identical. I think it might happen that find_function_entry_range_from_pc will come to be used in place of many of the calls to find_pc_partial_function within GDB. Care must be taken in making this change, however, since some of this code depends on the *ADDRESS <= PC < *ENDADDR property. Finally, a note regarding the name: I had initially chosen a different name with a find_pc_partial_ prefix, but Simon suggested the current name citing the goal of eventually making naming consistent using the form find_X_from_Y. In this case X is "function_entry_range" and Y is "pc". Both the name and rationale made sense to me, so that's how it came to be. gdb/ChangeLog: * infrun.c (fill_in_stop_func): Use find_function_entry_range_from_pc in place of find_pc_partial_function. * blockframe.c (find_function_entry_range_from_pc): New function. * symtab.h (find_function_entry_range_from_pc): Declare and document.
This commit is contained in:
parent
2b1ffcfd6f
commit
59adbf5d03
@ -377,6 +377,43 @@ find_pc_partial_function (CORE_ADDR pc, const char **name, CORE_ADDR *address,
|
||||
|
||||
/* See symtab.h. */
|
||||
|
||||
bool
|
||||
find_function_entry_range_from_pc (CORE_ADDR pc, const char **name,
|
||||
CORE_ADDR *address, CORE_ADDR *endaddr)
|
||||
{
|
||||
const struct block *block;
|
||||
bool status = find_pc_partial_function (pc, name, address, endaddr, &block);
|
||||
|
||||
if (status && block != nullptr && !BLOCK_CONTIGUOUS_P (block))
|
||||
{
|
||||
CORE_ADDR entry_pc = BLOCK_ENTRY_PC (block);
|
||||
|
||||
for (int i = 0; i < BLOCK_NRANGES (block); i++)
|
||||
{
|
||||
if (BLOCK_RANGE_START (block, i) <= entry_pc
|
||||
&& entry_pc < BLOCK_RANGE_END (block, i))
|
||||
{
|
||||
if (address != nullptr)
|
||||
*address = BLOCK_RANGE_START (block, i);
|
||||
|
||||
if (endaddr != nullptr)
|
||||
*endaddr = BLOCK_RANGE_END (block, i);
|
||||
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
/* It's an internal error if we exit the above loop without finding
|
||||
the range. */
|
||||
internal_error (__FILE__, __LINE__,
|
||||
_("Entry block not found in find_function_entry_range_from_pc"));
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* See symtab.h. */
|
||||
|
||||
struct type *
|
||||
find_function_type (CORE_ADDR pc)
|
||||
{
|
||||
|
@ -4287,9 +4287,10 @@ fill_in_stop_func (struct gdbarch *gdbarch,
|
||||
{
|
||||
/* Don't care about return value; stop_func_start and stop_func_name
|
||||
will both be 0 if it doesn't work. */
|
||||
find_pc_partial_function (ecs->event_thread->suspend.stop_pc,
|
||||
&ecs->stop_func_name,
|
||||
&ecs->stop_func_start, &ecs->stop_func_end);
|
||||
find_function_entry_range_from_pc (ecs->event_thread->suspend.stop_pc,
|
||||
&ecs->stop_func_name,
|
||||
&ecs->stop_func_start,
|
||||
&ecs->stop_func_end);
|
||||
ecs->stop_func_start
|
||||
+= gdbarch_deprecated_function_start_offset (gdbarch);
|
||||
|
||||
|
21
gdb/symtab.h
21
gdb/symtab.h
@ -1725,12 +1725,31 @@ extern struct symbol *find_symbol_at_address (CORE_ADDR);
|
||||
This might suggest that *ADDRESS and *ENDADDR ought to be set to the
|
||||
limits of the entry pc range, but that will cause the
|
||||
*ADDRESS <= PC < *ENDADDR condition to be violated; many of the
|
||||
callers of find_pc_partial_function expect this condition to hold. */
|
||||
callers of find_pc_partial_function expect this condition to hold.
|
||||
|
||||
Callers which require the start and/or end addresses for the range
|
||||
containing the entry pc should instead call
|
||||
find_function_entry_range_from_pc. */
|
||||
|
||||
extern int find_pc_partial_function (CORE_ADDR pc, const char **name,
|
||||
CORE_ADDR *address, CORE_ADDR *endaddr,
|
||||
const struct block **block = nullptr);
|
||||
|
||||
/* Like find_pc_partial_function, above, but *ADDRESS and *ENDADDR are
|
||||
set to start and end addresses of the range containing the entry pc.
|
||||
|
||||
Note that it is not necessarily the case that (for non-NULL ADDRESS
|
||||
and ENDADDR arguments) the *ADDRESS <= PC < *ENDADDR condition will
|
||||
hold.
|
||||
|
||||
See comment for find_pc_partial_function, above, for further
|
||||
explanation. */
|
||||
|
||||
extern bool find_function_entry_range_from_pc (CORE_ADDR pc,
|
||||
const char **name,
|
||||
CORE_ADDR *address,
|
||||
CORE_ADDR *endaddr);
|
||||
|
||||
/* Return the type of a function with its first instruction exactly at
|
||||
the PC address. Return NULL otherwise. */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user