xref: /linux-6.15/arch/x86/kernel/dumpstack_32.c (revision 5a8ff54c)
1 /*
2  *  Copyright (C) 1991, 1992  Linus Torvalds
3  *  Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs
4  */
5 #include <linux/kallsyms.h>
6 #include <linux/kprobes.h>
7 #include <linux/uaccess.h>
8 #include <linux/hardirq.h>
9 #include <linux/kdebug.h>
10 #include <linux/export.h>
11 #include <linux/ptrace.h>
12 #include <linux/kexec.h>
13 #include <linux/sysfs.h>
14 #include <linux/bug.h>
15 #include <linux/nmi.h>
16 
17 #include <asm/stacktrace.h>
18 
19 static void *is_irq_stack(void *p, void *irq)
20 {
21 	if (p < irq || p >= (irq + THREAD_SIZE))
22 		return NULL;
23 	return irq + THREAD_SIZE;
24 }
25 
26 
27 static void *is_hardirq_stack(unsigned long *stack, int cpu)
28 {
29 	void *irq = per_cpu(hardirq_stack, cpu);
30 
31 	return is_irq_stack(stack, irq);
32 }
33 
34 static void *is_softirq_stack(unsigned long *stack, int cpu)
35 {
36 	void *irq = per_cpu(softirq_stack, cpu);
37 
38 	return is_irq_stack(stack, irq);
39 }
40 
41 void dump_trace(struct task_struct *task, struct pt_regs *regs,
42 		unsigned long *stack, unsigned long bp,
43 		const struct stacktrace_ops *ops, void *data)
44 {
45 	const unsigned cpu = get_cpu();
46 	int graph = 0;
47 	u32 *prev_esp;
48 
49 	task = task ? : current;
50 	stack = stack ? : get_stack_pointer(task, regs);
51 	bp = bp ? : (unsigned long)get_frame_pointer(task, regs);
52 
53 	for (;;) {
54 		void *end_stack;
55 
56 		end_stack = is_hardirq_stack(stack, cpu);
57 		if (!end_stack)
58 			end_stack = is_softirq_stack(stack, cpu);
59 
60 		bp = ops->walk_stack(task, stack, bp, ops, data,
61 				     end_stack, &graph);
62 
63 		/* Stop if not on irq stack */
64 		if (!end_stack)
65 			break;
66 
67 		/* The previous esp is saved on the bottom of the stack */
68 		prev_esp = (u32 *)(end_stack - THREAD_SIZE);
69 		stack = (unsigned long *)*prev_esp;
70 		if (!stack)
71 			break;
72 
73 		if (ops->stack(data, "IRQ") < 0)
74 			break;
75 		touch_nmi_watchdog();
76 	}
77 	put_cpu();
78 }
79 EXPORT_SYMBOL(dump_trace);
80 
81 void
82 show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
83 		   unsigned long *sp, unsigned long bp, char *log_lvl)
84 {
85 	unsigned long *stack;
86 	int i;
87 
88 	sp = sp ? : get_stack_pointer(task, regs);
89 
90 	stack = sp;
91 	for (i = 0; i < kstack_depth_to_print; i++) {
92 		if (kstack_end(stack))
93 			break;
94 		if ((i % STACKSLOTS_PER_LINE) == 0) {
95 			if (i != 0)
96 				pr_cont("\n");
97 			printk("%s %08lx", log_lvl, *stack++);
98 		} else
99 			pr_cont(" %08lx", *stack++);
100 		touch_nmi_watchdog();
101 	}
102 	pr_cont("\n");
103 	show_trace_log_lvl(task, regs, sp, bp, log_lvl);
104 }
105 
106 
107 void show_regs(struct pt_regs *regs)
108 {
109 	int i;
110 
111 	show_regs_print_info(KERN_EMERG);
112 	__show_regs(regs, !user_mode(regs));
113 
114 	/*
115 	 * When in-kernel, we also print out the stack and code at the
116 	 * time of the fault..
117 	 */
118 	if (!user_mode(regs)) {
119 		unsigned int code_prologue = code_bytes * 43 / 64;
120 		unsigned int code_len = code_bytes;
121 		unsigned char c;
122 		u8 *ip;
123 
124 		pr_emerg("Stack:\n");
125 		show_stack_log_lvl(NULL, regs, NULL, 0, KERN_EMERG);
126 
127 		pr_emerg("Code:");
128 
129 		ip = (u8 *)regs->ip - code_prologue;
130 		if (ip < (u8 *)PAGE_OFFSET || probe_kernel_address(ip, c)) {
131 			/* try starting at IP */
132 			ip = (u8 *)regs->ip;
133 			code_len = code_len - code_prologue + 1;
134 		}
135 		for (i = 0; i < code_len; i++, ip++) {
136 			if (ip < (u8 *)PAGE_OFFSET ||
137 					probe_kernel_address(ip, c)) {
138 				pr_cont("  Bad EIP value.");
139 				break;
140 			}
141 			if (ip == (u8 *)regs->ip)
142 				pr_cont(" <%02x>", c);
143 			else
144 				pr_cont(" %02x", c);
145 		}
146 	}
147 	pr_cont("\n");
148 }
149 
150 int is_valid_bugaddr(unsigned long ip)
151 {
152 	unsigned short ud2;
153 
154 	if (ip < PAGE_OFFSET)
155 		return 0;
156 	if (probe_kernel_address((unsigned short *)ip, ud2))
157 		return 0;
158 
159 	return ud2 == 0x0b0f;
160 }
161