1 /* 2 * Stack trace management functions 3 * 4 * Copyright (C) 2006-2009 Red Hat, Inc., Ingo Molnar <mingo@redhat.com> 5 */ 6 #include <linux/sched.h> 7 #include <linux/stacktrace.h> 8 #include <linux/module.h> 9 #include <linux/uaccess.h> 10 #include <asm/stacktrace.h> 11 12 static void save_stack_warning(void *data, char *msg) 13 { 14 } 15 16 static void 17 save_stack_warning_symbol(void *data, char *msg, unsigned long symbol) 18 { 19 } 20 21 static int save_stack_stack(void *data, char *name) 22 { 23 return 0; 24 } 25 26 static void save_stack_address(void *data, unsigned long addr, int reliable) 27 { 28 struct stack_trace *trace = data; 29 if (!reliable) 30 return; 31 if (trace->skip > 0) { 32 trace->skip--; 33 return; 34 } 35 if (trace->nr_entries < trace->max_entries) 36 trace->entries[trace->nr_entries++] = addr; 37 } 38 39 static void 40 save_stack_address_nosched(void *data, unsigned long addr, int reliable) 41 { 42 struct stack_trace *trace = (struct stack_trace *)data; 43 if (!reliable) 44 return; 45 if (in_sched_functions(addr)) 46 return; 47 if (trace->skip > 0) { 48 trace->skip--; 49 return; 50 } 51 if (trace->nr_entries < trace->max_entries) 52 trace->entries[trace->nr_entries++] = addr; 53 } 54 55 static const struct stacktrace_ops save_stack_ops = { 56 .warning = save_stack_warning, 57 .warning_symbol = save_stack_warning_symbol, 58 .stack = save_stack_stack, 59 .address = save_stack_address, 60 }; 61 62 static const struct stacktrace_ops save_stack_ops_nosched = { 63 .warning = save_stack_warning, 64 .warning_symbol = save_stack_warning_symbol, 65 .stack = save_stack_stack, 66 .address = save_stack_address_nosched, 67 }; 68 69 /* 70 * Save stack-backtrace addresses into a stack_trace buffer. 71 */ 72 void save_stack_trace(struct stack_trace *trace) 73 { 74 dump_trace(current, NULL, NULL, 0, &save_stack_ops, trace); 75 if (trace->nr_entries < trace->max_entries) 76 trace->entries[trace->nr_entries++] = ULONG_MAX; 77 } 78 EXPORT_SYMBOL_GPL(save_stack_trace); 79 80 void save_stack_trace_bp(struct stack_trace *trace, unsigned long bp) 81 { 82 dump_trace(current, NULL, NULL, bp, &save_stack_ops, trace); 83 if (trace->nr_entries < trace->max_entries) 84 trace->entries[trace->nr_entries++] = ULONG_MAX; 85 } 86 87 void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) 88 { 89 dump_trace(tsk, NULL, NULL, 0, &save_stack_ops_nosched, trace); 90 if (trace->nr_entries < trace->max_entries) 91 trace->entries[trace->nr_entries++] = ULONG_MAX; 92 } 93 EXPORT_SYMBOL_GPL(save_stack_trace_tsk); 94 95 /* Userspace stacktrace - based on kernel/trace/trace_sysprof.c */ 96 97 struct stack_frame { 98 const void __user *next_fp; 99 unsigned long ret_addr; 100 }; 101 102 static int copy_stack_frame(const void __user *fp, struct stack_frame *frame) 103 { 104 int ret; 105 106 if (!access_ok(VERIFY_READ, fp, sizeof(*frame))) 107 return 0; 108 109 ret = 1; 110 pagefault_disable(); 111 if (__copy_from_user_inatomic(frame, fp, sizeof(*frame))) 112 ret = 0; 113 pagefault_enable(); 114 115 return ret; 116 } 117 118 static inline void __save_stack_trace_user(struct stack_trace *trace) 119 { 120 const struct pt_regs *regs = task_pt_regs(current); 121 const void __user *fp = (const void __user *)regs->bp; 122 123 if (trace->nr_entries < trace->max_entries) 124 trace->entries[trace->nr_entries++] = regs->ip; 125 126 while (trace->nr_entries < trace->max_entries) { 127 struct stack_frame frame; 128 129 frame.next_fp = NULL; 130 frame.ret_addr = 0; 131 if (!copy_stack_frame(fp, &frame)) 132 break; 133 if ((unsigned long)fp < regs->sp) 134 break; 135 if (frame.ret_addr) { 136 trace->entries[trace->nr_entries++] = 137 frame.ret_addr; 138 } 139 if (fp == frame.next_fp) 140 break; 141 fp = frame.next_fp; 142 } 143 } 144 145 void save_stack_trace_user(struct stack_trace *trace) 146 { 147 /* 148 * Trace user stack if we are not a kernel thread 149 */ 150 if (current->mm) { 151 __save_stack_trace_user(trace); 152 } 153 if (trace->nr_entries < trace->max_entries) 154 trace->entries[trace->nr_entries++] = ULONG_MAX; 155 } 156 157