]>
Commit | Line | Data |
---|---|---|
2bc5f927 AH |
1 | /* |
2 | * Copyright (C) 1991, 1992 Linus Torvalds | |
3 | * Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs | |
4 | */ | |
b17b0153 | 5 | #include <linux/sched/debug.h> |
2bc5f927 AH |
6 | #include <linux/kallsyms.h> |
7 | #include <linux/kprobes.h> | |
8 | #include <linux/uaccess.h> | |
2bc5f927 AH |
9 | #include <linux/hardirq.h> |
10 | #include <linux/kdebug.h> | |
186f4360 | 11 | #include <linux/export.h> |
2bc5f927 AH |
12 | #include <linux/ptrace.h> |
13 | #include <linux/kexec.h> | |
b8030906 | 14 | #include <linux/sysfs.h> |
2bc5f927 AH |
15 | #include <linux/bug.h> |
16 | #include <linux/nmi.h> | |
17 | ||
18 | #include <asm/stacktrace.h> | |
19 | ||
3d02a9c4 | 20 | const char *stack_type_name(enum stack_type type) |
198d208d | 21 | { |
3d02a9c4 JP |
22 | if (type == STACK_TYPE_IRQ) |
23 | return "IRQ"; | |
24 | ||
25 | if (type == STACK_TYPE_SOFTIRQ) | |
26 | return "SOFTIRQ"; | |
27 | ||
28 | return NULL; | |
198d208d SR |
29 | } |
30 | ||
cb76c939 JP |
31 | static bool in_hardirq_stack(unsigned long *stack, struct stack_info *info) |
32 | { | |
33 | unsigned long *begin = (unsigned long *)this_cpu_read(hardirq_stack); | |
34 | unsigned long *end = begin + (THREAD_SIZE / sizeof(long)); | |
35 | ||
5fe599e0 JP |
36 | /* |
37 | * This is a software stack, so 'end' can be a valid stack pointer. | |
38 | * It just means the stack is empty. | |
39 | */ | |
40 | if (stack < begin || stack > end) | |
cb76c939 JP |
41 | return false; |
42 | ||
43 | info->type = STACK_TYPE_IRQ; | |
44 | info->begin = begin; | |
45 | info->end = end; | |
46 | ||
47 | /* | |
48 | * See irq_32.c -- the next stack pointer is stored at the beginning of | |
49 | * the stack. | |
50 | */ | |
51 | info->next_sp = (unsigned long *)*begin; | |
198d208d | 52 | |
cb76c939 JP |
53 | return true; |
54 | } | |
55 | ||
56 | static bool in_softirq_stack(unsigned long *stack, struct stack_info *info) | |
198d208d | 57 | { |
cb76c939 JP |
58 | unsigned long *begin = (unsigned long *)this_cpu_read(softirq_stack); |
59 | unsigned long *end = begin + (THREAD_SIZE / sizeof(long)); | |
60 | ||
5fe599e0 JP |
61 | /* |
62 | * This is a software stack, so 'end' can be a valid stack pointer. | |
63 | * It just means the stack is empty. | |
64 | */ | |
65 | if (stack < begin || stack > end) | |
cb76c939 JP |
66 | return false; |
67 | ||
68 | info->type = STACK_TYPE_SOFTIRQ; | |
69 | info->begin = begin; | |
70 | info->end = end; | |
71 | ||
72 | /* | |
73 | * The next stack pointer is stored at the beginning of the stack. | |
74 | * See irq_32.c. | |
75 | */ | |
76 | info->next_sp = (unsigned long *)*begin; | |
198d208d | 77 | |
cb76c939 | 78 | return true; |
198d208d SR |
79 | } |
80 | ||
cb76c939 JP |
81 | int get_stack_info(unsigned long *stack, struct task_struct *task, |
82 | struct stack_info *info, unsigned long *visit_mask) | |
198d208d | 83 | { |
cb76c939 JP |
84 | if (!stack) |
85 | goto unknown; | |
198d208d | 86 | |
cb76c939 JP |
87 | task = task ? : current; |
88 | ||
89 | if (in_task_stack(stack, task, info)) | |
fcd709ef | 90 | goto recursion_check; |
cb76c939 JP |
91 | |
92 | if (task != current) | |
93 | goto unknown; | |
94 | ||
95 | if (in_hardirq_stack(stack, info)) | |
fcd709ef | 96 | goto recursion_check; |
cb76c939 JP |
97 | |
98 | if (in_softirq_stack(stack, info)) | |
fcd709ef JP |
99 | goto recursion_check; |
100 | ||
101 | goto unknown; | |
102 | ||
103 | recursion_check: | |
104 | /* | |
105 | * Make sure we don't iterate through any given stack more than once. | |
106 | * If it comes up a second time then there's something wrong going on: | |
107 | * just break out and report an unknown stack type. | |
108 | */ | |
109 | if (visit_mask) { | |
0d2b8579 JP |
110 | if (*visit_mask & (1UL << info->type)) { |
111 | printk_deferred_once(KERN_WARNING "WARNING: stack recursion on stack type %d\n", info->type); | |
fcd709ef | 112 | goto unknown; |
0d2b8579 | 113 | } |
fcd709ef JP |
114 | *visit_mask |= 1UL << info->type; |
115 | } | |
116 | ||
117 | return 0; | |
cb76c939 JP |
118 | |
119 | unknown: | |
120 | info->type = STACK_TYPE_UNKNOWN; | |
121 | return -EINVAL; | |
198d208d | 122 | } |
0406ca6d | 123 | |
57da8b96 | 124 | void show_regs(struct pt_regs *regs) |
2bc5f927 AH |
125 | { |
126 | int i; | |
127 | ||
a43cb95d | 128 | show_regs_print_info(KERN_EMERG); |
f39b6f0e | 129 | __show_regs(regs, !user_mode(regs)); |
2bc5f927 | 130 | |
2bc5f927 AH |
131 | /* |
132 | * When in-kernel, we also print out the stack and code at the | |
133 | * time of the fault.. | |
134 | */ | |
f39b6f0e | 135 | if (!user_mode(regs)) { |
2bc5f927 AH |
136 | unsigned int code_prologue = code_bytes * 43 / 64; |
137 | unsigned int code_len = code_bytes; | |
138 | unsigned char c; | |
139 | u8 *ip; | |
140 | ||
0ee1dd9f | 141 | show_trace_log_lvl(current, regs, NULL, KERN_EMERG); |
2bc5f927 | 142 | |
c767a54b | 143 | pr_emerg("Code:"); |
2bc5f927 AH |
144 | |
145 | ip = (u8 *)regs->ip - code_prologue; | |
146 | if (ip < (u8 *)PAGE_OFFSET || probe_kernel_address(ip, c)) { | |
8a541665 | 147 | /* try starting at IP */ |
2bc5f927 AH |
148 | ip = (u8 *)regs->ip; |
149 | code_len = code_len - code_prologue + 1; | |
150 | } | |
151 | for (i = 0; i < code_len; i++, ip++) { | |
152 | if (ip < (u8 *)PAGE_OFFSET || | |
153 | probe_kernel_address(ip, c)) { | |
c767a54b | 154 | pr_cont(" Bad EIP value."); |
2bc5f927 AH |
155 | break; |
156 | } | |
157 | if (ip == (u8 *)regs->ip) | |
c767a54b | 158 | pr_cont(" <%02x>", c); |
2bc5f927 | 159 | else |
c767a54b | 160 | pr_cont(" %02x", c); |
2bc5f927 AH |
161 | } |
162 | } | |
c767a54b | 163 | pr_cont("\n"); |
2bc5f927 | 164 | } |