From: Franck Bui-Huu <vagabon.xyz@gmail.com>
To: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
Cc: linux-mips@linux-mips.org, ralf@linux-mips.org, vagabon.xyz@gmail.com
Subject: Re: [PATCH] dump_stack() based on prologue code analysis (take 2)
Date: Mon, 31 Jul 2006 10:59:03 +0200 [thread overview]
Message-ID: <44CDC657.9090403@innova-card.com> (raw)
In-Reply-To: <20060729.232720.108740310.anemo@mba.ocn.ne.jp>
Atsushi Nemoto wrote:
>
> Subject: [PATCH] dump_stack() based on prologue code analysis
>
> Instead of dump all possible address in the stack, unwind the stack
> frame based on prologue code analysis, as like as get_wchan() does.
> While the code analysis might fail for some reason, there is a new
> kernel option "raw_show_trace" to disable this feature.
>
my comments included with this patch...(you can find the plain patch
at the end of this email)
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index 8709a46..3bb4d47 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -365,15 +365,15 @@ #else
mfinfo[0].func = schedule;
schedule_frame = &mfinfo[0];
#endif
- for (i = 0; i < ARRAY_SIZE(mfinfo) && mfinfo[i].func; i++) {
- struct mips_frame_info *info = &mfinfo[i];
- if (get_frame_info(info)) {
- /* leaf or unknown */
- if (info->func == schedule)
- printk("Can't analyze prologue code at %p\n",
- info->func);
- }
- }
+ for (i = 0; i < ARRAY_SIZE(mfinfo) && mfinfo[i].func; i++)
+ get_frame_info(mfinfo + i);
+
+ /*
+ * Without schedule() frame info, result given by
+ * thread_saved_pc() and get_wchan() are not reliable.
+ */
+ if (schedule_frame->pc_offset < 0)
+ printk("Can't analyze schedule() prologue at %p\n", schedule);
>>>>>>>>>>>>>
I just put the test out of the loop and add a comment.
<<<<<<<<<<<<<
mfinfo_num = i;
return 0;
@@ -446,14 +446,15 @@ #endif
#ifdef CONFIG_KALLSYMS
/* used by show_frametrace() */
-unsigned long unwind_stack(struct task_struct *task,
- unsigned long **sp, unsigned long pc)
+unsigned long unwind_stack(struct task_struct *task, unsigned long **sp,
+ unsigned long pc, struct pt_regs *regs)
{
unsigned long stack_page;
struct mips_frame_info info;
char *modname;
char namebuf[KSYM_NAME_LEN + 1];
unsigned long size, ofs;
+ int rv;
stack_page = (unsigned long)task_stack_page(task);
if (!stack_page)
@@ -466,18 +467,21 @@ unsigned long unwind_stack(struct task_s
info.func = (void *)(pc - ofs);
info.func_size = ofs; /* analyze from start to ofs */
- if (get_frame_info(&info)) {
- /* leaf or unknown */
- *sp += info.frame_size / sizeof(long);
+ rv = get_frame_info(&info);
+ if (rv < 0)
return 0;
- }
+
if ((unsigned long)*sp < stack_page ||
(unsigned long)*sp + info.frame_size / sizeof(long) >
stack_page + THREAD_SIZE - 32)
return 0;
- pc = (*sp)[info.pc_offset];
+ if (rv) /* leaf */
+ pc = regs->regs[31];
+ else /* nested */
+ pc = (*sp)[info.pc_offset];
+
*sp += info.frame_size / sizeof(long);
- return pc;
+ return __kernel_text_address(pc) ? pc : 0;
>>>>>>>>>>>>>
I pass regs to unwind_stack(), that simplify the caller because
it needn't to deal with leaf or nested case. Simply test for pc
is 0.
<<<<<<<<<<<<<
}
#endif
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index 7aa9dfc..bbd1cf9 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -73,13 +73,8 @@ void (*board_nmi_handler_setup)(void);
void (*board_ejtag_handler_setup)(void);
void (*board_bind_eic_interrupt)(int irq, int regset);
-/*
- * These constant is for searching for possible module text segments.
- * MODULE_RANGE is a guess of how much space is likely to be vmalloced.
- */
-#define MODULE_RANGE (8*1024*1024)
>>>>>>>>>>>>>
seems to be unused now...
<<<<<<<<<<<<<
-static void show_trace(unsigned long *stack)
+static void show_trace(unsigned long *sp)
{
const int field = 2 * sizeof(unsigned long);
unsigned long addr;
@@ -88,8 +83,8 @@ static void show_trace(unsigned long *st
#ifdef CONFIG_KALLSYMS
printk("\n");
#endif
- while (!kstack_end(stack)) {
- addr = *stack++;
+ while (!kstack_end(sp)) {
+ addr = *sp++;
>>>>>>>>>>>>>
now show_trace calls sp sp. (nothing is too late)
<<<<<<<<<<<<<
if (__kernel_text_address(addr)) {
printk(" [<%0*lx>] ", field, addr);
print_symbol("%s\n", addr);
@@ -107,32 +102,27 @@ static int __init set_raw_show_trace(cha
}
__setup("raw_show_trace", set_raw_show_trace);
-extern unsigned long unwind_stack(struct task_struct *task,
- unsigned long **sp, unsigned long pc);
-static void show_frametrace(struct task_struct *task, struct pt_regs *regs)
+extern unsigned long unwind_stack(struct task_struct *task, unsigned long **sp,
+ unsigned long pc, struct pt_regs *regs);
+
+static void show_backtrace(struct task_struct *task, struct pt_regs *regs)
>>>>>>>>>>>>>
Just renamed show_stacktrace() into show_backtrace(). I think we
usually use the latter no ?
<<<<<<<<<<<<<
{
- const int field = 2 * sizeof(unsigned long);
- unsigned long *stack = (long *)regs->regs[29];
+ unsigned long *sp = (long *)regs->regs[29];
unsigned long pc = regs->cp0_epc;
- int top = 1;
if (raw_show_trace || !__kernel_text_address(pc)) {
- show_trace(stack);
+ show_trace(sp);
return;
}
printk("Call Trace:\n");
- while (__kernel_text_address(pc)) {
- printk(" [<%0*lx>] ", field, pc);
+ do {
+ printk(" [<%0*lx>] ", 2*sizeof(unsigned long), pc);
print_symbol("%s\n", pc);
- pc = unwind_stack(task, &stack, pc);
- if (top && pc == 0)
- pc = regs->regs[31]; /* leaf? */
- top = 0;
- }
+ } while ((pc = unwind_stack(task, &sp, pc, regs)));
>>>>>>>>>>>>>
Now don't deal with leaf case since unwind_stack() does it for us.
<<<<<<<<<<<<<
printk("\n");
}
#else
-#define show_frametrace(task, r) show_trace((long *)(r)->regs[29]);
+#define show_backtrace(task, r) show_trace((long *)(r)->regs[29]);
#endif
/*
@@ -165,7 +155,7 @@ static void show_stacktrace(struct task_
i++;
}
printk("\n");
- show_frametrace(task, regs);
+ show_backtrace(task, regs);
}
static noinline void prepare_frametrace(struct pt_regs *regs)
@@ -216,7 +206,7 @@ #ifdef CONFIG_KALLSYMS
if (!raw_show_trace) {
struct pt_regs regs;
prepare_frametrace(®s);
- show_frametrace(current, ®s);
+ show_backtrace(current, ®s);
return;
}
#endif
Here is the plain patch.
-- >8 --
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index 8709a46..3bb4d47 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -365,15 +365,15 @@ #else
mfinfo[0].func = schedule;
schedule_frame = &mfinfo[0];
#endif
- for (i = 0; i < ARRAY_SIZE(mfinfo) && mfinfo[i].func; i++) {
- struct mips_frame_info *info = &mfinfo[i];
- if (get_frame_info(info)) {
- /* leaf or unknown */
- if (info->func == schedule)
- printk("Can't analyze prologue code at %p\n",
- info->func);
- }
- }
+ for (i = 0; i < ARRAY_SIZE(mfinfo) && mfinfo[i].func; i++)
+ get_frame_info(mfinfo + i);
+
+ /*
+ * Without schedule() frame info, result given by
+ * thread_saved_pc() and get_wchan() are not reliable.
+ */
+ if (schedule_frame->pc_offset < 0)
+ printk("Can't analyze schedule() prologue at %p\n", schedule);
mfinfo_num = i;
return 0;
@@ -446,14 +446,15 @@ #endif
#ifdef CONFIG_KALLSYMS
/* used by show_frametrace() */
-unsigned long unwind_stack(struct task_struct *task,
- unsigned long **sp, unsigned long pc)
+unsigned long unwind_stack(struct task_struct *task, unsigned long **sp,
+ unsigned long pc, struct pt_regs *regs)
{
unsigned long stack_page;
struct mips_frame_info info;
char *modname;
char namebuf[KSYM_NAME_LEN + 1];
unsigned long size, ofs;
+ int rv;
stack_page = (unsigned long)task_stack_page(task);
if (!stack_page)
@@ -466,18 +467,21 @@ unsigned long unwind_stack(struct task_s
info.func = (void *)(pc - ofs);
info.func_size = ofs; /* analyze from start to ofs */
- if (get_frame_info(&info)) {
- /* leaf or unknown */
- *sp += info.frame_size / sizeof(long);
+ rv = get_frame_info(&info);
+ if (rv < 0)
return 0;
- }
+
if ((unsigned long)*sp < stack_page ||
(unsigned long)*sp + info.frame_size / sizeof(long) >
stack_page + THREAD_SIZE - 32)
return 0;
- pc = (*sp)[info.pc_offset];
+ if (rv) /* leaf */
+ pc = regs->regs[31];
+ else /* nested */
+ pc = (*sp)[info.pc_offset];
+
*sp += info.frame_size / sizeof(long);
- return pc;
+ return __kernel_text_address(pc) ? pc : 0;
}
#endif
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index 7aa9dfc..bbd1cf9 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -73,13 +73,8 @@ void (*board_nmi_handler_setup)(void);
void (*board_ejtag_handler_setup)(void);
void (*board_bind_eic_interrupt)(int irq, int regset);
-/*
- * These constant is for searching for possible module text segments.
- * MODULE_RANGE is a guess of how much space is likely to be vmalloced.
- */
-#define MODULE_RANGE (8*1024*1024)
-static void show_trace(unsigned long *stack)
+static void show_trace(unsigned long *sp)
{
const int field = 2 * sizeof(unsigned long);
unsigned long addr;
@@ -88,8 +83,8 @@ static void show_trace(unsigned long *st
#ifdef CONFIG_KALLSYMS
printk("\n");
#endif
- while (!kstack_end(stack)) {
- addr = *stack++;
+ while (!kstack_end(sp)) {
+ addr = *sp++;
if (__kernel_text_address(addr)) {
printk(" [<%0*lx>] ", field, addr);
print_symbol("%s\n", addr);
@@ -107,32 +102,27 @@ static int __init set_raw_show_trace(cha
}
__setup("raw_show_trace", set_raw_show_trace);
-extern unsigned long unwind_stack(struct task_struct *task,
- unsigned long **sp, unsigned long pc);
-static void show_frametrace(struct task_struct *task, struct pt_regs *regs)
+extern unsigned long unwind_stack(struct task_struct *task, unsigned long **sp,
+ unsigned long pc, struct pt_regs *regs);
+
+static void show_backtrace(struct task_struct *task, struct pt_regs *regs)
{
- const int field = 2 * sizeof(unsigned long);
- unsigned long *stack = (long *)regs->regs[29];
+ unsigned long *sp = (long *)regs->regs[29];
unsigned long pc = regs->cp0_epc;
- int top = 1;
if (raw_show_trace || !__kernel_text_address(pc)) {
- show_trace(stack);
+ show_trace(sp);
return;
}
printk("Call Trace:\n");
- while (__kernel_text_address(pc)) {
- printk(" [<%0*lx>] ", field, pc);
+ do {
+ printk(" [<%0*lx>] ", 2*sizeof(unsigned long), pc);
print_symbol("%s\n", pc);
- pc = unwind_stack(task, &stack, pc);
- if (top && pc == 0)
- pc = regs->regs[31]; /* leaf? */
- top = 0;
- }
+ } while ((pc = unwind_stack(task, &sp, pc, regs)));
printk("\n");
}
#else
-#define show_frametrace(task, r) show_trace((long *)(r)->regs[29]);
+#define show_backtrace(task, r) show_trace((long *)(r)->regs[29]);
#endif
/*
@@ -165,7 +155,7 @@ static void show_stacktrace(struct task_
i++;
}
printk("\n");
- show_frametrace(task, regs);
+ show_backtrace(task, regs);
}
static noinline void prepare_frametrace(struct pt_regs *regs)
@@ -216,7 +206,7 @@ #ifdef CONFIG_KALLSYMS
if (!raw_show_trace) {
struct pt_regs regs;
prepare_frametrace(®s);
- show_frametrace(current, ®s);
+ show_backtrace(current, ®s);
return;
}
#endif
next prev parent reply other threads:[~2006-07-31 9:00 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2006-07-29 14:27 [PATCH] dump_stack() based on prologue code analysis (take 2) Atsushi Nemoto
2006-07-31 8:59 ` Franck Bui-Huu [this message]
2006-07-31 14:56 ` Atsushi Nemoto
2006-07-31 16:30 ` Franck Bui-Huu
2006-08-01 8:37 ` Franck Bui-Huu
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=44CDC657.9090403@innova-card.com \
--to=vagabon.xyz@gmail.com \
--cc=anemo@mba.ocn.ne.jp \
--cc=linux-mips@linux-mips.org \
--cc=ralf@linux-mips.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.