123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106 |
- /*
- * OpenRISC unwinder.c
- *
- * Reusable arch specific api for unwinding stacks.
- *
- * Copyright (C) 2017 Stafford Horne <shorne@gmail.com>
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
- */
- #include <linux/sched/task_stack.h>
- #include <linux/kernel.h>
- #include <asm/unwinder.h>
- #ifdef CONFIG_FRAME_POINTER
- struct or1k_frameinfo {
- unsigned long *fp;
- unsigned long ra;
- unsigned long top;
- };
- /*
- * Verify a frameinfo structure. The return address should be a valid text
- * address. The frame pointer may be null if its the last frame, otherwise
- * the frame pointer should point to a location in the stack after the the
- * top of the next frame up.
- */
- static inline int or1k_frameinfo_valid(struct or1k_frameinfo *frameinfo)
- {
- return (frameinfo->fp == NULL ||
- (!kstack_end(frameinfo->fp) &&
- frameinfo->fp > &frameinfo->top)) &&
- __kernel_text_address(frameinfo->ra);
- }
- /*
- * Create a stack trace doing scanning which is frame pointer aware. We can
- * get reliable stack traces by matching the previously found frame
- * pointer with the top of the stack address every time we find a valid
- * or1k_frameinfo.
- *
- * Ideally the stack parameter will be passed as FP, but it can not be
- * guaranteed. Therefore we scan each address looking for the first sign
- * of a return address.
- *
- * The OpenRISC stack frame looks something like the following. The
- * location SP is held in r1 and location FP is held in r2 when frame pointers
- * enabled.
- *
- * SP -> (top of stack)
- * - (callee saved registers)
- * - (local variables)
- * FP-8 -> previous FP \
- * FP-4 -> return address |- or1k_frameinfo
- * FP -> (previous top of stack) /
- */
- void unwind_stack(void *data, unsigned long *stack,
- void (*trace)(void *data, unsigned long addr, int reliable))
- {
- unsigned long *next_fp = NULL;
- struct or1k_frameinfo *frameinfo = NULL;
- int reliable = 0;
- while (!kstack_end(stack)) {
- frameinfo = container_of(stack,
- struct or1k_frameinfo,
- top);
- if (__kernel_text_address(frameinfo->ra)) {
- if (or1k_frameinfo_valid(frameinfo) &&
- (next_fp == NULL ||
- next_fp == &frameinfo->top)) {
- reliable = 1;
- next_fp = frameinfo->fp;
- } else
- reliable = 0;
- trace(data, frameinfo->ra, reliable);
- }
- stack++;
- }
- }
- #else /* CONFIG_FRAME_POINTER */
- /*
- * Create a stack trace by doing a simple scan treating all text addresses
- * as return addresses.
- */
- void unwind_stack(void *data, unsigned long *stack,
- void (*trace)(void *data, unsigned long addr, int reliable))
- {
- unsigned long addr;
- while (!kstack_end(stack)) {
- addr = *stack++;
- if (__kernel_text_address(addr))
- trace(data, addr, 0);
- }
- }
- #endif /* CONFIG_FRAME_POINTER */
|