Hi Dave The following patch is a consolidated cleanup and minor fixes attempt. Specifically it does the following: 1. Saves register values(rip, rsp, rbp) got from the exception frame. These are used to unwind the process stack. Added a 'bptr' field in the bt_info structure to save the rbp value from the eframe. 2. Added checks for offset being zero while resolving the text address to a symbol name. 3. Added dwarf_print_stack_entry() as a parallel to x86_print_stack_entry(). Could probably move the offset checking routine as a separate function. Would save us some lines of code. Pushed that for later. 4. Fixed 'levels' in the backtrace output. Thanks Rachita Signed-off-by: Rachita Kothiyal <rachita@xxxxxxxxxx> --- defs.h | 3 unwind_x86_32_64.c | 77 ++++++++++++++++++++++--- x86_64.c | 163 ++++++----------------------------------------------- 3 files changed, 91 insertions(+), 152 deletions(-) diff -puN x86_64.c~cfi_backtrace_minor_fixes x86_64.c --- crash-4.0-3.9/x86_64.c~cfi_backtrace_minor_fixes 2006-11-15 18:29:04.848359480 +0530 +++ crash-4.0-3.9-rachita/x86_64.c 2006-11-15 19:00:40.687148176 +0530 @@ -2548,6 +2548,7 @@ x86_64_dwarf_back_trace_cmd(struct bt_in irq_eframe = 0; last_process_stack_eframe = 0; bt->call_target = NULL; + bt->bptr = 0; rsp = bt->stkptr; if (!rsp) { error(INFO, "cannot determine starting stack pointer\n"); @@ -2617,31 +2618,9 @@ in_exception_stack: stacktop = bt->stacktop - SIZE(pt_regs); - if ((kt->flags & DWARF_UNWIND) && !done) - done = dwarf_backtrace(bt, stacktop); - - for (i = (rsp - bt->stackbase)/sizeof(ulong); - !done && (rsp < stacktop); i++, rsp += sizeof(ulong)) { - - up = (ulong *)(&bt->stackbuf[i*sizeof(ulong)]); - - if (!is_kernel_text(*up)) - continue; - - switch (x86_64_print_stack_entry(bt, ofp, level, i,*up)) - { - case BACKTRACE_ENTRY_AND_EFRAME_DISPLAYED: - rsp += SIZE(pt_regs); - i += SIZE(pt_regs)/sizeof(ulong); - case BACKTRACE_ENTRY_DISPLAYED: - level++; - break; - case BACKTRACE_ENTRY_IGNORED: - break; - case BACKTRACE_COMPLETE: - done = TRUE; - break; - } + if ((kt->flags & DWARF_UNWIND) && !done) { + level = dwarf_backtrace(bt, level, stacktop); + done = TRUE; } cs = x86_64_exception_frame(EFRAME_PRINT|EFRAME_CS, 0, @@ -2702,32 +2681,10 @@ in_exception_stack: stacktop = bt->stacktop - 64; /* from kernel code */ - if ((kt->flags & DWARF_UNWIND) && !done) - done = dwarf_backtrace(bt, stacktop); - - for (i = (rsp - bt->stackbase)/sizeof(ulong); - !done && (rsp < stacktop); i++, rsp += sizeof(ulong)) { - - up = (ulong *)(&bt->stackbuf[i*sizeof(ulong)]); - - if (!is_kernel_text(*up)) - continue; - - switch (x86_64_print_stack_entry(bt, ofp, level, i,*up)) - { - case BACKTRACE_ENTRY_AND_EFRAME_DISPLAYED: - rsp += SIZE(pt_regs); - i += SIZE(pt_regs)/sizeof(ulong); - case BACKTRACE_ENTRY_DISPLAYED: - level++; - break; - case BACKTRACE_ENTRY_IGNORED: - break; - case BACKTRACE_COMPLETE: - done = TRUE; - break; - } - } + if ((kt->flags & DWARF_UNWIND) && !done) { + level = dwarf_backtrace(bt, level, stacktop); + done = TRUE; + } if (!BT_REFERENCE_CHECK(bt)) fprintf(fp, "--- <IRQ stack> ---\n"); @@ -2792,21 +2749,6 @@ in_exception_stack: } /* - * For a normally blocked task, hand-create the first level. - */ - if (!done && !(kt->flags & DWARF_UNWIND) && - !(bt->flags & (BT_TEXT_SYMBOLS|BT_EXCEPTION_STACK|BT_IRQSTACK)) && - STREQ(closest_symbol(bt->instptr), "thread_return")) { - bt->flags |= BT_SCHEDULE; - i = (rsp - bt->stackbase)/sizeof(ulong); - x86_64_print_stack_entry(bt, ofp, level, - i, bt->instptr); - bt->flags &= ~(ulonglong)BT_SCHEDULE; - rsp += sizeof(ulong); - level++; - } - - /* * Dump the IRQ exception frame from the process stack. * If the CS register indicates a user exception frame, * then set done to TRUE to avoid the process stack walk-through. @@ -2814,8 +2756,7 @@ in_exception_stack: */ if (irq_eframe) { bt->flags |= BT_EXCEPTION_FRAME; - i = (irq_eframe - bt->stackbase)/sizeof(ulong); - x86_64_print_stack_entry(bt, ofp, level, i, bt->instptr); + level = dwarf_print_stack_entry(bt, level); bt->flags &= ~(ulonglong)BT_EXCEPTION_FRAME; cs = x86_64_exception_frame(EFRAME_PRINT|EFRAME_CS, 0, bt->stackbuf + (irq_eframe - bt->stackbase), bt, ofp); @@ -2833,81 +2774,10 @@ in_exception_stack: /* * Walk the process stack. */ - if ((kt->flags & DWARF_UNWIND) && !done) - done = dwarf_backtrace(bt, bt->stacktop); - - for (i = (rsp - bt->stackbase)/sizeof(ulong); - !done && (rsp < bt->stacktop); i++, rsp += sizeof(ulong)) { - - up = (ulong *)(&bt->stackbuf[i*sizeof(ulong)]); - - if (!is_kernel_text(*up)) - continue; - - if ((bt->flags & BT_CHECK_CALLER)) { - /* - * A non-zero offset value from the value_search() - * lets us know if it's a real text return address. - */ - spt = value_search(*up, &offset); - /* - * sp gets the syment of the function that the text - * routine above called before leaving its return - * address on the stack -- if it can be determined. - */ - sp = x86_64_function_called_by((*up)-5); - - if (sp == NULL) { - /* - * We were unable to get the called function. - * If the text address had an offset, then - * it must have made an indirect call, and - * can't have called our target function. - */ - if (offset) { - if (CRASHDEBUG(1)) - fprintf(ofp, - "< ignoring %s() -- makes indirect call and NOT %s()>\n", - spt->name, - bt->call_target); - continue; - } - } else if ((machdep->flags & SCHED_TEXT) && - STREQ(bt->call_target, "schedule") && - STREQ(sp->name, "__sched_text_start")) { - ; /* bait and switch */ - } else if (!STREQ(sp->name, bt->call_target)) { - /* - * We got function called by the text routine, - * but it's not our target function. - */ - if (CRASHDEBUG(2)) - fprintf(ofp, - "< ignoring %s() -- calls %s() and NOT %s()>\n", - spt->name, sp->name, - bt->call_target); - continue; - } - } - - switch (x86_64_print_stack_entry(bt, ofp, level, i,*up)) - { - case BACKTRACE_ENTRY_AND_EFRAME_DISPLAYED: - last_process_stack_eframe = rsp + 8; - if (x86_64_print_eframe_location(last_process_stack_eframe, level, ofp)) - level++; - rsp += SIZE(pt_regs); - i += SIZE(pt_regs)/sizeof(ulong); - case BACKTRACE_ENTRY_DISPLAYED: - level++; - break; - case BACKTRACE_ENTRY_IGNORED: - break; - case BACKTRACE_COMPLETE: - done = TRUE; - break; - } - } + if ((kt->flags & DWARF_UNWIND) && !done) { + level = dwarf_backtrace(bt, level, bt->stacktop); + done = TRUE; + } if (!irq_eframe && !is_kernel_thread(bt->tc->task) && (GET_STACKBASE(bt->tc->task) == bt->stackbase)) { @@ -3193,6 +3063,13 @@ x86_64_exception_frame(ulong flags, ulon x86_64_do_bt_reference_check(bt, r15, NULL); } + /* Remember the rip and rsp for unwinding the process stack */ + if (kt->flags & DWARF_UNWIND){ + bt->instptr = rip; + bt->stkptr = rsp; + bt->bptr = rbp; + } + if (kvaddr) FREEBUF(pt_regs_buf); diff -puN unwind_x86_32_64.c~cfi_backtrace_minor_fixes unwind_x86_32_64.c --- crash-4.0-3.9/unwind_x86_32_64.c~cfi_backtrace_minor_fixes 2006-11-15 18:35:50.519688064 +0530 +++ crash-4.0-3.9-rachita/unwind_x86_32_64.c 2006-11-15 19:31:45.705622272 +0530 @@ -1036,9 +1036,8 @@ dump_local_unwind_tables(void) int -dwarf_backtrace(struct bt_info *bt, ulong stacktop) +dwarf_backtrace(struct bt_info *bt, int level, ulong stacktop) { - int n = 0; unsigned long bp, offset; struct syment *sp; char *name; @@ -1051,7 +1050,7 @@ dwarf_backtrace(struct bt_info *bt, ulon UNW_PC(frame) = bt->instptr; /* read rbp from stack for non active tasks */ - if (!(bt->flags & BT_DUMPFILE_SEARCH) ) { + if (!(bt->flags & BT_DUMPFILE_SEARCH) && !bt->bptr) { // readmem(frame->regs.rsp, KVADDR, &bp, readmem(UNW_SP(frame), KVADDR, &bp, sizeof(unsigned long), "reading bp", FAULT_ON_ERROR); @@ -1084,7 +1083,7 @@ dwarf_backtrace(struct bt_info *bt, ulon name = sp->name; - fprintf(fp, " #0 [%016lx] %s at %016lx \n", UNW_SP(frame), name, UNW_PC(frame)); + fprintf(fp, " #%d [%016lx] %s at %016lx \n", level, UNW_SP(frame), name, UNW_PC(frame)); if (CRASHDEBUG(2)) fprintf(fp, " < SP: %lx PC: %lx FP: %lx >\n", UNW_SP(frame), @@ -1092,7 +1091,12 @@ dwarf_backtrace(struct bt_info *bt, ulon while ((UNW_SP(frame) < stacktop) && !unwind(frame) && UNW_PC(frame)) { - n++; + /* To prevent rip pushed on IRQ stack being reported both + * both on the IRQ and process stacks + */ + if ((bt->flags & BT_IRQSTACK) && (UNW_SP(frame) >= stacktop - 16)) + break; + level++; sp = value_search(UNW_PC(frame), &offset); if (!sp) { if (CRASHDEBUG(1)) @@ -1101,9 +1105,24 @@ dwarf_backtrace(struct bt_info *bt, ulon UNW_PC(frame)); break; } + + /* + * If offset is zero, it means we have crossed over to the next + * function. Recalculate by adjusting the text address + */ + if (!offset) { + sp = value_search(UNW_PC(frame) - 1, &offset); + if (!sp) { + if (CRASHDEBUG(1)) + fprintf(fp, + "unwind: cannot find symbol for PC: %lx\n", + UNW_PC(frame)-1); + goto bailout; + } + } name = sp->name; - fprintf(fp, "%s#%d [%016lx] %s at %016lx \n", n < 10 ? " " : "", - n, UNW_SP(frame), name, UNW_PC(frame)); + fprintf(fp, "%s#%d [%016lx] %s at %016lx \n", level < 10 ? " " : "", + level, UNW_SP(frame), name, UNW_PC(frame)); if (CRASHDEBUG(2)) fprintf(fp, " < SP: %lx PC: %lx FP: %lx >\n", UNW_SP(frame), @@ -1112,7 +1131,49 @@ dwarf_backtrace(struct bt_info *bt, ulon bailout: FREEBUF(frame); - return TRUE; + return ++level; +} + +int dwarf_print_stack_entry(struct bt_info *bt, int level) +{ + int n = 0; + unsigned long offset; + struct syment *sp; + char *name; + struct unwind_frame_info *frame; + + frame = (struct unwind_frame_info *)GETBUF(sizeof(struct unwind_frame_info)); + UNW_SP(frame) = bt->stkptr; + UNW_PC(frame) = bt->instptr; + + sp = value_search(UNW_PC(frame), &offset); + if (!sp) { + if (CRASHDEBUG(1)) + fprintf(fp, "unwind: cannot find symbol for PC: %lx\n", + UNW_PC(frame)); + goto bailout; + } + + /* + * If offset is zero, it means we have crossed over to the next + * function. Recalculate by adjusting the text address + */ + if (!offset) { + sp = value_search(UNW_PC(frame) - 1, &offset); + if (!sp) { + if (CRASHDEBUG(1)) + fprintf(fp, + "unwind: cannot find symbol for PC: %lx\n", + UNW_PC(frame)-1); + goto bailout; + } + } + name = sp->name; + fprintf(fp, " #%d [%016lx] %s at %016lx \n", level, UNW_SP(frame), name, UNW_PC(frame)); + +bailout: + FREEBUF(frame); + return level; } void diff -puN defs.h~cfi_backtrace_minor_fixes defs.h --- crash-4.0-3.9/defs.h~cfi_backtrace_minor_fixes 2006-11-15 18:51:28.030164808 +0530 +++ crash-4.0-3.9-rachita/defs.h 2006-11-15 18:51:46.272391568 +0530 @@ -645,6 +645,7 @@ struct bt_info { ulonglong flags; ulong instptr; ulong stkptr; + ulong bptr; ulong stackbase; ulong stacktop; char *stackbuf; @@ -3626,7 +3627,7 @@ struct machine_specific { * unwind_x86_32_64.c */ void init_unwind_table(void); -int dwarf_backtrace(struct bt_info *, ulong); +int dwarf_backtrace(struct bt_info *, int, ulong); void dwarf_debug(struct bt_info *); #endif _ -- Crash-utility mailing list Crash-utility@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/crash-utility