linux/arch/s390/include/asm/stacktrace.h
<<
>>
Prefs
   1/* SPDX-License-Identifier: GPL-2.0 */
   2#ifndef _ASM_S390_STACKTRACE_H
   3#define _ASM_S390_STACKTRACE_H
   4
   5#include <linux/uaccess.h>
   6#include <linux/ptrace.h>
   7#include <asm/switch_to.h>
   8
   9enum stack_type {
  10        STACK_TYPE_UNKNOWN,
  11        STACK_TYPE_TASK,
  12        STACK_TYPE_IRQ,
  13        STACK_TYPE_NODAT,
  14        STACK_TYPE_RESTART,
  15        STACK_TYPE_MCCK,
  16};
  17
  18struct stack_info {
  19        enum stack_type type;
  20        unsigned long begin, end;
  21};
  22
  23const char *stack_type_name(enum stack_type type);
  24int get_stack_info(unsigned long sp, struct task_struct *task,
  25                   struct stack_info *info, unsigned long *visit_mask);
  26
  27static inline bool on_stack(struct stack_info *info,
  28                            unsigned long addr, size_t len)
  29{
  30        if (info->type == STACK_TYPE_UNKNOWN)
  31                return false;
  32        if (addr + len < addr)
  33                return false;
  34        return addr >= info->begin && addr + len <= info->end;
  35}
  36
  37static __always_inline unsigned long get_stack_pointer(struct task_struct *task,
  38                                                       struct pt_regs *regs)
  39{
  40        if (regs)
  41                return (unsigned long) kernel_stack_pointer(regs);
  42        if (task == current)
  43                return current_stack_pointer();
  44        return (unsigned long) task->thread.ksp;
  45}
  46
  47/*
  48 * Stack layout of a C stack frame.
  49 */
  50#ifndef __PACK_STACK
  51struct stack_frame {
  52        unsigned long back_chain;
  53        unsigned long empty1[5];
  54        unsigned long gprs[10];
  55        unsigned int  empty2[8];
  56};
  57#else
  58struct stack_frame {
  59        unsigned long empty1[5];
  60        unsigned int  empty2[8];
  61        unsigned long gprs[10];
  62        unsigned long back_chain;
  63};
  64#endif
  65
  66/*
  67 * Unlike current_stack_pointer() which simply returns current value of %r15
  68 * current_frame_address() returns function stack frame address, which matches
  69 * %r15 upon function invocation. It may differ from %r15 later if function
  70 * allocates stack for local variables or new stack frame to call other
  71 * functions.
  72 */
  73#define current_frame_address()                                         \
  74        ((unsigned long)__builtin_frame_address(0) -                    \
  75         offsetof(struct stack_frame, back_chain))
  76
  77#define CALL_ARGS_0()                                                   \
  78        register unsigned long r2 asm("2")
  79#define CALL_ARGS_1(arg1)                                               \
  80        register unsigned long r2 asm("2") = (unsigned long)(arg1)
  81#define CALL_ARGS_2(arg1, arg2)                                         \
  82        CALL_ARGS_1(arg1);                                              \
  83        register unsigned long r3 asm("3") = (unsigned long)(arg2)
  84#define CALL_ARGS_3(arg1, arg2, arg3)                                   \
  85        CALL_ARGS_2(arg1, arg2);                                        \
  86        register unsigned long r4 asm("4") = (unsigned long)(arg3)
  87#define CALL_ARGS_4(arg1, arg2, arg3, arg4)                             \
  88        CALL_ARGS_3(arg1, arg2, arg3);                                  \
  89        register unsigned long r4 asm("5") = (unsigned long)(arg4)
  90#define CALL_ARGS_5(arg1, arg2, arg3, arg4, arg5)                       \
  91        CALL_ARGS_4(arg1, arg2, arg3, arg4);                            \
  92        register unsigned long r4 asm("6") = (unsigned long)(arg5)
  93
  94/*
  95 * To keep this simple mark register 2-6 as being changed (volatile)
  96 * by the called function, even though register 6 is saved/nonvolatile.
  97 */
  98#define CALL_FMT_0 "=&d" (r2)
  99#define CALL_FMT_1 "+&d" (r2)
 100#define CALL_FMT_2 CALL_FMT_1, "+&d" (r3)
 101#define CALL_FMT_3 CALL_FMT_2, "+&d" (r4)
 102#define CALL_FMT_4 CALL_FMT_3, "+&d" (r5)
 103#define CALL_FMT_5 CALL_FMT_4, "+&d" (r6)
 104
 105#define CALL_CLOBBER_5 "0", "1", "14", "cc", "memory"
 106#define CALL_CLOBBER_4 CALL_CLOBBER_5
 107#define CALL_CLOBBER_3 CALL_CLOBBER_4, "5"
 108#define CALL_CLOBBER_2 CALL_CLOBBER_3, "4"
 109#define CALL_CLOBBER_1 CALL_CLOBBER_2, "3"
 110#define CALL_CLOBBER_0 CALL_CLOBBER_1
 111
 112#define CALL_ON_STACK(fn, stack, nr, args...)                           \
 113({                                                                      \
 114        unsigned long frame = current_frame_address();                  \
 115        CALL_ARGS_##nr(args);                                           \
 116        unsigned long prev;                                             \
 117                                                                        \
 118        asm volatile(                                                   \
 119                "       la      %[_prev],0(15)\n"                       \
 120                "       lg      15,%[_stack]\n"                         \
 121                "       stg     %[_frame],%[_bc](15)\n"                 \
 122                "       brasl   14,%[_fn]\n"                            \
 123                "       la      15,0(%[_prev])\n"                       \
 124                : [_prev] "=&a" (prev), CALL_FMT_##nr                   \
 125                : [_stack] "R" (stack),                                 \
 126                  [_bc] "i" (offsetof(struct stack_frame, back_chain)), \
 127                  [_frame] "d" (frame),                                 \
 128                  [_fn] "X" (fn) : CALL_CLOBBER_##nr);                  \
 129        r2;                                                             \
 130})
 131
 132#define CALL_ON_STACK_NORETURN(fn, stack)                               \
 133({                                                                      \
 134        asm volatile(                                                   \
 135                "       la      15,0(%[_stack])\n"                      \
 136                "       xc      %[_bc](8,15),%[_bc](15)\n"              \
 137                "       brasl   14,%[_fn]\n"                            \
 138                ::[_bc] "i" (offsetof(struct stack_frame, back_chain)), \
 139                  [_stack] "a" (stack), [_fn] "X" (fn));                \
 140        BUG();                                                          \
 141})
 142
 143#endif /* _ASM_S390_STACKTRACE_H */
 144