summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Zijlstra <peterz@infradead.org>2017-02-02 08:43:51 -0500
committerIngo Molnar <mingo@kernel.org>2017-03-27 04:20:28 -0400
commit9a93848fe787a53aec404e4e00d8f7f9bbdaebb4 (patch)
tree4e3b4f0b97838278a72f47a4b4ed2825610e1969
parent1fa9d67a2f07893fc7e4a880867a6cbb81dda547 (diff)
x86/debug: Implement __WARN() using UD0
By using "UD0" for WARN()s we remove the function call and its possible __FILE__ and __LINE__ immediate arguments from the instruction stream. Total image size will not change much, what we win in the instruction stream we'll lose because of the __bug_table entries. Still, saves on I$ footprint and the total image size does go down a bit. text data filename 10702123 4530992 defconfig-build/vmlinux.orig 10682460 4530992 defconfig-build/vmlinux.patched (UML didn't seem to use GENERIC_BUG at all, so remove it) Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Reviewed-by: Josh Poimboeuf <jpoimboe@redhat.com> Cc: Arjan van de Ven <arjan@linux.intel.com> Cc: Borislav Petkov <bp@alien8.de> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Richard Weinberger <richard.weinberger@gmail.com> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--arch/um/Kconfig.common5
-rw-r--r--arch/x86/include/asm/bug.h78
-rw-r--r--arch/x86/kernel/dumpstack.c3
-rw-r--r--arch/x86/kernel/dumpstack_32.c12
-rw-r--r--arch/x86/kernel/dumpstack_64.c10
-rw-r--r--arch/x86/kernel/traps.c46
-rw-r--r--arch/x86/um/Makefile2
-rw-r--r--arch/x86/um/bug.c21
8 files changed, 101 insertions, 76 deletions
diff --git a/arch/um/Kconfig.common b/arch/um/Kconfig.common
index fd443852103c..ed9c5b5ff028 100644
--- a/arch/um/Kconfig.common
+++ b/arch/um/Kconfig.common
@@ -50,11 +50,6 @@ config GENERIC_CALIBRATE_DELAY
50 bool 50 bool
51 default y 51 default y
52 52
53config GENERIC_BUG
54 bool
55 default y
56 depends on BUG
57
58config HZ 53config HZ
59 int 54 int
60 default 100 55 default 100
diff --git a/arch/x86/include/asm/bug.h b/arch/x86/include/asm/bug.h
index ba38ebbaced3..4fde330c44b7 100644
--- a/arch/x86/include/asm/bug.h
+++ b/arch/x86/include/asm/bug.h
@@ -1,36 +1,78 @@
1#ifndef _ASM_X86_BUG_H 1#ifndef _ASM_X86_BUG_H
2#define _ASM_X86_BUG_H 2#define _ASM_X86_BUG_H
3 3
4#define HAVE_ARCH_BUG 4#include <linux/stringify.h>
5 5
6#ifdef CONFIG_DEBUG_BUGVERBOSE 6/*
7 * Since some emulators terminate on UD2, we cannot use it for WARN.
8 * Since various instruction decoders disagree on the length of UD1,
9 * we cannot use it either. So use UD0 for WARN.
10 *
11 * (binutils knows about "ud1" but {en,de}codes it as 2 bytes, whereas
12 * our kernel decoder thinks it takes a ModRM byte, which seems consistent
13 * with various things like the Intel SDM instruction encoding rules)
14 */
15
16#define ASM_UD0 ".byte 0x0f, 0xff"
17#define ASM_UD1 ".byte 0x0f, 0xb9" /* + ModRM */
18#define ASM_UD2 ".byte 0x0f, 0x0b"
19
20#define INSN_UD0 0xff0f
21#define INSN_UD2 0x0b0f
22
23#define LEN_UD0 2
24
25#ifdef CONFIG_GENERIC_BUG
26#define HAVE_ARCH_BUG
7 27
8#ifdef CONFIG_X86_32 28#ifdef CONFIG_X86_32
9# define __BUG_C0 "2:\t.long 1b, %c0\n" 29# define __BUG_REL(val) ".long " __stringify(val)
10#else 30#else
11# define __BUG_C0 "2:\t.long 1b - 2b, %c0 - 2b\n" 31# define __BUG_REL(val) ".long " __stringify(val) " - 2b"
12#endif 32#endif
13 33
14#define BUG() \ 34#ifdef CONFIG_DEBUG_BUGVERBOSE
15do { \ 35
16 asm volatile("1:\tud2\n" \ 36#define _BUG_FLAGS(ins, flags) \
17 ".pushsection __bug_table,\"a\"\n" \ 37do { \
18 __BUG_C0 \ 38 asm volatile("1:\t" ins "\n" \
19 "\t.word %c1, 0\n" \ 39 ".pushsection __bug_table,\"a\"\n" \
20 "\t.org 2b+%c2\n" \ 40 "2:\t" __BUG_REL(1b) "\t# bug_entry::bug_addr\n" \
21 ".popsection" \ 41 "\t" __BUG_REL(%c0) "\t# bug_entry::file\n" \
22 : : "i" (__FILE__), "i" (__LINE__), \ 42 "\t.word %c1" "\t# bug_entry::line\n" \
23 "i" (sizeof(struct bug_entry))); \ 43 "\t.word %c2" "\t# bug_entry::flags\n" \
24 unreachable(); \ 44 "\t.org 2b+%c3\n" \
45 ".popsection" \
46 : : "i" (__FILE__), "i" (__LINE__), \
47 "i" (flags), \
48 "i" (sizeof(struct bug_entry))); \
25} while (0) 49} while (0)
26 50
27#else 51#else /* !CONFIG_DEBUG_BUGVERBOSE */
52
53#define _BUG_FLAGS(ins, flags) \
54do { \
55 asm volatile("1:\t" ins "\n" \
56 ".pushsection __bug_table,\"a\"\n" \
57 "2:\t" __BUG_REL(1b) "\t# bug_entry::bug_addr\n" \
58 "\t.word %c0" "\t# bug_entry::flags\n" \
59 "\t.org 2b+%c1\n" \
60 ".popsection" \
61 : : "i" (flags), \
62 "i" (sizeof(struct bug_entry))); \
63} while (0)
64
65#endif /* CONFIG_DEBUG_BUGVERBOSE */
66
28#define BUG() \ 67#define BUG() \
29do { \ 68do { \
30 asm volatile("ud2"); \ 69 _BUG_FLAGS(ASM_UD2, 0); \
31 unreachable(); \ 70 unreachable(); \
32} while (0) 71} while (0)
33#endif 72
73#define __WARN_TAINT(taint) _BUG_FLAGS(ASM_UD0, BUGFLAG_TAINT(taint))
74
75#endif /* CONFIG_GENERIC_BUG */
34 76
35#include <asm-generic/bug.h> 77#include <asm-generic/bug.h>
36 78
diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c
index 09d4ac0d2661..924f45ea4382 100644
--- a/arch/x86/kernel/dumpstack.c
+++ b/arch/x86/kernel/dumpstack.c
@@ -289,9 +289,6 @@ void die(const char *str, struct pt_regs *regs, long err)
289 unsigned long flags = oops_begin(); 289 unsigned long flags = oops_begin();
290 int sig = SIGSEGV; 290 int sig = SIGSEGV;
291 291
292 if (!user_mode(regs))
293 report_bug(regs->ip, regs);
294
295 if (__die(str, regs, err)) 292 if (__die(str, regs, err))
296 sig = 0; 293 sig = 0;
297 oops_end(flags, regs, sig); 294 oops_end(flags, regs, sig);
diff --git a/arch/x86/kernel/dumpstack_32.c b/arch/x86/kernel/dumpstack_32.c
index b0b3a3df7c20..e5f0b40e66d2 100644
--- a/arch/x86/kernel/dumpstack_32.c
+++ b/arch/x86/kernel/dumpstack_32.c
@@ -162,15 +162,3 @@ void show_regs(struct pt_regs *regs)
162 } 162 }
163 pr_cont("\n"); 163 pr_cont("\n");
164} 164}
165
166int is_valid_bugaddr(unsigned long ip)
167{
168 unsigned short ud2;
169
170 if (ip < PAGE_OFFSET)
171 return 0;
172 if (probe_kernel_address((unsigned short *)ip, ud2))
173 return 0;
174
175 return ud2 == 0x0b0f;
176}
diff --git a/arch/x86/kernel/dumpstack_64.c b/arch/x86/kernel/dumpstack_64.c
index a8b117e93b46..3e1471d57487 100644
--- a/arch/x86/kernel/dumpstack_64.c
+++ b/arch/x86/kernel/dumpstack_64.c
@@ -178,13 +178,3 @@ void show_regs(struct pt_regs *regs)
178 } 178 }
179 pr_cont("\n"); 179 pr_cont("\n");
180} 180}
181
182int is_valid_bugaddr(unsigned long ip)
183{
184 unsigned short ud2;
185
186 if (__copy_from_user(&ud2, (const void __user *) ip, sizeof(ud2)))
187 return 0;
188
189 return ud2 == 0x0b0f;
190}
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index 948443e115c1..3c0751b120de 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -169,6 +169,37 @@ void ist_end_non_atomic(void)
169 preempt_disable(); 169 preempt_disable();
170} 170}
171 171
172int is_valid_bugaddr(unsigned long addr)
173{
174 unsigned short ud;
175
176 if (addr < TASK_SIZE_MAX)
177 return 0;
178
179 if (probe_kernel_address((unsigned short *)addr, ud))
180 return 0;
181
182 return ud == INSN_UD0 || ud == INSN_UD2;
183}
184
185static int fixup_bug(struct pt_regs *regs, int trapnr)
186{
187 if (trapnr != X86_TRAP_UD)
188 return 0;
189
190 switch (report_bug(regs->ip, regs)) {
191 case BUG_TRAP_TYPE_NONE:
192 case BUG_TRAP_TYPE_BUG:
193 break;
194
195 case BUG_TRAP_TYPE_WARN:
196 regs->ip += LEN_UD0;
197 return 1;
198 }
199
200 return 0;
201}
202
172static nokprobe_inline int 203static nokprobe_inline int
173do_trap_no_signal(struct task_struct *tsk, int trapnr, char *str, 204do_trap_no_signal(struct task_struct *tsk, int trapnr, char *str,
174 struct pt_regs *regs, long error_code) 205 struct pt_regs *regs, long error_code)
@@ -187,12 +218,15 @@ do_trap_no_signal(struct task_struct *tsk, int trapnr, char *str,
187 } 218 }
188 219
189 if (!user_mode(regs)) { 220 if (!user_mode(regs)) {
190 if (!fixup_exception(regs, trapnr)) { 221 if (fixup_exception(regs, trapnr))
191 tsk->thread.error_code = error_code; 222 return 0;
192 tsk->thread.trap_nr = trapnr; 223
193 die(str, regs, error_code); 224 if (fixup_bug(regs, trapnr))
194 } 225 return 0;
195 return 0; 226
227 tsk->thread.error_code = error_code;
228 tsk->thread.trap_nr = trapnr;
229 die(str, regs, error_code);
196 } 230 }
197 231
198 return -1; 232 return -1;
diff --git a/arch/x86/um/Makefile b/arch/x86/um/Makefile
index e7e7055a8658..76f17f05446f 100644
--- a/arch/x86/um/Makefile
+++ b/arch/x86/um/Makefile
@@ -8,7 +8,7 @@ else
8 BITS := 64 8 BITS := 64
9endif 9endif
10 10
11obj-y = bug.o bugs_$(BITS).o delay.o fault.o ldt.o \ 11obj-y = bugs_$(BITS).o delay.o fault.o ldt.o \
12 ptrace_$(BITS).o ptrace_user.o setjmp_$(BITS).o signal.o \ 12 ptrace_$(BITS).o ptrace_user.o setjmp_$(BITS).o signal.o \
13 stub_$(BITS).o stub_segv.o \ 13 stub_$(BITS).o stub_segv.o \
14 sys_call_table_$(BITS).o sysrq_$(BITS).o tls_$(BITS).o \ 14 sys_call_table_$(BITS).o sysrq_$(BITS).o tls_$(BITS).o \
diff --git a/arch/x86/um/bug.c b/arch/x86/um/bug.c
deleted file mode 100644
index e8034e363d83..000000000000
--- a/arch/x86/um/bug.c
+++ /dev/null
@@ -1,21 +0,0 @@
1/*
2 * Copyright (C) 2006 Jeff Dike (jdike@addtoit.com)
3 * Licensed under the GPL V2
4 */
5
6#include <linux/uaccess.h>
7
8/*
9 * Mostly copied from i386/x86_86 - eliminated the eip < PAGE_OFFSET because
10 * that's not relevant in skas mode.
11 */
12
13int is_valid_bugaddr(unsigned long eip)
14{
15 unsigned short ud2;
16
17 if (probe_kernel_address((unsigned short __user *)eip, ud2))
18 return 0;
19
20 return ud2 == 0x0b0f;
21}