Commit 65a1b880 authored by Kevin Buettner's avatar Kevin Buettner
Browse files

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.
parent 84b14f21
......@@ -50,6 +50,11 @@
* tracepoint.c (info_scope_command): Likewise.
* value.c (value_fn_field): Likewise.
* 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.
2018-08-24 Pedro Alves <palves@redhat.com>
Simon Marchi <simon.marchi@ericsson.com>
......
......@@ -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)
{
......
......@@ -4291,9 +4291,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);
......
......@@ -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. */
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment