aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh/kernel/dwarf.c
diff options
context:
space:
mode:
authorMatt Fleming <matt@console-pimps.org>2009-08-13 15:41:31 -0400
committerPaul Mundt <lethal@linux-sh.org>2009-08-13 16:00:21 -0400
commitf826466772ae52f26152287fcb2259351de78f0f (patch)
tree4129a61131b41009f9a183fb419e08beb0398260 /arch/sh/kernel/dwarf.c
parentbf43a160ff2d67a21b076286bab6f5e2c993bd0a (diff)
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.c44
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)
330 * @fde: the FDE for this function 330 * @fde: the FDE for this function
331 * @frame: the instructions calculate the CFA for this frame 331 * @frame: the instructions calculate the CFA for this frame
332 * @pc: the program counter of the address we're interested in 332 * @pc: the program counter of the address we're interested in
333 * @define_ra: keep executing insns until the return addr reg is defined?
333 * 334 *
334 * Execute the Call Frame instruction sequence starting at 335 * Execute the Call Frame instruction sequence starting at
335 * @insn_start and ending at @insn_end. The instructions describe 336 * @insn_start and ending at @insn_end. The instructions describe
@@ -341,17 +342,36 @@ static int dwarf_cfa_execute_insns(unsigned char *insn_start,
341 struct dwarf_cie *cie, 342 struct dwarf_cie *cie,
342 struct dwarf_fde *fde, 343 struct dwarf_fde *fde,
343 struct dwarf_frame *frame, 344 struct dwarf_frame *frame,
344 unsigned long pc) 345 unsigned long pc,
346 bool define_ra)
345{ 347{
346 unsigned char insn; 348 unsigned char insn;
347 unsigned char *current_insn; 349 unsigned char *current_insn;
348 unsigned int count, delta, reg, expr_len, offset; 350 unsigned int count, delta, reg, expr_len, offset;
351 bool seen_ra_reg;
349 352
350 current_insn = insn_start; 353 current_insn = insn_start;
351 354
352 while (current_insn < insn_end && frame->pc <= pc) { 355 /*
356 * If we're executing instructions for the dwarf_unwind_stack()
357 * FDE we need to keep executing instructions until the value of
358 * DWARF_ARCH_RA_REG is defined. See the comment in
359 * dwarf_unwind_stack() for more details.
360 */
361 if (define_ra)
362 seen_ra_reg = false;
363 else
364 seen_ra_reg = true;
365
366 while (current_insn < insn_end && (frame->pc <= pc || !seen_ra_reg) ) {
353 insn = __raw_readb(current_insn++); 367 insn = __raw_readb(current_insn++);
354 368
369 if (!seen_ra_reg) {
370 if (frame->num_regs >= DWARF_ARCH_RA_REG &&
371 frame->regs[DWARF_ARCH_RA_REG].flags)
372 seen_ra_reg = true;
373 }
374
355 /* 375 /*
356 * Firstly, handle the opcodes that embed their operands 376 * Firstly, handle the opcodes that embed their operands
357 * in the instructions. 377 * in the instructions.
@@ -490,20 +510,25 @@ struct dwarf_frame *dwarf_unwind_stack(unsigned long pc,
490 struct dwarf_fde *fde; 510 struct dwarf_fde *fde;
491 unsigned long addr; 511 unsigned long addr;
492 int i, offset; 512 int i, offset;
513 bool define_ra = false;
493 514
494 /* 515 /*
495 * If this is the first invocation of this recursive function we 516 * If this is the first invocation of this recursive function we
496 * need get the contents of a physical register to get the CFA 517 * need get the contents of a physical register to get the CFA
497 * in order to begin the virtual unwinding of the stack. 518 * in order to begin the virtual unwinding of the stack.
498 * 519 *
499 * The constant DWARF_ARCH_UNWIND_OFFSET is added to the address of 520 * Setting "define_ra" to true indictates that we want
500 * this function because the return address register 521 * dwarf_cfa_execute_insns() to continue executing instructions
501 * (DWARF_ARCH_RA_REG) will probably not be initialised until a 522 * until we know how to calculate the value of DWARF_ARCH_RA_REG
502 * few instructions into the prologue. 523 * (which we need in order to kick off the whole unwinding
524 * process).
525 *
526 * NOTE: the return address is guaranteed to be setup by the
527 * time this function makes its first function call.
503 */ 528 */
504 if (!pc && !prev) { 529 if (!pc && !prev) {
505 pc = (unsigned long)&dwarf_unwind_stack; 530 pc = (unsigned long)&dwarf_unwind_stack;
506 pc += DWARF_ARCH_UNWIND_OFFSET; 531 define_ra = true;
507 } 532 }
508 533
509 frame = kzalloc(sizeof(*frame), GFP_KERNEL); 534 frame = kzalloc(sizeof(*frame), GFP_KERNEL);
@@ -539,11 +564,12 @@ struct dwarf_frame *dwarf_unwind_stack(unsigned long pc,
539 564
540 /* CIE initial instructions */ 565 /* CIE initial instructions */
541 dwarf_cfa_execute_insns(cie->initial_instructions, 566 dwarf_cfa_execute_insns(cie->initial_instructions,
542 cie->instructions_end, cie, fde, frame, pc); 567 cie->instructions_end, cie, fde,
568 frame, pc, false);
543 569
544 /* FDE instructions */ 570 /* FDE instructions */
545 dwarf_cfa_execute_insns(fde->instructions, fde->end, cie, 571 dwarf_cfa_execute_insns(fde->instructions, fde->end, cie,
546 fde, frame, pc); 572 fde, frame, pc, define_ra);
547 573
548 /* Calculate the CFA */ 574 /* Calculate the CFA */
549 switch (frame->flags) { 575 switch (frame->flags) {