/*1* OpenRISC unwinder.c2*3* Reusable arch specific api for unwinding stacks.4*5* Copyright (C) 2017 Stafford Horne <[email protected]>6*7* This file is licensed under the terms of the GNU General Public License8* version 2. This program is licensed "as is" without any warranty of any9* kind, whether express or implied.10*/1112#include <linux/sched/task_stack.h>13#include <linux/kernel.h>1415#include <asm/unwinder.h>1617#ifdef CONFIG_FRAME_POINTER18struct or1k_frameinfo {19unsigned long *fp;20unsigned long ra;21unsigned long top;22};2324/*25* Verify a frameinfo structure. The return address should be a valid text26* address. The frame pointer may be null if its the last frame, otherwise27* the frame pointer should point to a location in the stack after the28* top of the next frame up.29*/30static inline int or1k_frameinfo_valid(struct or1k_frameinfo *frameinfo)31{32return (frameinfo->fp == NULL ||33(!kstack_end(frameinfo->fp) &&34frameinfo->fp > &frameinfo->top)) &&35__kernel_text_address(frameinfo->ra);36}3738/*39* Create a stack trace doing scanning which is frame pointer aware. We can40* get reliable stack traces by matching the previously found frame41* pointer with the top of the stack address every time we find a valid42* or1k_frameinfo.43*44* Ideally the stack parameter will be passed as FP, but it can not be45* guaranteed. Therefore we scan each address looking for the first sign46* of a return address.47*48* The OpenRISC stack frame looks something like the following. The49* location SP is held in r1 and location FP is held in r2 when frame pointers50* enabled.51*52* SP -> (top of stack)53* - (callee saved registers)54* - (local variables)55* FP-8 -> previous FP \56* FP-4 -> return address |- or1k_frameinfo57* FP -> (previous top of stack) /58*/59void unwind_stack(void *data, unsigned long *stack,60void (*trace)(void *data, unsigned long addr, int reliable))61{62unsigned long *next_fp = NULL;63struct or1k_frameinfo *frameinfo = NULL;64int reliable = 0;6566while (!kstack_end(stack)) {67frameinfo = container_of(stack,68struct or1k_frameinfo,69top);7071if (__kernel_text_address(frameinfo->ra)) {72if (or1k_frameinfo_valid(frameinfo) &&73(next_fp == NULL ||74next_fp == &frameinfo->top)) {75reliable = 1;76next_fp = frameinfo->fp;77} else78reliable = 0;7980trace(data, frameinfo->ra, reliable);81}82stack++;83}84}8586#else /* CONFIG_FRAME_POINTER */8788/*89* Create a stack trace by doing a simple scan treating all text addresses90* as return addresses.91*/92void unwind_stack(void *data, unsigned long *stack,93void (*trace)(void *data, unsigned long addr, int reliable))94{95unsigned long addr;9697while (!kstack_end(stack)) {98addr = *stack++;99if (__kernel_text_address(addr))100trace(data, addr, 0);101}102}103#endif /* CONFIG_FRAME_POINTER */104105106107