1 | /* SPDX-License-Identifier: GPL-2.0 */ |
2 | /* |
3 | * Copyright (C) 1991, 1992 Linus Torvalds |
4 | * Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs |
5 | */ |
6 | |
7 | #ifndef _ASM_X86_STACKTRACE_H |
8 | #define _ASM_X86_STACKTRACE_H |
9 | |
10 | #include <linux/uaccess.h> |
11 | #include <linux/ptrace.h> |
12 | |
13 | #include <asm/cpu_entry_area.h> |
14 | #include <asm/switch_to.h> |
15 | |
16 | enum stack_type { |
17 | STACK_TYPE_UNKNOWN, |
18 | STACK_TYPE_TASK, |
19 | STACK_TYPE_IRQ, |
20 | STACK_TYPE_SOFTIRQ, |
21 | STACK_TYPE_ENTRY, |
22 | STACK_TYPE_EXCEPTION, |
23 | STACK_TYPE_EXCEPTION_LAST = STACK_TYPE_EXCEPTION + N_EXCEPTION_STACKS-1, |
24 | }; |
25 | |
26 | struct stack_info { |
27 | enum stack_type type; |
28 | unsigned long *begin, *end, *next_sp; |
29 | }; |
30 | |
31 | bool in_task_stack(unsigned long *stack, struct task_struct *task, |
32 | struct stack_info *info); |
33 | |
34 | bool in_entry_stack(unsigned long *stack, struct stack_info *info); |
35 | |
36 | int get_stack_info(unsigned long *stack, struct task_struct *task, |
37 | struct stack_info *info, unsigned long *visit_mask); |
38 | bool get_stack_info_noinstr(unsigned long *stack, struct task_struct *task, |
39 | struct stack_info *info); |
40 | |
41 | static __always_inline |
42 | bool get_stack_guard_info(unsigned long *stack, struct stack_info *info) |
43 | { |
44 | /* make sure it's not in the stack proper */ |
45 | if (get_stack_info_noinstr(stack, current, info)) |
46 | return false; |
47 | /* but if it is in the page below it, we hit a guard */ |
48 | return get_stack_info_noinstr(stack: (void *)stack + PAGE_SIZE, current, info); |
49 | } |
50 | |
51 | const char *stack_type_name(enum stack_type type); |
52 | |
53 | static inline bool on_stack(struct stack_info *info, void *addr, size_t len) |
54 | { |
55 | void *begin = info->begin; |
56 | void *end = info->end; |
57 | |
58 | return (info->type != STACK_TYPE_UNKNOWN && |
59 | addr >= begin && addr < end && |
60 | addr + len > begin && addr + len <= end); |
61 | } |
62 | |
63 | #ifdef CONFIG_X86_32 |
64 | #define STACKSLOTS_PER_LINE 8 |
65 | #else |
66 | #define STACKSLOTS_PER_LINE 4 |
67 | #endif |
68 | |
69 | #ifdef CONFIG_FRAME_POINTER |
70 | static inline unsigned long * |
71 | get_frame_pointer(struct task_struct *task, struct pt_regs *regs) |
72 | { |
73 | if (regs) |
74 | return (unsigned long *)regs->bp; |
75 | |
76 | if (task == current) |
77 | return __builtin_frame_address(0); |
78 | |
79 | return &((struct inactive_task_frame *)task->thread.sp)->bp; |
80 | } |
81 | #else |
82 | static inline unsigned long * |
83 | get_frame_pointer(struct task_struct *task, struct pt_regs *regs) |
84 | { |
85 | return NULL; |
86 | } |
87 | #endif /* CONFIG_FRAME_POINTER */ |
88 | |
89 | static inline unsigned long * |
90 | get_stack_pointer(struct task_struct *task, struct pt_regs *regs) |
91 | { |
92 | if (regs) |
93 | return (unsigned long *)regs->sp; |
94 | |
95 | if (task == current) |
96 | return __builtin_frame_address(0); |
97 | |
98 | return (unsigned long *)task->thread.sp; |
99 | } |
100 | |
101 | /* The form of the top of the frame on the stack */ |
102 | struct stack_frame { |
103 | struct stack_frame *next_frame; |
104 | unsigned long return_address; |
105 | }; |
106 | |
107 | struct stack_frame_ia32 { |
108 | u32 next_frame; |
109 | u32 return_address; |
110 | }; |
111 | |
112 | void show_opcodes(struct pt_regs *regs, const char *loglvl); |
113 | void show_ip(struct pt_regs *regs, const char *loglvl); |
114 | #endif /* _ASM_X86_STACKTRACE_H */ |
115 | |