1b2441318SGreg Kroah-Hartman /* SPDX-License-Identifier: GPL-2.0 */
2c9cf4dbbSFrederic Weisbecker /*
3c9cf4dbbSFrederic Weisbecker * Copyright (C) 1991, 1992 Linus Torvalds
4c9cf4dbbSFrederic Weisbecker * Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs
5c9cf4dbbSFrederic Weisbecker */
6c9cf4dbbSFrederic Weisbecker
71965aae3SH. Peter Anvin #ifndef _ASM_X86_STACKTRACE_H
81965aae3SH. Peter Anvin #define _ASM_X86_STACKTRACE_H
9bb898558SAl Viro
10c9cf4dbbSFrederic Weisbecker #include <linux/uaccess.h>
119c0729dcSSoeren Sandmann Pedersen #include <linux/ptrace.h>
1232074269SThomas Gleixner
1332074269SThomas Gleixner #include <asm/cpu_entry_area.h>
147b32aeadSBrian Gerst #include <asm/switch_to.h>
15c9cf4dbbSFrederic Weisbecker
16cb76c939SJosh Poimboeuf enum stack_type {
17cb76c939SJosh Poimboeuf STACK_TYPE_UNKNOWN,
18cb76c939SJosh Poimboeuf STACK_TYPE_TASK,
19cb76c939SJosh Poimboeuf STACK_TYPE_IRQ,
20cb76c939SJosh Poimboeuf STACK_TYPE_SOFTIRQ,
214fe2d8b1SDave Hansen STACK_TYPE_ENTRY,
22cb76c939SJosh Poimboeuf STACK_TYPE_EXCEPTION,
23cb76c939SJosh Poimboeuf STACK_TYPE_EXCEPTION_LAST = STACK_TYPE_EXCEPTION + N_EXCEPTION_STACKS-1,
24cb76c939SJosh Poimboeuf };
25cb76c939SJosh Poimboeuf
26cb76c939SJosh Poimboeuf struct stack_info {
27cb76c939SJosh Poimboeuf enum stack_type type;
28cb76c939SJosh Poimboeuf unsigned long *begin, *end, *next_sp;
29cb76c939SJosh Poimboeuf };
30cb76c939SJosh Poimboeuf
31cb76c939SJosh Poimboeuf bool in_task_stack(unsigned long *stack, struct task_struct *task,
32cb76c939SJosh Poimboeuf struct stack_info *info);
33cb76c939SJosh Poimboeuf
344fe2d8b1SDave Hansen bool in_entry_stack(unsigned long *stack, struct stack_info *info);
3533a2f1a6SAndy Lutomirski
36cb76c939SJosh Poimboeuf int get_stack_info(unsigned long *stack, struct task_struct *task,
37cb76c939SJosh Poimboeuf struct stack_info *info, unsigned long *visit_mask);
386b27edd7SJoerg Roedel bool get_stack_info_noinstr(unsigned long *stack, struct task_struct *task,
396b27edd7SJoerg Roedel struct stack_info *info);
40cb76c939SJosh Poimboeuf
41*44b979faSPeter Zijlstra static __always_inline
get_stack_guard_info(unsigned long * stack,struct stack_info * info)42*44b979faSPeter Zijlstra bool get_stack_guard_info(unsigned long *stack, struct stack_info *info)
43*44b979faSPeter Zijlstra {
44*44b979faSPeter Zijlstra /* make sure it's not in the stack proper */
45*44b979faSPeter Zijlstra if (get_stack_info_noinstr(stack, current, info))
46*44b979faSPeter Zijlstra return false;
47*44b979faSPeter Zijlstra /* but if it is in the page below it, we hit a guard */
48*44b979faSPeter Zijlstra return get_stack_info_noinstr((void *)stack + PAGE_SIZE, current, info);
49*44b979faSPeter Zijlstra }
50*44b979faSPeter Zijlstra
513d02a9c4SJosh Poimboeuf const char *stack_type_name(enum stack_type type);
52cb76c939SJosh Poimboeuf
on_stack(struct stack_info * info,void * addr,size_t len)53cb76c939SJosh Poimboeuf static inline bool on_stack(struct stack_info *info, void *addr, size_t len)
54cb76c939SJosh Poimboeuf {
55cb76c939SJosh Poimboeuf void *begin = info->begin;
56cb76c939SJosh Poimboeuf void *end = info->end;
57cb76c939SJosh Poimboeuf
58cb76c939SJosh Poimboeuf return (info->type != STACK_TYPE_UNKNOWN &&
59cb76c939SJosh Poimboeuf addr >= begin && addr < end &&
60cb76c939SJosh Poimboeuf addr + len > begin && addr + len <= end);
61cb76c939SJosh Poimboeuf }
62cb76c939SJosh Poimboeuf
63c9cf4dbbSFrederic Weisbecker #ifdef CONFIG_X86_32
64c9cf4dbbSFrederic Weisbecker #define STACKSLOTS_PER_LINE 8
65c9cf4dbbSFrederic Weisbecker #else
66c9cf4dbbSFrederic Weisbecker #define STACKSLOTS_PER_LINE 4
67c9cf4dbbSFrederic Weisbecker #endif
68c9cf4dbbSFrederic Weisbecker
699c0729dcSSoeren Sandmann Pedersen #ifdef CONFIG_FRAME_POINTER
704b8afafbSJosh Poimboeuf static inline unsigned long *
get_frame_pointer(struct task_struct * task,struct pt_regs * regs)714b8afafbSJosh Poimboeuf get_frame_pointer(struct task_struct *task, struct pt_regs *regs)
729c0729dcSSoeren Sandmann Pedersen {
739c0729dcSSoeren Sandmann Pedersen if (regs)
744b8afafbSJosh Poimboeuf return (unsigned long *)regs->bp;
759c0729dcSSoeren Sandmann Pedersen
7681539169SJosh Poimboeuf if (task == current)
774b8afafbSJosh Poimboeuf return __builtin_frame_address(0);
789c0729dcSSoeren Sandmann Pedersen
792c96b2feSJosh Poimboeuf return &((struct inactive_task_frame *)task->thread.sp)->bp;
809c0729dcSSoeren Sandmann Pedersen }
819c0729dcSSoeren Sandmann Pedersen #else
824b8afafbSJosh Poimboeuf static inline unsigned long *
get_frame_pointer(struct task_struct * task,struct pt_regs * regs)834b8afafbSJosh Poimboeuf get_frame_pointer(struct task_struct *task, struct pt_regs *regs)
849c0729dcSSoeren Sandmann Pedersen {
854b8afafbSJosh Poimboeuf return NULL;
869c0729dcSSoeren Sandmann Pedersen }
874b8afafbSJosh Poimboeuf #endif /* CONFIG_FRAME_POINTER */
884b8afafbSJosh Poimboeuf
894b8afafbSJosh Poimboeuf static inline unsigned long *
get_stack_pointer(struct task_struct * task,struct pt_regs * regs)904b8afafbSJosh Poimboeuf get_stack_pointer(struct task_struct *task, struct pt_regs *regs)
914b8afafbSJosh Poimboeuf {
924b8afafbSJosh Poimboeuf if (regs)
933c88c692SPeter Zijlstra return (unsigned long *)regs->sp;
944b8afafbSJosh Poimboeuf
9581539169SJosh Poimboeuf if (task == current)
964b8afafbSJosh Poimboeuf return __builtin_frame_address(0);
974b8afafbSJosh Poimboeuf
984b8afafbSJosh Poimboeuf return (unsigned long *)task->thread.sp;
994b8afafbSJosh Poimboeuf }
1009c0729dcSSoeren Sandmann Pedersen
101c9cf4dbbSFrederic Weisbecker /* The form of the top of the frame on the stack */
102c9cf4dbbSFrederic Weisbecker struct stack_frame {
103c9cf4dbbSFrederic Weisbecker struct stack_frame *next_frame;
104c9cf4dbbSFrederic Weisbecker unsigned long return_address;
105c9cf4dbbSFrederic Weisbecker };
106c9cf4dbbSFrederic Weisbecker
107c9cf4dbbSFrederic Weisbecker struct stack_frame_ia32 {
108c9cf4dbbSFrederic Weisbecker u32 next_frame;
109c9cf4dbbSFrederic Weisbecker u32 return_address;
110c9cf4dbbSFrederic Weisbecker };
111c9cf4dbbSFrederic Weisbecker
112342db04aSJann Horn void show_opcodes(struct pt_regs *regs, const char *loglvl);
1137cccf072SBorislav Petkov void show_ip(struct pt_regs *regs, const char *loglvl);
1141965aae3SH. Peter Anvin #endif /* _ASM_X86_STACKTRACE_H */
115