xref: /openbmc/linux/arch/x86/kernel/dumpstack_32.c (revision cb76c93982404273d746f3ccd5085b47689099a8)
12bc5f927SAlexander van Heukelum /*
22bc5f927SAlexander van Heukelum  *  Copyright (C) 1991, 1992  Linus Torvalds
32bc5f927SAlexander van Heukelum  *  Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs
42bc5f927SAlexander van Heukelum  */
52bc5f927SAlexander van Heukelum #include <linux/kallsyms.h>
62bc5f927SAlexander van Heukelum #include <linux/kprobes.h>
72bc5f927SAlexander van Heukelum #include <linux/uaccess.h>
82bc5f927SAlexander van Heukelum #include <linux/hardirq.h>
92bc5f927SAlexander van Heukelum #include <linux/kdebug.h>
10186f4360SPaul Gortmaker #include <linux/export.h>
112bc5f927SAlexander van Heukelum #include <linux/ptrace.h>
122bc5f927SAlexander van Heukelum #include <linux/kexec.h>
13b8030906SIngo Molnar #include <linux/sysfs.h>
142bc5f927SAlexander van Heukelum #include <linux/bug.h>
152bc5f927SAlexander van Heukelum #include <linux/nmi.h>
162bc5f927SAlexander van Heukelum 
172bc5f927SAlexander van Heukelum #include <asm/stacktrace.h>
182bc5f927SAlexander van Heukelum 
19*cb76c939SJosh Poimboeuf void stack_type_str(enum stack_type type, const char **begin, const char **end)
20198d208dSSteven Rostedt {
21*cb76c939SJosh Poimboeuf 	switch (type) {
22*cb76c939SJosh Poimboeuf 	case STACK_TYPE_IRQ:
23*cb76c939SJosh Poimboeuf 	case STACK_TYPE_SOFTIRQ:
24*cb76c939SJosh Poimboeuf 		*begin = "IRQ";
25*cb76c939SJosh Poimboeuf 		*end   = "EOI";
26*cb76c939SJosh Poimboeuf 		break;
27*cb76c939SJosh Poimboeuf 	default:
28*cb76c939SJosh Poimboeuf 		*begin = NULL;
29*cb76c939SJosh Poimboeuf 		*end   = NULL;
30*cb76c939SJosh Poimboeuf 	}
31198d208dSSteven Rostedt }
32198d208dSSteven Rostedt 
33*cb76c939SJosh Poimboeuf static bool in_hardirq_stack(unsigned long *stack, struct stack_info *info)
34198d208dSSteven Rostedt {
35*cb76c939SJosh Poimboeuf 	unsigned long *begin = (unsigned long *)this_cpu_read(hardirq_stack);
36*cb76c939SJosh Poimboeuf 	unsigned long *end   = begin + (THREAD_SIZE / sizeof(long));
37198d208dSSteven Rostedt 
38*cb76c939SJosh Poimboeuf 	if (stack < begin || stack >= end)
39*cb76c939SJosh Poimboeuf 		return false;
40*cb76c939SJosh Poimboeuf 
41*cb76c939SJosh Poimboeuf 	info->type	= STACK_TYPE_IRQ;
42*cb76c939SJosh Poimboeuf 	info->begin	= begin;
43*cb76c939SJosh Poimboeuf 	info->end	= end;
44*cb76c939SJosh Poimboeuf 
45*cb76c939SJosh Poimboeuf 	/*
46*cb76c939SJosh Poimboeuf 	 * See irq_32.c -- the next stack pointer is stored at the beginning of
47*cb76c939SJosh Poimboeuf 	 * the stack.
48*cb76c939SJosh Poimboeuf 	 */
49*cb76c939SJosh Poimboeuf 	info->next_sp	= (unsigned long *)*begin;
50*cb76c939SJosh Poimboeuf 
51*cb76c939SJosh Poimboeuf 	return true;
52198d208dSSteven Rostedt }
53198d208dSSteven Rostedt 
54*cb76c939SJosh Poimboeuf static bool in_softirq_stack(unsigned long *stack, struct stack_info *info)
55198d208dSSteven Rostedt {
56*cb76c939SJosh Poimboeuf 	unsigned long *begin = (unsigned long *)this_cpu_read(softirq_stack);
57*cb76c939SJosh Poimboeuf 	unsigned long *end   = begin + (THREAD_SIZE / sizeof(long));
58198d208dSSteven Rostedt 
59*cb76c939SJosh Poimboeuf 	if (stack < begin || stack >= end)
60*cb76c939SJosh Poimboeuf 		return false;
61*cb76c939SJosh Poimboeuf 
62*cb76c939SJosh Poimboeuf 	info->type	= STACK_TYPE_SOFTIRQ;
63*cb76c939SJosh Poimboeuf 	info->begin	= begin;
64*cb76c939SJosh Poimboeuf 	info->end	= end;
65*cb76c939SJosh Poimboeuf 
66*cb76c939SJosh Poimboeuf 	/*
67*cb76c939SJosh Poimboeuf 	 * The next stack pointer is stored at the beginning of the stack.
68*cb76c939SJosh Poimboeuf 	 * See irq_32.c.
69*cb76c939SJosh Poimboeuf 	 */
70*cb76c939SJosh Poimboeuf 	info->next_sp	= (unsigned long *)*begin;
71*cb76c939SJosh Poimboeuf 
72*cb76c939SJosh Poimboeuf 	return true;
73*cb76c939SJosh Poimboeuf }
74*cb76c939SJosh Poimboeuf 
75*cb76c939SJosh Poimboeuf int get_stack_info(unsigned long *stack, struct task_struct *task,
76*cb76c939SJosh Poimboeuf 		   struct stack_info *info, unsigned long *visit_mask)
77*cb76c939SJosh Poimboeuf {
78*cb76c939SJosh Poimboeuf 	if (!stack)
79*cb76c939SJosh Poimboeuf 		goto unknown;
80*cb76c939SJosh Poimboeuf 
81*cb76c939SJosh Poimboeuf 	task = task ? : current;
82*cb76c939SJosh Poimboeuf 
83*cb76c939SJosh Poimboeuf 	if (in_task_stack(stack, task, info))
84*cb76c939SJosh Poimboeuf 		return 0;
85*cb76c939SJosh Poimboeuf 
86*cb76c939SJosh Poimboeuf 	if (task != current)
87*cb76c939SJosh Poimboeuf 		goto unknown;
88*cb76c939SJosh Poimboeuf 
89*cb76c939SJosh Poimboeuf 	if (in_hardirq_stack(stack, info))
90*cb76c939SJosh Poimboeuf 		return 0;
91*cb76c939SJosh Poimboeuf 
92*cb76c939SJosh Poimboeuf 	if (in_softirq_stack(stack, info))
93*cb76c939SJosh Poimboeuf 		return 0;
94*cb76c939SJosh Poimboeuf 
95*cb76c939SJosh Poimboeuf unknown:
96*cb76c939SJosh Poimboeuf 	info->type = STACK_TYPE_UNKNOWN;
97*cb76c939SJosh Poimboeuf 	return -EINVAL;
98198d208dSSteven Rostedt }
990406ca6dSFrederic Weisbecker 
100e8e999cfSNamhyung Kim void dump_trace(struct task_struct *task, struct pt_regs *regs,
101e8e999cfSNamhyung Kim 		unsigned long *stack, unsigned long bp,
1022bc5f927SAlexander van Heukelum 		const struct stacktrace_ops *ops, void *data)
1032bc5f927SAlexander van Heukelum {
104*cb76c939SJosh Poimboeuf 	unsigned long visit_mask = 0;
1057ee991fbSSteven Rostedt 	int graph = 0;
1067ee991fbSSteven Rostedt 
1074b8afafbSJosh Poimboeuf 	task = task ? : current;
1084b8afafbSJosh Poimboeuf 	stack = stack ? : get_stack_pointer(task, regs);
1094b8afafbSJosh Poimboeuf 	bp = bp ? : (unsigned long)get_frame_pointer(task, regs);
110e8e999cfSNamhyung Kim 
1112bc5f927SAlexander van Heukelum 	for (;;) {
112*cb76c939SJosh Poimboeuf 		const char *begin_str, *end_str;
113*cb76c939SJosh Poimboeuf 		struct stack_info info;
1142bc5f927SAlexander van Heukelum 
115*cb76c939SJosh Poimboeuf 		if (get_stack_info(stack, task, &info, &visit_mask))
1160788aa6aSSteven Rostedt 			break;
1170788aa6aSSteven Rostedt 
118*cb76c939SJosh Poimboeuf 		stack_type_str(info.type, &begin_str, &end_str);
119*cb76c939SJosh Poimboeuf 
120*cb76c939SJosh Poimboeuf 		if (begin_str && ops->stack(data, begin_str) < 0)
1212bc5f927SAlexander van Heukelum 			break;
1220788aa6aSSteven Rostedt 
123*cb76c939SJosh Poimboeuf 		bp = ops->walk_stack(task, stack, bp, ops, data, &info, &graph);
124*cb76c939SJosh Poimboeuf 
125*cb76c939SJosh Poimboeuf 		if (end_str && ops->stack(data, end_str) < 0)
1262ac53721SAlexander van Heukelum 			break;
127*cb76c939SJosh Poimboeuf 
128*cb76c939SJosh Poimboeuf 		stack = info.next_sp;
129*cb76c939SJosh Poimboeuf 
1302bc5f927SAlexander van Heukelum 		touch_nmi_watchdog();
1312bc5f927SAlexander van Heukelum 	}
1322bc5f927SAlexander van Heukelum }
1332bc5f927SAlexander van Heukelum EXPORT_SYMBOL(dump_trace);
1342bc5f927SAlexander van Heukelum 
135878719e8SNeil Horman void
1362bc5f927SAlexander van Heukelum show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
137e8e999cfSNamhyung Kim 		   unsigned long *sp, unsigned long bp, char *log_lvl)
1382bc5f927SAlexander van Heukelum {
1392bc5f927SAlexander van Heukelum 	unsigned long *stack;
1402bc5f927SAlexander van Heukelum 	int i;
1412bc5f927SAlexander van Heukelum 
1424b8afafbSJosh Poimboeuf 	sp = sp ? : get_stack_pointer(task, regs);
1432bc5f927SAlexander van Heukelum 
1442bc5f927SAlexander van Heukelum 	stack = sp;
1452bc5f927SAlexander van Heukelum 	for (i = 0; i < kstack_depth_to_print; i++) {
1462bc5f927SAlexander van Heukelum 		if (kstack_end(stack))
1472bc5f927SAlexander van Heukelum 			break;
1481fc7f61cSAdrien Schildknecht 		if ((i % STACKSLOTS_PER_LINE) == 0) {
1491fc7f61cSAdrien Schildknecht 			if (i != 0)
150c767a54bSJoe Perches 				pr_cont("\n");
1511fc7f61cSAdrien Schildknecht 			printk("%s %08lx", log_lvl, *stack++);
1521fc7f61cSAdrien Schildknecht 		} else
153c767a54bSJoe Perches 			pr_cont(" %08lx", *stack++);
154ca0a8164SAlexander van Heukelum 		touch_nmi_watchdog();
1552bc5f927SAlexander van Heukelum 	}
156c767a54bSJoe Perches 	pr_cont("\n");
157e8e999cfSNamhyung Kim 	show_trace_log_lvl(task, regs, sp, bp, log_lvl);
1582bc5f927SAlexander van Heukelum }
1592bc5f927SAlexander van Heukelum 
1602bc5f927SAlexander van Heukelum 
16157da8b96SJan Beulich void show_regs(struct pt_regs *regs)
1622bc5f927SAlexander van Heukelum {
1632bc5f927SAlexander van Heukelum 	int i;
1642bc5f927SAlexander van Heukelum 
165a43cb95dSTejun Heo 	show_regs_print_info(KERN_EMERG);
166f39b6f0eSAndy Lutomirski 	__show_regs(regs, !user_mode(regs));
1672bc5f927SAlexander van Heukelum 
1682bc5f927SAlexander van Heukelum 	/*
1692bc5f927SAlexander van Heukelum 	 * When in-kernel, we also print out the stack and code at the
1702bc5f927SAlexander van Heukelum 	 * time of the fault..
1712bc5f927SAlexander van Heukelum 	 */
172f39b6f0eSAndy Lutomirski 	if (!user_mode(regs)) {
1732bc5f927SAlexander van Heukelum 		unsigned int code_prologue = code_bytes * 43 / 64;
1742bc5f927SAlexander van Heukelum 		unsigned int code_len = code_bytes;
1752bc5f927SAlexander van Heukelum 		unsigned char c;
1762bc5f927SAlexander van Heukelum 		u8 *ip;
1772bc5f927SAlexander van Heukelum 
178c767a54bSJoe Perches 		pr_emerg("Stack:\n");
1795a8ff54cSJosh Poimboeuf 		show_stack_log_lvl(NULL, regs, NULL, 0, KERN_EMERG);
1802bc5f927SAlexander van Heukelum 
181c767a54bSJoe Perches 		pr_emerg("Code:");
1822bc5f927SAlexander van Heukelum 
1832bc5f927SAlexander van Heukelum 		ip = (u8 *)regs->ip - code_prologue;
1842bc5f927SAlexander van Heukelum 		if (ip < (u8 *)PAGE_OFFSET || probe_kernel_address(ip, c)) {
1858a541665SAlexander van Heukelum 			/* try starting at IP */
1862bc5f927SAlexander van Heukelum 			ip = (u8 *)regs->ip;
1872bc5f927SAlexander van Heukelum 			code_len = code_len - code_prologue + 1;
1882bc5f927SAlexander van Heukelum 		}
1892bc5f927SAlexander van Heukelum 		for (i = 0; i < code_len; i++, ip++) {
1902bc5f927SAlexander van Heukelum 			if (ip < (u8 *)PAGE_OFFSET ||
1912bc5f927SAlexander van Heukelum 					probe_kernel_address(ip, c)) {
192c767a54bSJoe Perches 				pr_cont("  Bad EIP value.");
1932bc5f927SAlexander van Heukelum 				break;
1942bc5f927SAlexander van Heukelum 			}
1952bc5f927SAlexander van Heukelum 			if (ip == (u8 *)regs->ip)
196c767a54bSJoe Perches 				pr_cont(" <%02x>", c);
1972bc5f927SAlexander van Heukelum 			else
198c767a54bSJoe Perches 				pr_cont(" %02x", c);
1992bc5f927SAlexander van Heukelum 		}
2002bc5f927SAlexander van Heukelum 	}
201c767a54bSJoe Perches 	pr_cont("\n");
2022bc5f927SAlexander van Heukelum }
2032bc5f927SAlexander van Heukelum 
2042bc5f927SAlexander van Heukelum int is_valid_bugaddr(unsigned long ip)
2052bc5f927SAlexander van Heukelum {
2062bc5f927SAlexander van Heukelum 	unsigned short ud2;
2072bc5f927SAlexander van Heukelum 
2082bc5f927SAlexander van Heukelum 	if (ip < PAGE_OFFSET)
2092bc5f927SAlexander van Heukelum 		return 0;
2102bc5f927SAlexander van Heukelum 	if (probe_kernel_address((unsigned short *)ip, ud2))
2112bc5f927SAlexander van Heukelum 		return 0;
2122bc5f927SAlexander van Heukelum 
2132bc5f927SAlexander van Heukelum 	return ud2 == 0x0b0f;
2142bc5f927SAlexander van Heukelum }
215