1 /* 2 * arch/xtensa/kernel/stacktrace.c 3 * 4 * This file is subject to the terms and conditions of the GNU General Public 5 * License. See the file "COPYING" in the main directory of this archive 6 * for more details. 7 * 8 * Copyright (C) 2001 - 2013 Tensilica Inc. 9 */ 10 #include <linux/export.h> 11 #include <linux/sched.h> 12 #include <linux/stacktrace.h> 13 14 #include <asm/stacktrace.h> 15 #include <asm/traps.h> 16 17 void walk_stackframe(unsigned long *sp, 18 int (*fn)(struct stackframe *frame, void *data), 19 void *data) 20 { 21 unsigned long a0, a1; 22 unsigned long sp_end; 23 24 a1 = (unsigned long)sp; 25 sp_end = ALIGN(a1, THREAD_SIZE); 26 27 spill_registers(); 28 29 while (a1 < sp_end) { 30 struct stackframe frame; 31 32 sp = (unsigned long *)a1; 33 34 a0 = *(sp - 4); 35 a1 = *(sp - 3); 36 37 if (a1 <= (unsigned long)sp) 38 break; 39 40 frame.pc = MAKE_PC_FROM_RA(a0, a1); 41 frame.sp = a1; 42 43 if (fn(&frame, data)) 44 return; 45 } 46 } 47 48 #ifdef CONFIG_STACKTRACE 49 50 struct stack_trace_data { 51 struct stack_trace *trace; 52 unsigned skip; 53 }; 54 55 static int stack_trace_cb(struct stackframe *frame, void *data) 56 { 57 struct stack_trace_data *trace_data = data; 58 struct stack_trace *trace = trace_data->trace; 59 60 if (trace_data->skip) { 61 --trace_data->skip; 62 return 0; 63 } 64 if (!kernel_text_address(frame->pc)) 65 return 0; 66 67 trace->entries[trace->nr_entries++] = frame->pc; 68 return trace->nr_entries >= trace->max_entries; 69 } 70 71 void save_stack_trace_tsk(struct task_struct *task, struct stack_trace *trace) 72 { 73 struct stack_trace_data trace_data = { 74 .trace = trace, 75 .skip = trace->skip, 76 }; 77 walk_stackframe(stack_pointer(task), stack_trace_cb, &trace_data); 78 } 79 EXPORT_SYMBOL_GPL(save_stack_trace_tsk); 80 81 void save_stack_trace(struct stack_trace *trace) 82 { 83 save_stack_trace_tsk(current, trace); 84 } 85 EXPORT_SYMBOL_GPL(save_stack_trace); 86 87 #endif 88 89 #ifdef CONFIG_FRAME_POINTER 90 91 struct return_addr_data { 92 unsigned long addr; 93 unsigned skip; 94 }; 95 96 static int return_address_cb(struct stackframe *frame, void *data) 97 { 98 struct return_addr_data *r = data; 99 100 if (r->skip) { 101 --r->skip; 102 return 0; 103 } 104 if (!kernel_text_address(frame->pc)) 105 return 0; 106 r->addr = frame->pc; 107 return 1; 108 } 109 110 unsigned long return_address(unsigned level) 111 { 112 struct return_addr_data r = { 113 .skip = level + 1, 114 }; 115 walk_stackframe(stack_pointer(NULL), return_address_cb, &r); 116 return r.addr; 117 } 118 EXPORT_SYMBOL(return_address); 119 120 #endif 121