linux/arch/openrisc/kernel/unwinder.c
<<
>>
Prefs
   1/*
   2 * OpenRISC unwinder.c
   3 *
   4 * Reusable arch specific api for unwinding stacks.
   5 *
   6 * Copyright (C) 2017 Stafford Horne <shorne@gmail.com>
   7 *
   8 * This file is licensed under the terms of the GNU General Public License
   9 * version 2.  This program is licensed "as is" without any warranty of any
  10 * kind, whether express or implied.
  11 */
  12
  13#include <linux/sched/task_stack.h>
  14#include <linux/kernel.h>
  15
  16#include <asm/unwinder.h>
  17
  18#ifdef CONFIG_FRAME_POINTER
  19struct or1k_frameinfo {
  20        unsigned long *fp;
  21        unsigned long ra;
  22        unsigned long top;
  23};
  24
  25/*
  26 * Verify a frameinfo structure.  The return address should be a valid text
  27 * address.  The frame pointer may be null if its the last frame, otherwise
  28 * the frame pointer should point to a location in the stack after the the
  29 * top of the next frame up.
  30 */
  31static inline int or1k_frameinfo_valid(struct or1k_frameinfo *frameinfo)
  32{
  33        return (frameinfo->fp == NULL ||
  34                (!kstack_end(frameinfo->fp) &&
  35                 frameinfo->fp > &frameinfo->top)) &&
  36               __kernel_text_address(frameinfo->ra);
  37}
  38
  39/*
  40 * Create a stack trace doing scanning which is frame pointer aware. We can
  41 * get reliable stack traces by matching the previously found frame
  42 * pointer with the top of the stack address every time we find a valid
  43 * or1k_frameinfo.
  44 *
  45 * Ideally the stack parameter will be passed as FP, but it can not be
  46 * guaranteed.  Therefore we scan each address looking for the first sign
  47 * of a return address.
  48 *
  49 * The OpenRISC stack frame looks something like the following.  The
  50 * location SP is held in r1 and location FP is held in r2 when frame pointers
  51 * enabled.
  52 *
  53 * SP   -> (top of stack)
  54 *      -  (callee saved registers)
  55 *      -  (local variables)
  56 * FP-8 -> previous FP             \
  57 * FP-4 -> return address          |- or1k_frameinfo
  58 * FP   -> (previous top of stack) /
  59 */
  60void unwind_stack(void *data, unsigned long *stack,
  61                  void (*trace)(void *data, unsigned long addr, int reliable))
  62{
  63        unsigned long *next_fp = NULL;
  64        struct or1k_frameinfo *frameinfo = NULL;
  65        int reliable = 0;
  66
  67        while (!kstack_end(stack)) {
  68                frameinfo = container_of(stack,
  69                                         struct or1k_frameinfo,
  70                                         top);
  71
  72                if (__kernel_text_address(frameinfo->ra)) {
  73                        if (or1k_frameinfo_valid(frameinfo) &&
  74                            (next_fp == NULL ||
  75                             next_fp == &frameinfo->top)) {
  76                                reliable = 1;
  77                                next_fp = frameinfo->fp;
  78                        } else
  79                                reliable = 0;
  80
  81                        trace(data, frameinfo->ra, reliable);
  82                }
  83                stack++;
  84        }
  85}
  86
  87#else /* CONFIG_FRAME_POINTER */
  88
  89/*
  90 * Create a stack trace by doing a simple scan treating all text addresses
  91 * as return addresses.
  92 */
  93void unwind_stack(void *data, unsigned long *stack,
  94                   void (*trace)(void *data, unsigned long addr, int reliable))
  95{
  96        unsigned long addr;
  97
  98        while (!kstack_end(stack)) {
  99                addr = *stack++;
 100                if (__kernel_text_address(addr))
 101                        trace(data, addr, 0);
 102        }
 103}
 104#endif /* CONFIG_FRAME_POINTER */
 105
 106