All of lore.kernel.org
 help / color / mirror / Atom feed
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(&regs);
> +		}
> +	}
> +	show_stacktrace(task, &regs);
>  }
>  
>  /*
> @@ -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(&regs);
> +		show_frametrace(current, &regs);
> +		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");
>  }
> 
> 

  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 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.