From f826466772ae52f26152287fcb2259351de78f0f Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Thu, 13 Aug 2009 20:41:31 +0100 Subject: 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 Signed-off-by: Paul Mundt --- arch/sh/kernel/dwarf.c | 44 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 9 deletions(-) (limited to 'arch/sh/kernel') 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) { -- cgit v1.2.2