1/** 2 * @file backtrace.c 3 * 4 * @remark Copyright 2002 OProfile authors 5 * @remark Read the file COPYING 6 * 7 * @author John Levon 8 * @author David Smith 9 */ 10 11#include <linux/oprofile.h> 12#include <linux/sched.h> 13#include <linux/mm.h> 14#include <asm/ptrace.h> 15#include <asm/uaccess.h> 16#include <asm/stacktrace.h> 17 18static void backtrace_warning_symbol(void *data, char *msg, 19 unsigned long symbol) 20{ 21 /* Ignore warnings */ 22} 23 24static void backtrace_warning(void *data, char *msg) 25{ 26 /* Ignore warnings */ 27} 28 29static int backtrace_stack(void *data, char *name) 30{ 31 /* Yes, we want all stacks */ 32 return 0; 33} 34 35static void backtrace_address(void *data, unsigned long addr, int reliable) 36{ 37 unsigned int *depth = data; 38 39 if ((*depth)--) 40 oprofile_add_trace(addr); 41} 42 43static struct stacktrace_ops backtrace_ops = { 44 .warning = backtrace_warning, 45 .warning_symbol = backtrace_warning_symbol, 46 .stack = backtrace_stack, 47 .address = backtrace_address, 48 .walk_stack = print_context_stack, 49}; 50 51struct frame_head { 52 struct frame_head *bp; 53 unsigned long ret; 54} __attribute__((packed)); 55 56static struct frame_head *dump_user_backtrace(struct frame_head *head) 57{ 58 struct frame_head bufhead[2]; 59 60 /* Also check accessibility of one struct frame_head beyond */ 61 if (!access_ok(VERIFY_READ, head, sizeof(bufhead))) 62 return NULL; 63 if (__copy_from_user_inatomic(bufhead, head, sizeof(bufhead))) 64 return NULL; 65 66 oprofile_add_trace(bufhead[0].ret); 67 68 /* frame pointers should strictly progress back up the stack 69 * (towards higher addresses) */ 70 if (head >= bufhead[0].bp) 71 return NULL; 72 73 return bufhead[0].bp; 74} 75 76void 77x86_backtrace(struct pt_regs * const regs, unsigned int depth) 78{ 79 struct frame_head *head = (struct frame_head *)frame_pointer(regs); 80 81 if (!user_mode_vm(regs)) { 82 unsigned long stack = kernel_stack_pointer(regs); 83 if (depth) 84 dump_trace(NULL, regs, (unsigned long *)stack, 0, 85 &backtrace_ops, &depth); 86 return; 87 } 88 89 while (depth-- && head) 90 head = dump_user_backtrace(head); 91} 92