This source file includes following definitions.
- xtensa_backtrace_user
- xtensa_backtrace_kernel
- walk_stackframe
- stack_trace_cb
- save_stack_trace_tsk
- save_stack_trace
- return_address_cb
- return_address
   1 
   2 
   3 
   4 
   5 
   6 
   7 
   8 
   9 
  10 
  11 #include <linux/export.h>
  12 #include <linux/sched.h>
  13 #include <linux/stacktrace.h>
  14 
  15 #include <asm/stacktrace.h>
  16 #include <asm/traps.h>
  17 #include <linux/uaccess.h>
  18 
  19 #if IS_ENABLED(CONFIG_OPROFILE) || IS_ENABLED(CONFIG_PERF_EVENTS)
  20 
  21 
  22 
  23 
  24 extern int common_exception_return;
  25 
  26 void xtensa_backtrace_user(struct pt_regs *regs, unsigned int depth,
  27                            int (*ufn)(struct stackframe *frame, void *data),
  28                            void *data)
  29 {
  30         unsigned long windowstart = regs->windowstart;
  31         unsigned long windowbase = regs->windowbase;
  32         unsigned long a0 = regs->areg[0];
  33         unsigned long a1 = regs->areg[1];
  34         unsigned long pc = regs->pc;
  35         struct stackframe frame;
  36         int index;
  37 
  38         if (!depth--)
  39                 return;
  40 
  41         frame.pc = pc;
  42         frame.sp = a1;
  43 
  44         if (pc == 0 || pc >= TASK_SIZE || ufn(&frame, data))
  45                 return;
  46 
  47         if (IS_ENABLED(CONFIG_USER_ABI_CALL0_ONLY) ||
  48             (IS_ENABLED(CONFIG_USER_ABI_CALL0_PROBE) &&
  49              !(regs->ps & PS_WOE_MASK)))
  50                 return;
  51 
  52         
  53 
  54 
  55 
  56 
  57 
  58 
  59 
  60         
  61         
  62 
  63 
  64         windowstart = (windowstart << WSBITS | windowstart) >> windowbase;
  65 
  66         
  67 
  68 
  69         for (index = WSBITS - 1; (index > 0) && depth; depth--, index--)
  70                 if (windowstart & (1 << index)) {
  71                         
  72                         pc = MAKE_PC_FROM_RA(a0, pc);
  73                         
  74 
  75 
  76                         a0 = regs->areg[index * 4];
  77                         a1 = regs->areg[index * 4 + 1];
  78 
  79                         frame.pc = pc;
  80                         frame.sp = a1;
  81 
  82                         if (pc == 0 || pc >= TASK_SIZE || ufn(&frame, data))
  83                                 return;
  84                 }
  85 
  86         
  87         
  88 
  89 
  90         if (!depth)
  91                 return;
  92 
  93         
  94         
  95         while (a0 != 0 && depth--) {
  96                 pc = MAKE_PC_FROM_RA(a0, pc);
  97 
  98                 
  99                 if (!access_ok(&SPILL_SLOT(a1, 0), 8))
 100                         return;
 101                 
 102                 if (__get_user(a0, &SPILL_SLOT(a1, 0)) ||
 103                     __get_user(a1, &SPILL_SLOT(a1, 1)))
 104                         return;
 105 
 106                 frame.pc = pc;
 107                 frame.sp = a1;
 108 
 109                 if (pc == 0 || pc >= TASK_SIZE || ufn(&frame, data))
 110                         return;
 111         }
 112 }
 113 EXPORT_SYMBOL(xtensa_backtrace_user);
 114 
 115 void xtensa_backtrace_kernel(struct pt_regs *regs, unsigned int depth,
 116                              int (*kfn)(struct stackframe *frame, void *data),
 117                              int (*ufn)(struct stackframe *frame, void *data),
 118                              void *data)
 119 {
 120         unsigned long pc = regs->depc > VALID_DOUBLE_EXCEPTION_ADDRESS ?
 121                 regs->depc : regs->pc;
 122         unsigned long sp_start, sp_end;
 123         unsigned long a0 = regs->areg[0];
 124         unsigned long a1 = regs->areg[1];
 125 
 126         sp_start = a1 & ~(THREAD_SIZE - 1);
 127         sp_end = sp_start + THREAD_SIZE;
 128 
 129         
 130         spill_registers();
 131 
 132         
 133 
 134 
 135         while (a1 > sp_start && a1 < sp_end && depth--) {
 136                 struct stackframe frame;
 137 
 138                 frame.pc = pc;
 139                 frame.sp = a1;
 140 
 141                 if (kernel_text_address(pc) && kfn(&frame, data))
 142                         return;
 143 
 144                 if (pc == (unsigned long)&common_exception_return) {
 145                         regs = (struct pt_regs *)a1;
 146                         if (user_mode(regs)) {
 147                                 if (ufn == NULL)
 148                                         return;
 149                                 xtensa_backtrace_user(regs, depth, ufn, data);
 150                                 return;
 151                         }
 152                         a0 = regs->areg[0];
 153                         a1 = regs->areg[1];
 154                         continue;
 155                 }
 156 
 157                 sp_start = a1;
 158 
 159                 pc = MAKE_PC_FROM_RA(a0, pc);
 160                 a0 = SPILL_SLOT(a1, 0);
 161                 a1 = SPILL_SLOT(a1, 1);
 162         }
 163 }
 164 EXPORT_SYMBOL(xtensa_backtrace_kernel);
 165 
 166 #endif
 167 
 168 void walk_stackframe(unsigned long *sp,
 169                 int (*fn)(struct stackframe *frame, void *data),
 170                 void *data)
 171 {
 172         unsigned long a0, a1;
 173         unsigned long sp_end;
 174 
 175         a1 = (unsigned long)sp;
 176         sp_end = ALIGN(a1, THREAD_SIZE);
 177 
 178         spill_registers();
 179 
 180         while (a1 < sp_end) {
 181                 struct stackframe frame;
 182 
 183                 sp = (unsigned long *)a1;
 184 
 185                 a0 = SPILL_SLOT(a1, 0);
 186                 a1 = SPILL_SLOT(a1, 1);
 187 
 188                 if (a1 <= (unsigned long)sp)
 189                         break;
 190 
 191                 frame.pc = MAKE_PC_FROM_RA(a0, a1);
 192                 frame.sp = a1;
 193 
 194                 if (fn(&frame, data))
 195                         return;
 196         }
 197 }
 198 
 199 #ifdef CONFIG_STACKTRACE
 200 
 201 struct stack_trace_data {
 202         struct stack_trace *trace;
 203         unsigned skip;
 204 };
 205 
 206 static int stack_trace_cb(struct stackframe *frame, void *data)
 207 {
 208         struct stack_trace_data *trace_data = data;
 209         struct stack_trace *trace = trace_data->trace;
 210 
 211         if (trace_data->skip) {
 212                 --trace_data->skip;
 213                 return 0;
 214         }
 215         if (!kernel_text_address(frame->pc))
 216                 return 0;
 217 
 218         trace->entries[trace->nr_entries++] = frame->pc;
 219         return trace->nr_entries >= trace->max_entries;
 220 }
 221 
 222 void save_stack_trace_tsk(struct task_struct *task, struct stack_trace *trace)
 223 {
 224         struct stack_trace_data trace_data = {
 225                 .trace = trace,
 226                 .skip = trace->skip,
 227         };
 228         walk_stackframe(stack_pointer(task), stack_trace_cb, &trace_data);
 229 }
 230 EXPORT_SYMBOL_GPL(save_stack_trace_tsk);
 231 
 232 void save_stack_trace(struct stack_trace *trace)
 233 {
 234         save_stack_trace_tsk(current, trace);
 235 }
 236 EXPORT_SYMBOL_GPL(save_stack_trace);
 237 
 238 #endif
 239 
 240 #ifdef CONFIG_FRAME_POINTER
 241 
 242 struct return_addr_data {
 243         unsigned long addr;
 244         unsigned skip;
 245 };
 246 
 247 static int return_address_cb(struct stackframe *frame, void *data)
 248 {
 249         struct return_addr_data *r = data;
 250 
 251         if (r->skip) {
 252                 --r->skip;
 253                 return 0;
 254         }
 255         if (!kernel_text_address(frame->pc))
 256                 return 0;
 257         r->addr = frame->pc;
 258         return 1;
 259 }
 260 
 261 
 262 
 263 
 264 
 265 unsigned long return_address(unsigned level)
 266 {
 267         struct return_addr_data r = {
 268                 .skip = level,
 269         };
 270         walk_stackframe(stack_pointer(NULL), return_address_cb, &r);
 271         return r.addr;
 272 }
 273 EXPORT_SYMBOL(return_address);
 274 
 275 #endif