#include "gdbcmd.h"
#include "symfile.h"
#include "objfiles.h"
-#include "xcoffsolib.h"
#include "arch-utils.h"
#include "bfd/libbfd.h" /* for bfd_default_set_arch_mach */
#define GET_SRC_REG(x) (((x) >> 21) & 0x1f)
+/* Limit the number of skipped non-prologue instructions, as the examining
+ of the prologue is expensive. */
+static int max_skip_non_prologue_insns = 10;
+
+/* Given PC representing the starting address of a function, and
+ LIM_PC which is the (sloppy) limit to which to scan when looking
+ for a prologue, attempt to further refine this limit by using
+ the line data in the symbol table. If successful, a better guess
+ on where the prologue ends is returned, otherwise the previous
+ value of lim_pc is returned. */
+static CORE_ADDR
+refine_prologue_limit (CORE_ADDR pc, CORE_ADDR lim_pc)
+{
+ struct symtab_and_line prologue_sal;
+
+ prologue_sal = find_pc_line (pc, 0);
+ if (prologue_sal.line != 0)
+ {
+ int i;
+ CORE_ADDR addr = prologue_sal.end;
+
+ /* Handle the case in which compiler's optimizer/scheduler
+ has moved instructions into the prologue. We scan ahead
+ in the function looking for address ranges whose corresponding
+ line number is less than or equal to the first one that we
+ found for the function. (It can be less than when the
+ scheduler puts a body instruction before the first prologue
+ instruction.) */
+ for (i = 2 * max_skip_non_prologue_insns;
+ i > 0 && (lim_pc == 0 || addr < lim_pc);
+ i--)
+ {
+ struct symtab_and_line sal;
+
+ sal = find_pc_line (addr, 0);
+ if (sal.line == 0)
+ break;
+ if (sal.line <= prologue_sal.line
+ && sal.symtab == prologue_sal.symtab)
+ {
+ prologue_sal = sal;
+ }
+ addr = sal.end;
+ }
+
+ if (lim_pc == 0 || prologue_sal.end < lim_pc)
+ lim_pc = prologue_sal.end;
+ }
+ return lim_pc;
+}
+
+
static CORE_ADDR
skip_prologue (CORE_ADDR pc, CORE_ADDR lim_pc, struct rs6000_framedata *fdata)
{
CORE_ADDR orig_pc = pc;
- CORE_ADDR last_prologue_pc;
+ CORE_ADDR last_prologue_pc = pc;
char buf[4];
unsigned long op;
long offset = 0;
int framep = 0;
int minimal_toc_loaded = 0;
int prev_insn_was_prologue_insn = 1;
+ int num_skip_non_prologue_insns = 0;
+
+ /* Attempt to find the end of the prologue when no limit is specified.
+ Note that refine_prologue_limit() has been written so that it may
+ be used to "refine" the limits of non-zero PC values too, but this
+ is only safe if we 1) trust the line information provided by the
+ compiler and 2) iterate enough to actually find the end of the
+ prologue.
+
+ It may become a good idea at some point (for both performance and
+ accuracy) to unconditionally call refine_prologue_limit(). But,
+ until we can make a clear determination that this is beneficial,
+ we'll play it safe and only use it to obtain a limit when none
+ has been specified. */
+ if (lim_pc == 0)
+ lim_pc = refine_prologue_limit (pc, lim_pc);
memset (fdata, 0, sizeof (struct rs6000_framedata));
fdata->saved_gpr = -1;
fdata->frameless = 1;
fdata->nosavedpc = 1;
- pc -= 4;
- while (lim_pc == 0 || pc < lim_pc - 4)
+ for (;; pc += 4)
{
- pc += 4;
-
/* Sometimes it isn't clear if an instruction is a prologue
instruction or not. When we encounter one of these ambiguous
cases, we'll set prev_insn_was_prologue_insn to 0 (false).
Otherwise, we'll assume that it really is a prologue instruction. */
if (prev_insn_was_prologue_insn)
last_prologue_pc = pc;
+
+ /* Stop scanning if we've hit the limit. */
+ if (lim_pc != 0 && pc >= lim_pc)
+ break;
+
prev_insn_was_prologue_insn = 1;
+ /* Fetch the instruction and convert it to an integer. */
if (target_read_memory (pc, buf, 4))
break;
op = extract_signed_integer (buf, 4);
}
else
{
- break;
+ /* Not a recognized prologue instruction.
+ Handle optimizer code motions into the prologue by continuing
+ the search if we have no valid frame yet or if the return
+ address is not yet saved in the frame. */
+ if (fdata->frameless == 0
+ && (lr_reg == -1 || fdata->nosavedpc == 0))
+ break;
+
+ if (op == 0x4e800020 /* blr */
+ || op == 0x4e800420) /* bctr */
+ /* Do not scan past epilogue in frameless functions or
+ trampolines. */
+ break;
+ if ((op & 0xf4000000) == 0x40000000) /* bxx */
+ /* Never skip branches. */
+ break;
+
+ if (num_skip_non_prologue_insns++ > max_skip_non_prologue_insns)
+ /* Do not scan too many insns, scanning insns is expensive with
+ remote targets. */
+ break;
+
+ /* Continue scanning. */
+ prev_insn_was_prologue_insn = 0;
+ continue;
}
}
a function pointer would require allocation of a TOC entry in the
inferior's memory space, with all its drawbacks. To be able to
call C++ virtual methods in the inferior (which are called via
- function pointers), find_function_addr uses this macro to get the
+ function pointers), find_function_addr uses this function to get the
function address from a function pointer. */
-/* Return nonzero if ADDR (a function pointer) is in the data space and
- is therefore a special function pointer. */
+/* Return real function address if ADDR (a function pointer) is in the data
+ space and is therefore a special function pointer. */
CORE_ADDR
rs6000_convert_from_func_ptr_addr (CORE_ADDR addr)
set_gdbarch_frame_init_saved_regs (gdbarch, rs6000_frame_init_saved_regs);
set_gdbarch_init_extra_frame_info (gdbarch, rs6000_init_extra_frame_info);
+
+ /* Handle RS/6000 function pointers. */
+ set_gdbarch_convert_from_func_ptr_addr (gdbarch,
+ rs6000_convert_from_func_ptr_addr);
}
set_gdbarch_frame_args_address (gdbarch, rs6000_frame_args_address);
set_gdbarch_frame_locals_address (gdbarch, rs6000_frame_args_address);