Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  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
 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