1 /* 2 * kernel/stacktrace.c 3 * 4 * Stack trace management functions 5 * 6 * Copyright (C) 2006 Red Hat, Inc., Ingo Molnar <[email protected]> 7 */ 8 #include <linux/sched.h> 9 #include <linux/kernel.h> 10 #include <linux/export.h> 11 #include <linux/kallsyms.h> 12 #include <linux/stacktrace.h> 13 14 /** 15 * stack_trace_print - Print the entries in the stack trace 16 * @entries: Pointer to storage array 17 * @nr_entries: Number of entries in the storage array 18 * @spaces: Number of leading spaces to print 19 */ 20 void stack_trace_print(unsigned long *entries, unsigned int nr_entries, 21 int spaces) 22 { 23 unsigned int i; 24 25 if (WARN_ON(!entries)) 26 return; 27 28 for (i = 0; i < nr_entries; i++) 29 printk("%*c%pS\n", 1 + spaces, ' ', (void *)entries[i]); 30 } 31 EXPORT_SYMBOL_GPL(stack_trace_print); 32 33 void print_stack_trace(struct stack_trace *trace, int spaces) 34 { 35 stack_trace_print(trace->entries, trace->nr_entries, spaces); 36 } 37 EXPORT_SYMBOL_GPL(print_stack_trace); 38 39 /** 40 * stack_trace_snprint - Print the entries in the stack trace into a buffer 41 * @buf: Pointer to the print buffer 42 * @size: Size of the print buffer 43 * @entries: Pointer to storage array 44 * @nr_entries: Number of entries in the storage array 45 * @spaces: Number of leading spaces to print 46 * 47 * Return: Number of bytes printed. 48 */ 49 int stack_trace_snprint(char *buf, size_t size, unsigned long *entries, 50 unsigned int nr_entries, int spaces) 51 { 52 unsigned int generated, i, total = 0; 53 54 if (WARN_ON(!entries)) 55 return 0; 56 57 for (i = 0; i < nr_entries && size; i++) { 58 generated = snprintf(buf, size, "%*c%pS\n", 1 + spaces, ' ', 59 (void *)entries[i]); 60 61 total += generated; 62 if (generated >= size) { 63 buf += size; 64 size = 0; 65 } else { 66 buf += generated; 67 size -= generated; 68 } 69 } 70 71 return total; 72 } 73 EXPORT_SYMBOL_GPL(stack_trace_snprint); 74 75 int snprint_stack_trace(char *buf, size_t size, 76 struct stack_trace *trace, int spaces) 77 { 78 return stack_trace_snprint(buf, size, trace->entries, 79 trace->nr_entries, spaces); 80 } 81 EXPORT_SYMBOL_GPL(snprint_stack_trace); 82 83 /* 84 * Architectures that do not implement save_stack_trace_*() 85 * get these weak aliases and once-per-bootup warnings 86 * (whenever this facility is utilized - for example by procfs): 87 */ 88 __weak void 89 save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) 90 { 91 WARN_ONCE(1, KERN_INFO "save_stack_trace_tsk() not implemented yet.\n"); 92 } 93 94 __weak void 95 save_stack_trace_regs(struct pt_regs *regs, struct stack_trace *trace) 96 { 97 WARN_ONCE(1, KERN_INFO "save_stack_trace_regs() not implemented yet.\n"); 98 } 99 100 __weak int 101 save_stack_trace_tsk_reliable(struct task_struct *tsk, 102 struct stack_trace *trace) 103 { 104 WARN_ONCE(1, KERN_INFO "save_stack_tsk_reliable() not implemented yet.\n"); 105 return -ENOSYS; 106 } 107 108 /** 109 * stack_trace_save - Save a stack trace into a storage array 110 * @store: Pointer to storage array 111 * @size: Size of the storage array 112 * @skipnr: Number of entries to skip at the start of the stack trace 113 * 114 * Return: Number of trace entries stored 115 */ 116 unsigned int stack_trace_save(unsigned long *store, unsigned int size, 117 unsigned int skipnr) 118 { 119 struct stack_trace trace = { 120 .entries = store, 121 .max_entries = size, 122 .skip = skipnr + 1, 123 }; 124 125 save_stack_trace(&trace); 126 return trace.nr_entries; 127 } 128 EXPORT_SYMBOL_GPL(stack_trace_save); 129 130 /** 131 * stack_trace_save_tsk - Save a task stack trace into a storage array 132 * @task: The task to examine 133 * @store: Pointer to storage array 134 * @size: Size of the storage array 135 * @skipnr: Number of entries to skip at the start of the stack trace 136 * 137 * Return: Number of trace entries stored 138 */ 139 unsigned int stack_trace_save_tsk(struct task_struct *task, 140 unsigned long *store, unsigned int size, 141 unsigned int skipnr) 142 { 143 struct stack_trace trace = { 144 .entries = store, 145 .max_entries = size, 146 .skip = skipnr + 1, 147 }; 148 149 save_stack_trace_tsk(task, &trace); 150 return trace.nr_entries; 151 } 152 153 /** 154 * stack_trace_save_regs - Save a stack trace based on pt_regs into a storage array 155 * @regs: Pointer to pt_regs to examine 156 * @store: Pointer to storage array 157 * @size: Size of the storage array 158 * @skipnr: Number of entries to skip at the start of the stack trace 159 * 160 * Return: Number of trace entries stored 161 */ 162 unsigned int stack_trace_save_regs(struct pt_regs *regs, unsigned long *store, 163 unsigned int size, unsigned int skipnr) 164 { 165 struct stack_trace trace = { 166 .entries = store, 167 .max_entries = size, 168 .skip = skipnr, 169 }; 170 171 save_stack_trace_regs(regs, &trace); 172 return trace.nr_entries; 173 } 174 175 #ifdef CONFIG_HAVE_RELIABLE_STACKTRACE 176 /** 177 * stack_trace_save_tsk_reliable - Save task stack with verification 178 * @tsk: Pointer to the task to examine 179 * @store: Pointer to storage array 180 * @size: Size of the storage array 181 * 182 * Return: An error if it detects any unreliable features of the 183 * stack. Otherwise it guarantees that the stack trace is 184 * reliable and returns the number of entries stored. 185 * 186 * If the task is not 'current', the caller *must* ensure the task is inactive. 187 */ 188 int stack_trace_save_tsk_reliable(struct task_struct *tsk, unsigned long *store, 189 unsigned int size) 190 { 191 struct stack_trace trace = { 192 .entries = store, 193 .max_entries = size, 194 }; 195 int ret = save_stack_trace_tsk_reliable(tsk, &trace); 196 197 return ret ? ret : trace.nr_entries; 198 } 199 #endif 200 201 #ifdef CONFIG_USER_STACKTRACE_SUPPORT 202 /** 203 * stack_trace_save_user - Save a user space stack trace into a storage array 204 * @store: Pointer to storage array 205 * @size: Size of the storage array 206 * 207 * Return: Number of trace entries stored 208 */ 209 unsigned int stack_trace_save_user(unsigned long *store, unsigned int size) 210 { 211 struct stack_trace trace = { 212 .entries = store, 213 .max_entries = size, 214 }; 215 216 save_stack_trace_user(&trace); 217 return trace.nr_entries; 218 } 219 #endif /* CONFIG_USER_STACKTRACE_SUPPORT */ 220