diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-12-12 16:49:57 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-12-12 16:49:57 -0500 |
commit | 5645688f9d0d5a32f030f9c5429e1a58bedca23b (patch) | |
tree | 0b576ba953fb26d521c6b8c3364848acb00ceef3 /arch/x86/kernel/dumpstack.c | |
parent | 4ade5b2268b9ff05e48a9cb99689c4fd15fbe9c3 (diff) | |
parent | 53938ee427bf27525a63721b7e25d86b8f31f161 (diff) |
Merge branch 'x86-asm-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 asm updates from Ingo Molnar:
"The main changes in this development cycle were:
- a large number of call stack dumping/printing improvements: higher
robustness, better cross-context dumping, improved output, etc.
(Josh Poimboeuf)
- vDSO getcpu() performance improvement for future Intel CPUs with
the RDPID instruction (Andy Lutomirski)
- add two new Intel AVX512 features and the CPUID support
infrastructure for it: AVX512IFMA and AVX512VBMI. (Gayatri Kammela,
He Chen)
- more copy-user unification (Borislav Petkov)
- entry code assembly macro simplifications (Alexander Kuleshov)
- vDSO C/R support improvements (Dmitry Safonov)
- misc fixes and cleanups (Borislav Petkov, Paul Bolle)"
* 'x86-asm-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (40 commits)
scripts/decode_stacktrace.sh: Fix address line detection on x86
x86/boot/64: Use defines for page size
x86/dumpstack: Make stack name tags more comprehensible
selftests/x86: Add test_vdso to test getcpu()
x86/vdso: Use RDPID in preference to LSL when available
x86/dumpstack: Handle NULL stack pointer in show_trace_log_lvl()
x86/cpufeatures: Enable new AVX512 cpu features
x86/cpuid: Provide get_scattered_cpuid_leaf()
x86/cpuid: Cleanup cpuid_regs definitions
x86/copy_user: Unify the code by removing the 64-bit asm _copy_*_user() variants
x86/unwind: Ensure stack grows down
x86/vdso: Set vDSO pointer only after success
x86/prctl/uapi: Remove #ifdef for CHECKPOINT_RESTORE
x86/unwind: Detect bad stack return address
x86/dumpstack: Warn on stack recursion
x86/unwind: Warn on bad frame pointer
x86/decoder: Use stderr if insn sanity test fails
x86/decoder: Use stdout if insn decoder test is successful
mm/page_alloc: Remove kernel address exposure in free_reserved_area()
x86/dumpstack: Remove raw stack dump
...
Diffstat (limited to 'arch/x86/kernel/dumpstack.c')
-rw-r--r-- | arch/x86/kernel/dumpstack.c | 68 |
1 files changed, 28 insertions, 40 deletions
diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c index 85f854b98a9d..0cfd01d2754c 100644 --- a/arch/x86/kernel/dumpstack.c +++ b/arch/x86/kernel/dumpstack.c | |||
@@ -22,7 +22,6 @@ | |||
22 | int panic_on_unrecovered_nmi; | 22 | int panic_on_unrecovered_nmi; |
23 | int panic_on_io_nmi; | 23 | int panic_on_io_nmi; |
24 | unsigned int code_bytes = 64; | 24 | unsigned int code_bytes = 64; |
25 | int kstack_depth_to_print = 3 * STACKSLOTS_PER_LINE; | ||
26 | static int die_counter; | 25 | static int die_counter; |
27 | 26 | ||
28 | bool in_task_stack(unsigned long *stack, struct task_struct *task, | 27 | bool in_task_stack(unsigned long *stack, struct task_struct *task, |
@@ -46,14 +45,7 @@ static void printk_stack_address(unsigned long address, int reliable, | |||
46 | char *log_lvl) | 45 | char *log_lvl) |
47 | { | 46 | { |
48 | touch_nmi_watchdog(); | 47 | touch_nmi_watchdog(); |
49 | printk("%s [<%p>] %s%pB\n", | 48 | printk("%s %s%pB\n", log_lvl, reliable ? "" : "? ", (void *)address); |
50 | log_lvl, (void *)address, reliable ? "" : "? ", | ||
51 | (void *)address); | ||
52 | } | ||
53 | |||
54 | void printk_address(unsigned long address) | ||
55 | { | ||
56 | pr_cont(" [<%p>] %pS\n", (void *)address, (void *)address); | ||
57 | } | 49 | } |
58 | 50 | ||
59 | void show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, | 51 | void show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, |
@@ -67,6 +59,7 @@ void show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, | |||
67 | printk("%sCall Trace:\n", log_lvl); | 59 | printk("%sCall Trace:\n", log_lvl); |
68 | 60 | ||
69 | unwind_start(&state, task, regs, stack); | 61 | unwind_start(&state, task, regs, stack); |
62 | stack = stack ? : get_stack_pointer(task, regs); | ||
70 | 63 | ||
71 | /* | 64 | /* |
72 | * Iterate through the stacks, starting with the current stack pointer. | 65 | * Iterate through the stacks, starting with the current stack pointer. |
@@ -82,8 +75,8 @@ void show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, | |||
82 | * - softirq stack | 75 | * - softirq stack |
83 | * - hardirq stack | 76 | * - hardirq stack |
84 | */ | 77 | */ |
85 | for (; stack; stack = stack_info.next_sp) { | 78 | for (regs = NULL; stack; stack = stack_info.next_sp) { |
86 | const char *str_begin, *str_end; | 79 | const char *stack_name; |
87 | 80 | ||
88 | /* | 81 | /* |
89 | * If we overflowed the task stack into a guard page, jump back | 82 | * If we overflowed the task stack into a guard page, jump back |
@@ -95,9 +88,9 @@ void show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, | |||
95 | if (get_stack_info(stack, task, &stack_info, &visit_mask)) | 88 | if (get_stack_info(stack, task, &stack_info, &visit_mask)) |
96 | break; | 89 | break; |
97 | 90 | ||
98 | stack_type_str(stack_info.type, &str_begin, &str_end); | 91 | stack_name = stack_type_name(stack_info.type); |
99 | if (str_begin) | 92 | if (stack_name) |
100 | printk("%s <%s> ", log_lvl, str_begin); | 93 | printk("%s <%s>\n", log_lvl, stack_name); |
101 | 94 | ||
102 | /* | 95 | /* |
103 | * Scan the stack, printing any text addresses we find. At the | 96 | * Scan the stack, printing any text addresses we find. At the |
@@ -119,6 +112,15 @@ void show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, | |||
119 | if (!__kernel_text_address(addr)) | 112 | if (!__kernel_text_address(addr)) |
120 | continue; | 113 | continue; |
121 | 114 | ||
115 | /* | ||
116 | * Don't print regs->ip again if it was already printed | ||
117 | * by __show_regs() below. | ||
118 | */ | ||
119 | if (regs && stack == ®s->ip) { | ||
120 | unwind_next_frame(&state); | ||
121 | continue; | ||
122 | } | ||
123 | |||
122 | if (stack == ret_addr_p) | 124 | if (stack == ret_addr_p) |
123 | reliable = 1; | 125 | reliable = 1; |
124 | 126 | ||
@@ -146,10 +148,15 @@ void show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, | |||
146 | * of the addresses will just be printed as unreliable. | 148 | * of the addresses will just be printed as unreliable. |
147 | */ | 149 | */ |
148 | unwind_next_frame(&state); | 150 | unwind_next_frame(&state); |
151 | |||
152 | /* if the frame has entry regs, print them */ | ||
153 | regs = unwind_get_entry_regs(&state); | ||
154 | if (regs) | ||
155 | __show_regs(regs, 0); | ||
149 | } | 156 | } |
150 | 157 | ||
151 | if (str_end) | 158 | if (stack_name) |
152 | printk("%s <%s> ", log_lvl, str_end); | 159 | printk("%s </%s>\n", log_lvl, stack_name); |
153 | } | 160 | } |
154 | } | 161 | } |
155 | 162 | ||
@@ -164,12 +171,12 @@ void show_stack(struct task_struct *task, unsigned long *sp) | |||
164 | if (!sp && task == current) | 171 | if (!sp && task == current) |
165 | sp = get_stack_pointer(current, NULL); | 172 | sp = get_stack_pointer(current, NULL); |
166 | 173 | ||
167 | show_stack_log_lvl(task, NULL, sp, ""); | 174 | show_trace_log_lvl(task, NULL, sp, KERN_DEFAULT); |
168 | } | 175 | } |
169 | 176 | ||
170 | void show_stack_regs(struct pt_regs *regs) | 177 | void show_stack_regs(struct pt_regs *regs) |
171 | { | 178 | { |
172 | show_stack_log_lvl(current, regs, NULL, ""); | 179 | show_trace_log_lvl(current, regs, NULL, KERN_DEFAULT); |
173 | } | 180 | } |
174 | 181 | ||
175 | static arch_spinlock_t die_lock = __ARCH_SPIN_LOCK_UNLOCKED; | 182 | static arch_spinlock_t die_lock = __ARCH_SPIN_LOCK_UNLOCKED; |
@@ -261,14 +268,11 @@ int __die(const char *str, struct pt_regs *regs, long err) | |||
261 | sp = kernel_stack_pointer(regs); | 268 | sp = kernel_stack_pointer(regs); |
262 | savesegment(ss, ss); | 269 | savesegment(ss, ss); |
263 | } | 270 | } |
264 | printk(KERN_EMERG "EIP: [<%08lx>] ", regs->ip); | 271 | printk(KERN_EMERG "EIP: %pS SS:ESP: %04x:%08lx\n", |
265 | print_symbol("%s", regs->ip); | 272 | (void *)regs->ip, ss, sp); |
266 | printk(" SS:ESP %04x:%08lx\n", ss, sp); | ||
267 | #else | 273 | #else |
268 | /* Executive summary in case the oops scrolled away */ | 274 | /* Executive summary in case the oops scrolled away */ |
269 | printk(KERN_ALERT "RIP "); | 275 | printk(KERN_ALERT "RIP: %pS RSP: %016lx\n", (void *)regs->ip, regs->sp); |
270 | printk_address(regs->ip); | ||
271 | printk(" RSP <%016lx>\n", regs->sp); | ||
272 | #endif | 276 | #endif |
273 | return 0; | 277 | return 0; |
274 | } | 278 | } |
@@ -291,22 +295,6 @@ void die(const char *str, struct pt_regs *regs, long err) | |||
291 | oops_end(flags, regs, sig); | 295 | oops_end(flags, regs, sig); |
292 | } | 296 | } |
293 | 297 | ||
294 | static int __init kstack_setup(char *s) | ||
295 | { | ||
296 | ssize_t ret; | ||
297 | unsigned long val; | ||
298 | |||
299 | if (!s) | ||
300 | return -EINVAL; | ||
301 | |||
302 | ret = kstrtoul(s, 0, &val); | ||
303 | if (ret) | ||
304 | return ret; | ||
305 | kstack_depth_to_print = val; | ||
306 | return 0; | ||
307 | } | ||
308 | early_param("kstack", kstack_setup); | ||
309 | |||
310 | static int __init code_bytes_setup(char *s) | 298 | static int __init code_bytes_setup(char *s) |
311 | { | 299 | { |
312 | ssize_t ret; | 300 | ssize_t ret; |