root/arch/xtensa/kernel/stacktrace.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. xtensa_backtrace_user
  2. xtensa_backtrace_kernel
  3. walk_stackframe
  4. stack_trace_cb
  5. save_stack_trace_tsk
  6. save_stack_trace
  7. return_address_cb
  8. return_address

   1 /*
   2  * Kernel and userspace stack tracing.
   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  * Copyright (C) 2015 Cadence Design Systems Inc.
  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 /* Address of common_exception_return, used to check the
  22  * transition from kernel to user space.
  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         /* Two steps:
  53          *
  54          * 1. Look through the register window for the
  55          * previous PCs in the call trace.
  56          *
  57          * 2. Look on the stack.
  58          */
  59 
  60         /* Step 1.  */
  61         /* Rotate WINDOWSTART to move the bit corresponding to
  62          * the current window to the bit #0.
  63          */
  64         windowstart = (windowstart << WSBITS | windowstart) >> windowbase;
  65 
  66         /* Look for bits that are set, they correspond to
  67          * valid windows.
  68          */
  69         for (index = WSBITS - 1; (index > 0) && depth; depth--, index--)
  70                 if (windowstart & (1 << index)) {
  71                         /* Get the PC from a0 and a1. */
  72                         pc = MAKE_PC_FROM_RA(a0, pc);
  73                         /* Read a0 and a1 from the
  74                          * corresponding position in AREGs.
  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         /* Step 2. */
  87         /* We are done with the register window, we need to
  88          * look through the stack.
  89          */
  90         if (!depth)
  91                 return;
  92 
  93         /* Start from the a1 register. */
  94         /* a1 = regs->areg[1]; */
  95         while (a0 != 0 && depth--) {
  96                 pc = MAKE_PC_FROM_RA(a0, pc);
  97 
  98                 /* Check if the region is OK to access. */
  99                 if (!access_ok(&SPILL_SLOT(a1, 0), 8))
 100                         return;
 101                 /* Copy a1, a0 from user space stack frame. */
 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         /* Spill the register window to the stack first. */
 130         spill_registers();
 131 
 132         /* Read the stack frames one by one and create the PC
 133          * from the a0 and a1 registers saved there.
 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  * level == 0 is for the return address from the caller of this function,
 263  * not from this function itself.
 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

/* [<][>][^][v][top][bottom][index][help] */