linux/arch/arc/kernel/stacktrace.c
<<
>>
Prefs
   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
  41static 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
 110notrace noinline unsigned int
 111arc_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 */
 161static 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 */
 172static 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
 187static 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
 207static 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
 220noinline 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}
 225EXPORT_SYMBOL(show_stacktrace);
 226
 227/* Expected by sched Code */
 228void 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 */
 237unsigned 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 */
 248void 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
 254void 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}
 259EXPORT_SYMBOL_GPL(save_stack_trace);
 260#endif
 261