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

unwind.h (3347B)


      1/* SPDX-License-Identifier: GPL-2.0 */
      2#ifndef _ASM_S390_UNWIND_H
      3#define _ASM_S390_UNWIND_H
      4
      5#include <linux/sched.h>
      6#include <linux/ftrace.h>
      7#include <linux/kprobes.h>
      8#include <linux/llist.h>
      9#include <asm/ptrace.h>
     10#include <asm/stacktrace.h>
     11
     12/*
     13 * To use the stack unwinder it has to be initialized with unwind_start.
     14 * There four combinations for task and regs:
     15 * 1) task==NULL, regs==NULL: the unwind starts for the task that is currently
     16 *    running, sp/ip picked up from the CPU registers
     17 * 2) task==NULL, regs!=NULL: the unwind starts from the sp/ip found in
     18 *    the struct pt_regs of an interrupt frame for the current task
     19 * 3) task!=NULL, regs==NULL: the unwind starts for an inactive task with
     20 *    the sp picked up from task->thread.ksp and the ip picked up from the
     21 *    return address stored by __switch_to
     22 * 4) task!=NULL, regs!=NULL: the sp/ip are picked up from the interrupt
     23 *    frame 'regs' of a inactive task
     24 * If 'first_frame' is not zero unwind_start skips unwind frames until it
     25 * reaches the specified stack pointer.
     26 * The end of the unwinding is indicated with unwind_done, this can be true
     27 * right after unwind_start, e.g. with first_frame!=0 that can not be found.
     28 * unwind_next_frame skips to the next frame.
     29 * Once the unwind is completed unwind_error() can be used to check if there
     30 * has been a situation where the unwinder could not correctly understand
     31 * the tasks call chain.
     32 */
     33
     34struct unwind_state {
     35	struct stack_info stack_info;
     36	unsigned long stack_mask;
     37	struct task_struct *task;
     38	struct pt_regs *regs;
     39	unsigned long sp, ip;
     40	int graph_idx;
     41	struct llist_node *kr_cur;
     42	bool reliable;
     43	bool error;
     44};
     45
     46/* Recover the return address modified by kretprobe and ftrace_graph. */
     47static inline unsigned long unwind_recover_ret_addr(struct unwind_state *state,
     48						    unsigned long ip)
     49{
     50	ip = ftrace_graph_ret_addr(state->task, &state->graph_idx, ip, NULL);
     51	if (is_kretprobe_trampoline(ip))
     52		ip = kretprobe_find_ret_addr(state->task, (void *)state->sp, &state->kr_cur);
     53	return ip;
     54}
     55
     56void __unwind_start(struct unwind_state *state, struct task_struct *task,
     57		    struct pt_regs *regs, unsigned long first_frame);
     58bool unwind_next_frame(struct unwind_state *state);
     59unsigned long unwind_get_return_address(struct unwind_state *state);
     60
     61static inline bool unwind_done(struct unwind_state *state)
     62{
     63	return state->stack_info.type == STACK_TYPE_UNKNOWN;
     64}
     65
     66static inline bool unwind_error(struct unwind_state *state)
     67{
     68	return state->error;
     69}
     70
     71static __always_inline void unwind_start(struct unwind_state *state,
     72					 struct task_struct *task,
     73					 struct pt_regs *regs,
     74					 unsigned long first_frame)
     75{
     76	task = task ?: current;
     77	first_frame = first_frame ?: get_stack_pointer(task, regs);
     78	__unwind_start(state, task, regs, first_frame);
     79}
     80
     81static inline struct pt_regs *unwind_get_entry_regs(struct unwind_state *state)
     82{
     83	return unwind_done(state) ? NULL : state->regs;
     84}
     85
     86#define unwind_for_each_frame(state, task, regs, first_frame)	\
     87	for (unwind_start(state, task, regs, first_frame);	\
     88	     !unwind_done(state);				\
     89	     unwind_next_frame(state))
     90
     91static inline void unwind_init(void) {}
     92static inline void unwind_module_init(struct module *mod, void *orc_ip,
     93				      size_t orc_ip_size, void *orc,
     94				      size_t orc_size) {}
     95
     96#endif /* _ASM_S390_UNWIND_H */