Skip to content

Commit

Permalink
x86/debug: Implement __WARN() using UD0
Browse files Browse the repository at this point in the history
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) <[email protected]>
Reviewed-by: Josh Poimboeuf <[email protected]>
Cc: Arjan van de Ven <[email protected]>
Cc: Borislav Petkov <[email protected]>
Cc: Linus Torvalds <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Richard Weinberger <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: [email protected]
Signed-off-by: Ingo Molnar <[email protected]>
  • Loading branch information
Peter Zijlstra authored and Ingo Molnar committed Mar 27, 2017
1 parent 1fa9d67 commit 9a93848
Show file tree
Hide file tree
Showing 8 changed files with 101 additions and 76 deletions.
5 changes: 0 additions & 5 deletions arch/um/Kconfig.common
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,6 @@ config GENERIC_CALIBRATE_DELAY
bool
default y

config GENERIC_BUG
bool
default y
depends on BUG

config HZ
int
default 100
Expand Down
78 changes: 60 additions & 18 deletions arch/x86/include/asm/bug.h
Original file line number Diff line number Diff line change
@@ -1,36 +1,78 @@
#ifndef _ASM_X86_BUG_H
#define _ASM_X86_BUG_H

#define HAVE_ARCH_BUG
#include <linux/stringify.h>

#ifdef CONFIG_DEBUG_BUGVERBOSE
/*
* Since some emulators terminate on UD2, we cannot use it for WARN.
* Since various instruction decoders disagree on the length of UD1,
* we cannot use it either. So use UD0 for WARN.
*
* (binutils knows about "ud1" but {en,de}codes it as 2 bytes, whereas
* our kernel decoder thinks it takes a ModRM byte, which seems consistent
* with various things like the Intel SDM instruction encoding rules)
*/

#define ASM_UD0 ".byte 0x0f, 0xff"
#define ASM_UD1 ".byte 0x0f, 0xb9" /* + ModRM */
#define ASM_UD2 ".byte 0x0f, 0x0b"

#define INSN_UD0 0xff0f
#define INSN_UD2 0x0b0f

#define LEN_UD0 2

#ifdef CONFIG_GENERIC_BUG
#define HAVE_ARCH_BUG

#ifdef CONFIG_X86_32
# define __BUG_C0 "2:\t.long 1b, %c0\n"
# define __BUG_REL(val) ".long " __stringify(val)
#else
# define __BUG_C0 "2:\t.long 1b - 2b, %c0 - 2b\n"
# define __BUG_REL(val) ".long " __stringify(val) " - 2b"
#endif

#define BUG() \
do { \
asm volatile("1:\tud2\n" \
".pushsection __bug_table,\"a\"\n" \
__BUG_C0 \
"\t.word %c1, 0\n" \
"\t.org 2b+%c2\n" \
".popsection" \
: : "i" (__FILE__), "i" (__LINE__), \
"i" (sizeof(struct bug_entry))); \
unreachable(); \
#ifdef CONFIG_DEBUG_BUGVERBOSE

#define _BUG_FLAGS(ins, flags) \
do { \
asm volatile("1:\t" ins "\n" \
".pushsection __bug_table,\"a\"\n" \
"2:\t" __BUG_REL(1b) "\t# bug_entry::bug_addr\n" \
"\t" __BUG_REL(%c0) "\t# bug_entry::file\n" \
"\t.word %c1" "\t# bug_entry::line\n" \
"\t.word %c2" "\t# bug_entry::flags\n" \
"\t.org 2b+%c3\n" \
".popsection" \
: : "i" (__FILE__), "i" (__LINE__), \
"i" (flags), \
"i" (sizeof(struct bug_entry))); \
} while (0)

#else
#else /* !CONFIG_DEBUG_BUGVERBOSE */

#define _BUG_FLAGS(ins, flags) \
do { \
asm volatile("1:\t" ins "\n" \
".pushsection __bug_table,\"a\"\n" \
"2:\t" __BUG_REL(1b) "\t# bug_entry::bug_addr\n" \
"\t.word %c0" "\t# bug_entry::flags\n" \
"\t.org 2b+%c1\n" \
".popsection" \
: : "i" (flags), \
"i" (sizeof(struct bug_entry))); \
} while (0)

#endif /* CONFIG_DEBUG_BUGVERBOSE */

#define BUG() \
do { \
asm volatile("ud2"); \
_BUG_FLAGS(ASM_UD2, 0); \
unreachable(); \
} while (0)
#endif

#define __WARN_TAINT(taint) _BUG_FLAGS(ASM_UD0, BUGFLAG_TAINT(taint))

#endif /* CONFIG_GENERIC_BUG */

#include <asm-generic/bug.h>

Expand Down
3 changes: 0 additions & 3 deletions arch/x86/kernel/dumpstack.c
Original file line number Diff line number Diff line change
Expand Up @@ -289,9 +289,6 @@ void die(const char *str, struct pt_regs *regs, long err)
unsigned long flags = oops_begin();
int sig = SIGSEGV;

if (!user_mode(regs))
report_bug(regs->ip, regs);

if (__die(str, regs, err))
sig = 0;
oops_end(flags, regs, sig);
Expand Down
12 changes: 0 additions & 12 deletions arch/x86/kernel/dumpstack_32.c
Original file line number Diff line number Diff line change
Expand Up @@ -162,15 +162,3 @@ void show_regs(struct pt_regs *regs)
}
pr_cont("\n");
}

int is_valid_bugaddr(unsigned long ip)
{
unsigned short ud2;

if (ip < PAGE_OFFSET)
return 0;
if (probe_kernel_address((unsigned short *)ip, ud2))
return 0;

return ud2 == 0x0b0f;
}
10 changes: 0 additions & 10 deletions arch/x86/kernel/dumpstack_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -178,13 +178,3 @@ void show_regs(struct pt_regs *regs)
}
pr_cont("\n");
}

int is_valid_bugaddr(unsigned long ip)
{
unsigned short ud2;

if (__copy_from_user(&ud2, (const void __user *) ip, sizeof(ud2)))
return 0;

return ud2 == 0x0b0f;
}
46 changes: 40 additions & 6 deletions arch/x86/kernel/traps.c
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,37 @@ void ist_end_non_atomic(void)
preempt_disable();
}

int is_valid_bugaddr(unsigned long addr)
{
unsigned short ud;

if (addr < TASK_SIZE_MAX)
return 0;

if (probe_kernel_address((unsigned short *)addr, ud))
return 0;

return ud == INSN_UD0 || ud == INSN_UD2;
}

static int fixup_bug(struct pt_regs *regs, int trapnr)
{
if (trapnr != X86_TRAP_UD)
return 0;

switch (report_bug(regs->ip, regs)) {
case BUG_TRAP_TYPE_NONE:
case BUG_TRAP_TYPE_BUG:
break;

case BUG_TRAP_TYPE_WARN:
regs->ip += LEN_UD0;
return 1;
}

return 0;
}

static nokprobe_inline int
do_trap_no_signal(struct task_struct *tsk, int trapnr, char *str,
struct pt_regs *regs, long error_code)
Expand All @@ -187,12 +218,15 @@ do_trap_no_signal(struct task_struct *tsk, int trapnr, char *str,
}

if (!user_mode(regs)) {
if (!fixup_exception(regs, trapnr)) {
tsk->thread.error_code = error_code;
tsk->thread.trap_nr = trapnr;
die(str, regs, error_code);
}
return 0;
if (fixup_exception(regs, trapnr))
return 0;

if (fixup_bug(regs, trapnr))
return 0;

tsk->thread.error_code = error_code;
tsk->thread.trap_nr = trapnr;
die(str, regs, error_code);
}

return -1;
Expand Down
2 changes: 1 addition & 1 deletion arch/x86/um/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ else
BITS := 64
endif

obj-y = bug.o bugs_$(BITS).o delay.o fault.o ldt.o \
obj-y = bugs_$(BITS).o delay.o fault.o ldt.o \
ptrace_$(BITS).o ptrace_user.o setjmp_$(BITS).o signal.o \
stub_$(BITS).o stub_segv.o \
sys_call_table_$(BITS).o sysrq_$(BITS).o tls_$(BITS).o \
Expand Down
21 changes: 0 additions & 21 deletions arch/x86/um/bug.c

This file was deleted.

0 comments on commit 9a93848

Please sign in to comment.