mirror of
https://github.com/torvalds/linux.git
synced 2024-11-05 19:41:54 +00:00
5bc27dc2f5
Right now, we take the stack pointer early during the backtrace path, but only calculate bp several functions deep later, making it hard to reconcile the stack and bp backtraces (as well as showing several internal backtrace functions on the stack with bp based backtracing). This patch moves the bp taking to the same place we take the stack pointer; sadly this ripples through several layers of the back tracing stack, but it's not all that bad in the end I hope. Signed-off-by: Arjan van de Ven <arjan@linux.intel.com> Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
92 lines
1.9 KiB
C
92 lines
1.9 KiB
C
/**
|
|
* @file backtrace.c
|
|
*
|
|
* @remark Copyright 2002 OProfile authors
|
|
* @remark Read the file COPYING
|
|
*
|
|
* @author John Levon
|
|
* @author David Smith
|
|
*/
|
|
|
|
#include <linux/oprofile.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/mm.h>
|
|
#include <asm/ptrace.h>
|
|
#include <asm/uaccess.h>
|
|
#include <asm/stacktrace.h>
|
|
|
|
static void backtrace_warning_symbol(void *data, char *msg,
|
|
unsigned long symbol)
|
|
{
|
|
/* Ignore warnings */
|
|
}
|
|
|
|
static void backtrace_warning(void *data, char *msg)
|
|
{
|
|
/* Ignore warnings */
|
|
}
|
|
|
|
static int backtrace_stack(void *data, char *name)
|
|
{
|
|
/* Yes, we want all stacks */
|
|
return 0;
|
|
}
|
|
|
|
static void backtrace_address(void *data, unsigned long addr, int reliable)
|
|
{
|
|
unsigned int *depth = data;
|
|
|
|
if ((*depth)--)
|
|
oprofile_add_trace(addr);
|
|
}
|
|
|
|
static struct stacktrace_ops backtrace_ops = {
|
|
.warning = backtrace_warning,
|
|
.warning_symbol = backtrace_warning_symbol,
|
|
.stack = backtrace_stack,
|
|
.address = backtrace_address,
|
|
};
|
|
|
|
struct frame_head {
|
|
struct frame_head *bp;
|
|
unsigned long ret;
|
|
} __attribute__((packed));
|
|
|
|
static struct frame_head *
|
|
dump_user_backtrace(struct frame_head * head)
|
|
{
|
|
struct frame_head bufhead[2];
|
|
|
|
/* Also check accessibility of one struct frame_head beyond */
|
|
if (!access_ok(VERIFY_READ, head, sizeof(bufhead)))
|
|
return NULL;
|
|
if (__copy_from_user_inatomic(bufhead, head, sizeof(bufhead)))
|
|
return NULL;
|
|
|
|
oprofile_add_trace(bufhead[0].ret);
|
|
|
|
/* frame pointers should strictly progress back up the stack
|
|
* (towards higher addresses) */
|
|
if (head >= bufhead[0].bp)
|
|
return NULL;
|
|
|
|
return bufhead[0].bp;
|
|
}
|
|
|
|
void
|
|
x86_backtrace(struct pt_regs * const regs, unsigned int depth)
|
|
{
|
|
struct frame_head *head = (struct frame_head *)frame_pointer(regs);
|
|
unsigned long stack = stack_pointer(regs);
|
|
|
|
if (!user_mode_vm(regs)) {
|
|
if (depth)
|
|
dump_trace(NULL, regs, (unsigned long *)stack, 0,
|
|
&backtrace_ops, &depth);
|
|
return;
|
|
}
|
|
|
|
while (depth-- && head)
|
|
head = dump_user_backtrace(head);
|
|
}
|