cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

unwinder.c (2871B)


      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