bc850d6b37
For enhancing the 32 bit EBP based backtracer, I need the capability for the backtracer to tell it's customer that an entry is either reliable or unreliable, and the backtrace printing code then needs to print the unreliable ones slightly different. This patch adds the basic capability, the next patch will add a user of this capability. 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,
|
|
&backtrace_ops, &depth);
|
|
return;
|
|
}
|
|
|
|
while (depth-- && head)
|
|
head = dump_user_backtrace(head);
|
|
}
|