root/arch/arc/kernel/stacktrace.c

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

DEFINITIONS

This source file includes following definitions.
  1. seed_unwind_frame_info
  2. arc_unwind_core
  3. __print_sym
  4. __collect_all
  5. __collect_all_but_sched
  6. __get_first_nonsched
  7. show_stacktrace
  8. show_stack
  9. get_wchan
  10. save_stack_trace_tsk
  11. save_stack_trace

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  *      stacktrace.c : stacktracing APIs needed by rest of kernel
   4  *                      (wrappers over ARC dwarf based unwinder)
   5  *
   6  * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
   7  *
   8  *  vineetg: aug 2009
   9  *  -Implemented CONFIG_STACKTRACE APIs, primarily save_stack_trace_tsk( )
  10  *   for displaying task's kernel mode call stack in /proc/<pid>/stack
  11  *  -Iterator based approach to have single copy of unwinding core and APIs
  12  *   needing unwinding, implement the logic in iterator regarding:
  13  *      = which frame onwards to start capture
  14  *      = which frame to stop capturing (wchan)
  15  *      = specifics of data structs where trace is saved(CONFIG_STACKTRACE etc)
  16  *
  17  *  vineetg: March 2009
  18  *  -Implemented correct versions of thread_saved_pc() and get_wchan()
  19  *
  20  *  rajeshwarr: 2008
  21  *  -Initial implementation
  22  */
  23 
  24 #include <linux/ptrace.h>
  25 #include <linux/export.h>
  26 #include <linux/stacktrace.h>
  27 #include <linux/kallsyms.h>
  28 #include <linux/sched/debug.h>
  29 
  30 #include <asm/arcregs.h>
  31 #include <asm/unwind.h>
  32 #include <asm/switch_to.h>
  33 
  34 /*-------------------------------------------------------------------------
  35  *              Unwinder Iterator
  36  *-------------------------------------------------------------------------
  37  */
  38 
  39 #ifdef CONFIG_ARC_DW2_UNWIND
  40 
  41 static void seed_unwind_frame_info(struct task_struct *tsk,
  42                                    struct pt_regs *regs,
  43                                    struct unwind_frame_info *frame_info)
  44 {
  45         /*
  46          * synchronous unwinding (e.g. dump_stack)
  47          *  - uses current values of SP and friends
  48          */
  49         if (tsk == NULL && regs == NULL) {
  50                 unsigned long fp, sp, blink, ret;
  51                 frame_info->task = current;
  52 
  53                 __asm__ __volatile__(
  54                         "mov %0,r27\n\t"
  55                         "mov %1,r28\n\t"
  56                         "mov %2,r31\n\t"
  57                         "mov %3,r63\n\t"
  58                         : "=r"(fp), "=r"(sp), "=r"(blink), "=r"(ret)
  59                 );
  60 
  61                 frame_info->regs.r27 = fp;
  62                 frame_info->regs.r28 = sp;
  63                 frame_info->regs.r31 = blink;
  64                 frame_info->regs.r63 = ret;
  65                 frame_info->call_frame = 0;
  66         } else if (regs == NULL) {
  67                 /*
  68                  * Asynchronous unwinding of sleeping task
  69                  *  - Gets SP etc from task's pt_regs (saved bottom of kernel
  70                  *    mode stack of task)
  71                  */
  72 
  73                 frame_info->task = tsk;
  74 
  75                 frame_info->regs.r27 = TSK_K_FP(tsk);
  76                 frame_info->regs.r28 = TSK_K_ESP(tsk);
  77                 frame_info->regs.r31 = TSK_K_BLINK(tsk);
  78                 frame_info->regs.r63 = (unsigned int)__switch_to;
  79 
  80                 /* In the prologue of __switch_to, first FP is saved on stack
  81                  * and then SP is copied to FP. Dwarf assumes cfa as FP based
  82                  * but we didn't save FP. The value retrieved above is FP's
  83                  * state in previous frame.
  84                  * As a work around for this, we unwind from __switch_to start
  85                  * and adjust SP accordingly. The other limitation is that
  86                  * __switch_to macro is dwarf rules are not generated for inline
  87                  * assembly code
  88                  */
  89                 frame_info->regs.r27 = 0;
  90                 frame_info->regs.r28 += 60;
  91                 frame_info->call_frame = 0;
  92 
  93         } else {
  94                 /*
  95                  * Asynchronous unwinding of intr/exception
  96                  *  - Just uses the pt_regs passed
  97                  */
  98                 frame_info->task = tsk;
  99 
 100                 frame_info->regs.r27 = regs->fp;
 101                 frame_info->regs.r28 = regs->sp;
 102                 frame_info->regs.r31 = regs->blink;
 103                 frame_info->regs.r63 = regs->ret;
 104                 frame_info->call_frame = 0;
 105         }
 106 }
 107 
 108 #endif
 109 
 110 notrace noinline unsigned int
 111 arc_unwind_core(struct task_struct *tsk, struct pt_regs *regs,
 112                 int (*consumer_fn) (unsigned int, void *), void *arg)
 113 {
 114 #ifdef CONFIG_ARC_DW2_UNWIND
 115         int ret = 0;
 116         unsigned int address;
 117         struct unwind_frame_info frame_info;
 118 
 119         seed_unwind_frame_info(tsk, regs, &frame_info);
 120 
 121         while (1) {
 122                 address = UNW_PC(&frame_info);
 123 
 124                 if (!address || !__kernel_text_address(address))
 125                         break;
 126 
 127                 if (consumer_fn(address, arg) == -1)
 128                         break;
 129 
 130                 ret = arc_unwind(&frame_info);
 131                 if (ret)
 132                         break;
 133 
 134                 frame_info.regs.r63 = frame_info.regs.r31;
 135         }
 136 
 137         return address;         /* return the last address it saw */
 138 #else
 139         /* On ARC, only Dward based unwinder works. fp based backtracing is
 140          * not possible (-fno-omit-frame-pointer) because of the way function
 141          * prelogue is setup (callee regs saved and then fp set and not other
 142          * way around
 143          */
 144         pr_warn_once("CONFIG_ARC_DW2_UNWIND needs to be enabled\n");
 145         return 0;
 146 
 147 #endif
 148 }
 149 
 150 /*-------------------------------------------------------------------------
 151  * callbacks called by unwinder iterator to implement kernel APIs
 152  *
 153  * The callback can return -1 to force the iterator to stop, which by default
 154  * keeps going till the bottom-most frame.
 155  *-------------------------------------------------------------------------
 156  */
 157 
 158 /* Call-back which plugs into unwinding core to dump the stack in
 159  * case of panic/OOPs/BUG etc
 160  */
 161 static int __print_sym(unsigned int address, void *unused)
 162 {
 163         printk("  %pS\n", (void *)address);
 164         return 0;
 165 }
 166 
 167 #ifdef CONFIG_STACKTRACE
 168 
 169 /* Call-back which plugs into unwinding core to capture the
 170  * traces needed by kernel on /proc/<pid>/stack
 171  */
 172 static int __collect_all(unsigned int address, void *arg)
 173 {
 174         struct stack_trace *trace = arg;
 175 
 176         if (trace->skip > 0)
 177                 trace->skip--;
 178         else
 179                 trace->entries[trace->nr_entries++] = address;
 180 
 181         if (trace->nr_entries >= trace->max_entries)
 182                 return -1;
 183 
 184         return 0;
 185 }
 186 
 187 static int __collect_all_but_sched(unsigned int address, void *arg)
 188 {
 189         struct stack_trace *trace = arg;
 190 
 191         if (in_sched_functions(address))
 192                 return 0;
 193 
 194         if (trace->skip > 0)
 195                 trace->skip--;
 196         else
 197                 trace->entries[trace->nr_entries++] = address;
 198 
 199         if (trace->nr_entries >= trace->max_entries)
 200                 return -1;
 201 
 202         return 0;
 203 }
 204 
 205 #endif
 206 
 207 static int __get_first_nonsched(unsigned int address, void *unused)
 208 {
 209         if (in_sched_functions(address))
 210                 return 0;
 211 
 212         return -1;
 213 }
 214 
 215 /*-------------------------------------------------------------------------
 216  *              APIs expected by various kernel sub-systems
 217  *-------------------------------------------------------------------------
 218  */
 219 
 220 noinline void show_stacktrace(struct task_struct *tsk, struct pt_regs *regs)
 221 {
 222         pr_info("\nStack Trace:\n");
 223         arc_unwind_core(tsk, regs, __print_sym, NULL);
 224 }
 225 EXPORT_SYMBOL(show_stacktrace);
 226 
 227 /* Expected by sched Code */
 228 void show_stack(struct task_struct *tsk, unsigned long *sp)
 229 {
 230         show_stacktrace(tsk, NULL);
 231 }
 232 
 233 /* Another API expected by schedular, shows up in "ps" as Wait Channel
 234  * Of course just returning schedule( ) would be pointless so unwind until
 235  * the function is not in schedular code
 236  */
 237 unsigned int get_wchan(struct task_struct *tsk)
 238 {
 239         return arc_unwind_core(tsk, NULL, __get_first_nonsched, NULL);
 240 }
 241 
 242 #ifdef CONFIG_STACKTRACE
 243 
 244 /*
 245  * API required by CONFIG_STACKTRACE, CONFIG_LATENCYTOP.
 246  * A typical use is when /proc/<pid>/stack is queried by userland
 247  */
 248 void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
 249 {
 250         /* Assumes @tsk is sleeping so unwinds from __switch_to */
 251         arc_unwind_core(tsk, NULL, __collect_all_but_sched, trace);
 252 }
 253 
 254 void save_stack_trace(struct stack_trace *trace)
 255 {
 256         /* Pass NULL for task so it unwinds the current call frame */
 257         arc_unwind_core(NULL, NULL, __collect_all, trace);
 258 }
 259 EXPORT_SYMBOL_GPL(save_stack_trace);
 260 #endif

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