Hi DaveHi Rachita,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
RachitaSigned-off-by: Rachita Kothiyal <rachita@xxxxxxxxxx>
---
Great -- I'll tinker with this today and get out a new release ASAP.
One question re: this hanging thread:
> So, in other words, if we hardwire the user_regs_struct so that > it uses the NT_PRSTATUS registers all the time, then we get > the second (preferred/better) budget back trace when unwind > is off. > > That being the case, I argue for hardwiring them all the time. Yes, we can(should) do that for all the active tasks. Rachita
Correct me if I'm wrong here, but...
If, during machdep_init(POST_GBD), if we force-initialize
(hardwire when necessary) the relevant user_regs_struct items,
then we could change this line from:
if (((NETDUMP_DUMPFILE() || KDUMP_DUMPFILE())
&&
VALID_STRUCT(user_regs_struct)
&& (bt->task == tt->panic_task)) ||
(KDUMP_DUMPFILE()
&& (kt->flags & DWARF_UNWIND) &&
(bt->flags
& BT_DUMPFILE_SEARCH))) {
to:
if (((NETDUMP_DUMPFILE() || KDUMP_DUMPFILE())
&&
VALID_STRUCT(user_regs_struct)
&& (bt->task == tt->panic_task)) ||
(KDUMP_DUMPFILE()
&& (bt->flags & BT_DUMPFILE_SEARCH))) {
To be absolutely safe in a backwards-compatibility sense, perhaps
we should only do the hardwiring if it's a KDUMP_DUMPFILE().
Make sense?
Dave
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, ulonwhile ((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, ulonbailout:
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