aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/ChangeLog5
-rw-r--r--gdb/blockframe.c99
-rw-r--r--gdb/symtab.h40
3 files changed, 121 insertions, 23 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 9dc0441..9d226c1 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -9,6 +9,11 @@
block.c (make_blockranges): New function.
* dwarf2read.c (dwarf2_record_block_ranges): Fill in BLOCK_RANGES
for block.
+ * symtab.h (find_pc_partial_function): Add new parameter `block'.
+ * blockframe.c (cache_pc_function_block): New static global.
+ (clear_pc_function_cache): Clear cache_pc_function_block.
+ (find_pc_partial_function): Move comment to symtab.h. Add
+ support for non-contiguous blocks.
2018-08-23 Xavier Roirand <roirand@adacore.com>
diff --git a/gdb/blockframe.c b/gdb/blockframe.c
index 6a018cc..6dc736e 100644
--- a/gdb/blockframe.c
+++ b/gdb/blockframe.c
@@ -165,13 +165,35 @@ find_pc_sect_containing_function (CORE_ADDR pc, struct obj_section *section)
return block_containing_function (bl);
}
-/* These variables are used to cache the most recent result
- of find_pc_partial_function. */
+/* These variables are used to cache the most recent result of
+ find_pc_partial_function.
+
+ The addresses cache_pc_function_low and cache_pc_function_high
+ record the range in which PC was found during the most recent
+ successful lookup. When the function occupies a single contiguous
+ address range, these values correspond to the low and high
+ addresses of the function. (The high address is actually one byte
+ beyond the last byte of the function.) For a function with more
+ than one (non-contiguous) range, the range in which PC was found is
+ used to set the cache bounds.
+
+ When determining whether or not these cached values apply to a
+ particular PC value, PC must be within the range specified by
+ cache_pc_function_low and cache_pc_function_high. In addition to
+ PC being in that range, cache_pc_section must also match PC's
+ section. See find_pc_partial_function() for details on both the
+ comparison as well as how PC's section is determined.
+
+ The other values aren't used for determining whether the cache
+ applies, but are used for setting the outputs from
+ find_pc_partial_function. cache_pc_function_low and
+ cache_pc_function_high are used to set outputs as well. */
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;
+static const struct block *cache_pc_function_block = nullptr;
/* Clear cache, e.g. when symbol table is discarded. */
@@ -182,24 +204,14 @@ clear_pc_function_cache (void)
cache_pc_function_high = 0;
cache_pc_function_name = (char *) 0;
cache_pc_function_section = NULL;
+ cache_pc_function_block = nullptr;
}
-/* 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. */
+/* See symtab.h. */
int
find_pc_partial_function (CORE_ADDR pc, const char **name, CORE_ADDR *address,
- CORE_ADDR *endaddr)
+ CORE_ADDR *endaddr, const struct block **block)
{
struct obj_section *section;
struct symbol *f;
@@ -241,17 +253,62 @@ find_pc_partial_function (CORE_ADDR pc, const char **name, CORE_ADDR *address,
if (compunit_symtab != NULL)
{
/* Checking whether the msymbol has a larger value is for the
- "pathological" case mentioned in print_frame_info. */
+ "pathological" case mentioned in stack.c:find_frame_funname.
+
+ We use BLOCK_ENTRY_PC instead of BLOCK_START_PC for this
+ comparison because the minimal symbol should refer to the
+ function's entry pc which is not necessarily the lowest
+ address of the function. This will happen when the function
+ has more than one range and the entry pc is not within the
+ lowest range of addresses. */
f = find_pc_sect_function (mapped_pc, section);
if (f != NULL
&& (msymbol.minsym == NULL
- || (BLOCK_START (SYMBOL_BLOCK_VALUE (f))
+ || (BLOCK_ENTRY_PC (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));
+ const struct block *b = SYMBOL_BLOCK_VALUE (f);
+
cache_pc_function_name = SYMBOL_LINKAGE_NAME (f);
cache_pc_function_section = section;
+ cache_pc_function_block = b;
+
+ /* For blocks occupying contiguous addresses (i.e. no gaps),
+ the low and high cache addresses are simply the start
+ and end of the block.
+
+ For blocks with non-contiguous ranges, we have to search
+ for the range containing mapped_pc and then use the start
+ and end of that range.
+
+ This causes the returned *ADDRESS and *ENDADDR values to
+ be limited to the range in which mapped_pc is found. See
+ comment preceding declaration of find_pc_partial_function
+ in symtab.h for more information. */
+
+ if (BLOCK_CONTIGUOUS_P (b))
+ {
+ cache_pc_function_low = BLOCK_START (b);
+ cache_pc_function_high = BLOCK_END (b);
+ }
+ else
+ {
+ int i;
+ for (i = 0; i < BLOCK_NRANGES (b); i++)
+ {
+ if (BLOCK_RANGE_START (b, i) <= mapped_pc
+ && mapped_pc < BLOCK_RANGE_END (b, i))
+ {
+ cache_pc_function_low = BLOCK_RANGE_START (b, i);
+ cache_pc_function_high = BLOCK_RANGE_END (b, i);
+ break;
+ }
+ }
+ /* Above loop should exit via the break. */
+ gdb_assert (i < BLOCK_NRANGES (b));
+ }
+
+
goto return_cached_value;
}
}
@@ -281,6 +338,7 @@ find_pc_partial_function (CORE_ADDR pc, const char **name, CORE_ADDR *address,
cache_pc_function_name = MSYMBOL_LINKAGE_NAME (msymbol.minsym);
cache_pc_function_section = section;
cache_pc_function_high = minimal_symbol_upper_bound (msymbol);
+ cache_pc_function_block = nullptr;
return_cached_value:
@@ -311,6 +369,9 @@ find_pc_partial_function (CORE_ADDR pc, const char **name, CORE_ADDR *address,
*endaddr = cache_pc_function_high;
}
+ if (block != nullptr)
+ *block = cache_pc_function_block;
+
return 1;
}
diff --git a/gdb/symtab.h b/gdb/symtab.h
index 0b155d0..746b5e6 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -1694,10 +1694,42 @@ extern struct symbol *find_pc_sect_containing_function
extern struct symbol *find_symbol_at_address (CORE_ADDR);
-/* lookup function from address, return name, start addr and end addr. */
-
-extern int find_pc_partial_function (CORE_ADDR, const char **, CORE_ADDR *,
- CORE_ADDR *);
+/* 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). If the optional parameter BLOCK is non-null,
+ then set *BLOCK to the address of the block corresponding to the
+ function symbol, if such a symbol could be found during the lookup;
+ nullptr is used as a return value for *BLOCK if no block is found.
+ 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.
+
+ If the function in question occupies non-contiguous ranges,
+ *ADDRESS and *ENDADDR are (subject to the conditions noted above) set
+ to the start and end of the range in which PC is found. Thus
+ *ADDRESS <= PC < *ENDADDR with no intervening gaps (in which ranges
+ from other functions might be found).
+
+ This property allows find_pc_partial_function to be used (as it had
+ been prior to the introduction of non-contiguous range support) by
+ various tdep files for finding a start address and limit address
+ for prologue analysis. This still isn't ideal, however, because we
+ probably shouldn't be doing prologue analysis (in which
+ instructions are scanned to determine frame size and stack layout)
+ for any range that doesn't contain the entry pc. Moreover, a good
+ argument can be made that prologue analysis ought to be performed
+ starting from the entry pc even when PC is within some other range.
+ 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. */
+
+extern int find_pc_partial_function (CORE_ADDR pc, const char **name,
+ CORE_ADDR *address, CORE_ADDR *endaddr,
+ const struct block **block = nullptr);
/* Return the type of a function with its first instruction exactly at
the PC address. Return NULL otherwise. */