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
Subject: Re: [PATCH] dump_stack() based on prologue code analysis
Date: Thu, 27 Jul 2006 16:33:08 +0200 [thread overview]
Message-ID: <44C8CEA4.20000@innova-card.com> (raw)
In-Reply-To: <20060726.232231.59465336.anemo@mba.ocn.ne.jp>
Hi Atsushi ;)
Atsushi Nemoto wrote:
> Instead of dump all possible address in the stack, unwind the stack
> frame based on prologue code analysis, as like as get_chan() does.
> While the code analysis might fail for some reason, there is a new
> kernel option "raw_show_trace" to disable this feature.
>
> Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
>
> diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
> index 7ab67f7..8f1a5fe 100644
> --- a/arch/mips/kernel/process.c
> +++ b/arch/mips/kernel/process.c
> @@ -281,7 +281,7 @@ static struct mips_frame_info {
> } *schedule_frame, mfinfo[64];
> static int mfinfo_num;
>
> -static int __init get_frame_info(struct mips_frame_info *info)
> +static int get_frame_info(struct mips_frame_info *info)
> {
> int i;
> void *func = info->func;
> @@ -329,12 +329,6 @@ #endif
> ip->i_format.simmediate / sizeof(long);
> }
> }
> - if (info->pc_offset == -1 || info->frame_size == 0) {
> - if (func == schedule)
> - printk("Can't analyze prologue code at %p\n", func);
> - info->pc_offset = -1;
> - info->frame_size = 0;
> - }
>
> return 0;
> }
> @@ -367,8 +361,17 @@ #else
> mfinfo[0].func = schedule;
> schedule_frame = &mfinfo[0];
> #endif
> - for (i = 0; i < ARRAY_SIZE(mfinfo) && mfinfo[i].func; i++)
> - get_frame_info(&mfinfo[i]);
> + for (i = 0; i < ARRAY_SIZE(mfinfo) && mfinfo[i].func; i++) {
> + struct mips_frame_info *info = &mfinfo[i];
> + get_frame_info(info);
> + if (info->pc_offset < 0 || info->frame_size == 0) {
> + if (info->func == schedule)
This can't happen since "schedule" is not a leaf function. Something I'm
missing here but I would have said:
if (func != schedule)
instead, no ?
> + printk("Can't analyze prologue code at %p\n",
> + info->func);
> + info->pc_offset = -1;
> + info->frame_size = 0;
> + }
> + }
>
> mfinfo_num = i;
> return 0;
> @@ -437,3 +440,41 @@ #endif
> return pc;
> }
>
> +#ifdef CONFIG_KALLSYMS
> +/* used by show_frametrace() */
> +unsigned long unwind_stack(struct task_struct *task,
> + unsigned long **sp, unsigned long pc)
> +{
> + unsigned long stack_page;
> + struct mips_frame_info info;
> + char *modname;
> + char namebuf[KSYM_NAME_LEN + 1];
> + unsigned long size, ofs;
> +
> + stack_page = (unsigned long)task_stack_page(task);
> + if (!stack_page)
> + return 0;
> +
> + if (!kallsyms_lookup(pc, &size, &ofs, &modname, namebuf))
> + return 0;
> + if (ofs == 0)
> + return 0;
> +
> + info.func = (void *)(pc - ofs);
> + info.func_size = ofs; /* analyze from start to ofs */
> + get_frame_info(&info);
> + if (info.pc_offset < 0 || !info.frame_size) {
> + /* leaf? */
for leaf case, can't we simply do this test:
if (info.pc_offset < 0) {
IOW, can a leaf function move sp ? I would say yes...
BTW why not let this logic inside get_frame_info() ? Hence this function
could return:
if (info.frame_size && info.pc_offset > 0) /* nested */
return 0;
if (info.pc_offset < 0) /* leaf */
return 1;
/* prologue seems boggus... */
printk("Can't analyze prologue code at %p\n", info->func);
return -1;
> + *sp += info.frame_size / sizeof(long);
> + return 0;
why not returning:
return regs->regs[31];
and removes the leaf detection logic in show_frametrace() ?
> + }
> + 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];
> + *sp += info.frame_size / sizeof(long);
> + return pc;
why not directly doing:
return (*sp)[info.pc_offset];
and remove:
pc = (*sp)[info.pc_offset];
> +}
> +#endif
> diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
> index c6f7046..bf36fcc 100644
> --- a/arch/mips/kernel/traps.c
> +++ b/arch/mips/kernel/traps.c
> @@ -98,24 +98,53 @@ #endif
> printk("\n");
> }
>
> +#ifdef CONFIG_KALLSYMS
> +static int raw_show_trace;
> +static int __init set_raw_show_trace(char *str)
> +{
> + raw_show_trace = 1;
> + return 1;
> +}
> +__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)
> +{
> + const int field = 2 * sizeof(unsigned long);
> + unsigned long *stack = (long *)regs->regs[29];
why not calling that "sp" ?
> + unsigned long pc = regs->cp0_epc;
> + int top = 1;
> +
> + if (raw_show_trace || !__kernel_text_address(pc)) {
> + show_trace(stack);
> + return;
> + }
> + printk("Call Trace:\n");
> + while (__kernel_text_address(pc)) {
> + printk(" [<%0*lx>] ", field, pc);
> + print_symbol("%s\n", pc);
> + pc = unwind_stack(task, &stack, pc);
> + if (top && pc == 0)
> + pc = regs->regs[31]; /* leaf? */
> + top = 0;
> + }
> + printk("\n");
> +}
> +#else
> +#define show_frametrace(task, r) show_trace((long *)(r)->regs[29]);
> +#endif
> +
> /*
> * This routine abuses get_user()/put_user() to reference pointers
> * with at least a bit of error checking ...
> */
> -void show_stack(struct task_struct *task, unsigned long *sp)
> +static void show_stacktrace(struct task_struct *task, struct pt_regs *regs)
> {
> const int field = 2 * sizeof(unsigned long);
> long stackdata;
> int i;
> - unsigned long *stack;
> -
> - if (!sp) {
> - if (task && task != current)
> - sp = (unsigned long *) task->thread.reg29;
> - else
> - sp = (unsigned long *) &sp;
> - }
> - stack = sp;
> + unsigned long *sp = (unsigned long *)regs->regs[29];
>
> printk("Stack :");
> i = 0;
> @@ -136,7 +165,44 @@ void show_stack(struct task_struct *task
> i++;
> }
> printk("\n");
> - show_trace(stack);
> + show_frametrace(task, regs);
> +}
> +
> +static noinline void dump_stack_top(struct pt_regs *regs)
This sounds weird, you're actually dumping v0, ra, and sp, no ?
If so "dump_stack_top" seems not be appropriate, does it ?
> +{
> + __asm__ __volatile__(
> + "1: la $2, 1b\n\t"
> +#ifdef CONFIG_64BIT
> + "sd $2, %0\n\t"
> + "sd $29, %1\n\t"
> + "sd $31, %2\n\t"
> +#else
> + "sw $2, %0\n\t"
> + "sw $29, %1\n\t"
> + "sw $31, %2\n\t"
> +#endif
> + : "=m" (regs->cp0_epc),
> + "=m" (regs->regs[29]), "=m" (regs->regs[31])
> + : : "memory");
> +}
> +
> +void show_stack(struct task_struct *task, unsigned long *sp)
> +{
> + struct pt_regs regs;
> + if (sp) {
> + regs.regs[29] = (unsigned long)sp;
> + regs.regs[31] = 0;
> + regs.cp0_epc = 0;
> + } else {
> + if (task && task != current) {
> + regs.regs[29] = task->thread.reg29;
> + regs.regs[31] = 0;
> + regs.cp0_epc = task->thread.reg31;
> + } else {
> + dump_stack_top(®s);
> + }
> + }
> + show_stacktrace(task, ®s);
> }
>
> /*
> @@ -146,6 +212,14 @@ void dump_stack(void)
> {
> unsigned long stack;
>
> +#ifdef CONFIG_KALLSYMS
> + if (!raw_show_trace) {
> + struct pt_regs regs;
> + dump_stack_top(®s);
> + show_frametrace(current, ®s);
> + return;
> + }
> +#endif
> show_trace(&stack);
> }
>
> @@ -265,7 +339,7 @@ void show_registers(struct pt_regs *regs
> print_modules();
> printk("Process %s (pid: %d, threadinfo=%p, task=%p)\n",
> current->comm, current->pid, current_thread_info(), current);
> - show_stack(current, (long *) regs->regs[29]);
> + show_stacktrace(current, regs);
> show_code((unsigned int *) regs->cp0_epc);
> printk("\n");
> }
>
>
next prev parent reply other threads:[~2006-07-27 14:34 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
2006-07-26 14:22 [PATCH] dump_stack() based on prologue code analysis Atsushi Nemoto
2006-07-27 14:33 ` Franck Bui-Huu [this message]
2006-07-27 19:03 ` Franck Bui-Huu
2006-07-28 8:16 ` Franck Bui-Huu
2006-07-28 16:08 ` Atsushi Nemoto
2006-07-28 16:01 ` Atsushi Nemoto
2006-07-31 9:15 ` Franck Bui-Huu
2006-07-31 13:39 ` Atsushi Nemoto
2006-07-31 14:32 ` Franck Bui-Huu
2006-07-31 15:33 ` Atsushi Nemoto
2006-07-31 15:51 ` Franck Bui-Huu
2006-07-31 15:59 ` Atsushi Nemoto
2006-07-28 15:44 ` Atsushi Nemoto
2006-07-31 8:45 ` Franck Bui-Huu
2006-07-27 16:54 ` David Daney
2006-07-27 17:03 ` Thiemo Seufer
2006-07-27 17:27 ` David Daney
2006-07-27 18:51 ` Franck Bui-Huu
2006-07-27 19:12 ` Thiemo Seufer
2006-07-28 14:38 ` Atsushi Nemoto
2006-07-28 17:05 ` David Daney
2006-07-28 17:34 ` Nigel Stephens
2006-07-28 18:32 ` David Daney
2006-07-28 19:31 ` Thiemo Seufer
2006-07-29 14:25 ` Atsushi Nemoto
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=44C8CEA4.20000@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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox