diff options
author | Matt Fleming <matt@console-pimps.org> | 2009-08-13 20:41:31 +0100 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2009-08-14 05:00:21 +0900 |
commit | f826466772ae52f26152287fcb2259351de78f0f (patch) | |
tree | 4129a61131b41009f9a183fb419e08beb0398260 /arch/sh/kernel/dwarf.c | |
parent | bf43a160ff2d67a21b076286bab6f5e2c993bd0a (diff) | |
download | lwn-f826466772ae52f26152287fcb2259351de78f0f.tar.gz lwn-f826466772ae52f26152287fcb2259351de78f0f.zip |
sh: Delete DWARF_ARCH_UNWIND_OFFSET
Trying to figure out the best value for DWARF_ARCH_UNWIND_OFFSET is
tricky at best. Various things can change the size (and offset from the
beginning of the function) of the prologue. Notably, turning on ftrace
adds calls to mcount at the beginning of functions, thereby pushing the
prologue further into the function.
So replace DWARF_ARCH_UNWIND_OFFSET with some code that continues to
execute CFA instructions until the value of return address register is
defined. This is safe to do because we know that the return address must
have been pushed onto the frame before our first function call; we just
can't figure out where at compile-time.
Signed-off-by: Matt Fleming <matt@console-pimps.org>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/sh/kernel/dwarf.c')
-rw-r--r-- | arch/sh/kernel/dwarf.c | 44 |
1 files changed, 35 insertions, 9 deletions
diff --git a/arch/sh/kernel/dwarf.c b/arch/sh/kernel/dwarf.c index 49d039f19426..83f3cc92549f 100644 --- a/arch/sh/kernel/dwarf.c +++ b/arch/sh/kernel/dwarf.c @@ -330,6 +330,7 @@ struct dwarf_fde *dwarf_lookup_fde(unsigned long pc) * @fde: the FDE for this function * @frame: the instructions calculate the CFA for this frame * @pc: the program counter of the address we're interested in + * @define_ra: keep executing insns until the return addr reg is defined? * * Execute the Call Frame instruction sequence starting at * @insn_start and ending at @insn_end. The instructions describe @@ -341,17 +342,36 @@ static int dwarf_cfa_execute_insns(unsigned char *insn_start, struct dwarf_cie *cie, struct dwarf_fde *fde, struct dwarf_frame *frame, - unsigned long pc) + unsigned long pc, + bool define_ra) { unsigned char insn; unsigned char *current_insn; unsigned int count, delta, reg, expr_len, offset; + bool seen_ra_reg; current_insn = insn_start; - while (current_insn < insn_end && frame->pc <= pc) { + /* + * If we're executing instructions for the dwarf_unwind_stack() + * FDE we need to keep executing instructions until the value of + * DWARF_ARCH_RA_REG is defined. See the comment in + * dwarf_unwind_stack() for more details. + */ + if (define_ra) + seen_ra_reg = false; + else + seen_ra_reg = true; + + while (current_insn < insn_end && (frame->pc <= pc || !seen_ra_reg) ) { insn = __raw_readb(current_insn++); + if (!seen_ra_reg) { + if (frame->num_regs >= DWARF_ARCH_RA_REG && + frame->regs[DWARF_ARCH_RA_REG].flags) + seen_ra_reg = true; + } + /* * Firstly, handle the opcodes that embed their operands * in the instructions. @@ -490,20 +510,25 @@ struct dwarf_frame *dwarf_unwind_stack(unsigned long pc, struct dwarf_fde *fde; unsigned long addr; int i, offset; + bool define_ra = false; /* * If this is the first invocation of this recursive function we * need get the contents of a physical register to get the CFA * in order to begin the virtual unwinding of the stack. * - * The constant DWARF_ARCH_UNWIND_OFFSET is added to the address of - * this function because the return address register - * (DWARF_ARCH_RA_REG) will probably not be initialised until a - * few instructions into the prologue. + * Setting "define_ra" to true indictates that we want + * dwarf_cfa_execute_insns() to continue executing instructions + * until we know how to calculate the value of DWARF_ARCH_RA_REG + * (which we need in order to kick off the whole unwinding + * process). + * + * NOTE: the return address is guaranteed to be setup by the + * time this function makes its first function call. */ if (!pc && !prev) { pc = (unsigned long)&dwarf_unwind_stack; - pc += DWARF_ARCH_UNWIND_OFFSET; + define_ra = true; } frame = kzalloc(sizeof(*frame), GFP_KERNEL); @@ -539,11 +564,12 @@ struct dwarf_frame *dwarf_unwind_stack(unsigned long pc, /* CIE initial instructions */ dwarf_cfa_execute_insns(cie->initial_instructions, - cie->instructions_end, cie, fde, frame, pc); + cie->instructions_end, cie, fde, + frame, pc, false); /* FDE instructions */ dwarf_cfa_execute_insns(fde->instructions, fde->end, cie, - fde, frame, pc); + fde, frame, pc, define_ra); /* Calculate the CFA */ switch (frame->flags) { |