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