xref: /linux/arch/x86/include/asm/stacktrace.h (revision 03ab8e6297acd1bc0eedaa050e2a1635c576fd11)
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