sh: Try again at getting the initial return address for an unwind

The previous hack for calculating the return address for the first frame
we unwind (dwarf_unwinder_dump) didn't always work. The problem was that
it assumed once it read the rule for calculating the return address,
there would be no new rules for calculating it. This isn't true because
the way in which the CFA is calculated can change as you progress
through a function and the return address is figured out using the
CFA. Therefore, the way to calculate the return address can change.

So, instead of using some offset from the beginning of
dwarf_unwind_stack which is just a flakey approach, and instead of
executing instructions from the FDE until the return address is setup,
we now figure out the pc in dwarf_unwind_stack() just before we call
dwarf_cfa_execute_insns().

Signed-off-by: Matt Fleming <matt@console-pimps.org>
This commit is contained in:
Matt Fleming 2009-08-15 23:10:57 +01:00
parent 38f9ddf441
commit b955873bf5
1 changed files with 6 additions and 35 deletions

View File

@ -330,7 +330,6 @@ 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
@ -342,36 +341,17 @@ 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,
bool define_ra)
unsigned long pc)
{
unsigned char insn;
unsigned char *current_insn;
unsigned int count, delta, reg, expr_len, offset;
bool seen_ra_reg;
current_insn = insn_start;
/*
* 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) ) {
while (current_insn < insn_end && frame->pc <= pc) {
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.
@ -511,26 +491,17 @@ 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.
*
* 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;
define_ra = true;
}
if (!pc && !prev)
pc = (unsigned long)current_text_addr();
frame = kzalloc(sizeof(*frame), GFP_ATOMIC);
if (!frame)
@ -566,11 +537,11 @@ 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, false);
frame, pc);
/* FDE instructions */
dwarf_cfa_execute_insns(fde->instructions, fde->end, cie,
fde, frame, pc, define_ra);
fde, frame, pc);
/* Calculate the CFA */
switch (frame->flags) {