diff --git a/arch/x86/include/asm/kgdb.h b/arch/x86/include/asm/kgdb.h index e6c6c808489f..006da3687cdc 100644 --- a/arch/x86/include/asm/kgdb.h +++ b/arch/x86/include/asm/kgdb.h @@ -76,4 +76,7 @@ static inline void arch_kgdb_breakpoint(void) #define BREAK_INSTR_SIZE 1 #define CACHE_FLUSH_IS_SAFE 1 +extern int kgdb_ll_trap(int cmd, const char *str, + struct pt_regs *regs, long err, int trap, int sig); + #endif /* _ASM_X86_KGDB_H */ diff --git a/arch/x86/kernel/kgdb.c b/arch/x86/kernel/kgdb.c index acba57169938..95b89d4cb8f1 100644 --- a/arch/x86/kernel/kgdb.c +++ b/arch/x86/kernel/kgdb.c @@ -538,7 +538,7 @@ static int __kgdb_notify(struct die_args *args, unsigned long cmd) return NOTIFY_DONE; } - if (kgdb_handle_exception(args->trapnr, args->signr, args->err, regs)) + if (kgdb_handle_exception(args->trapnr, args->signr, cmd, regs)) return NOTIFY_DONE; /* Must touch watchdog before return to normal operation */ @@ -546,6 +546,26 @@ static int __kgdb_notify(struct die_args *args, unsigned long cmd) return NOTIFY_STOP; } +#ifdef CONFIG_KGDB_LOW_LEVEL_TRAP +int kgdb_ll_trap(int cmd, const char *str, + struct pt_regs *regs, long err, int trap, int sig) +{ + struct die_args args = { + .regs = regs, + .str = str, + .err = err, + .trapnr = trap, + .signr = sig, + + }; + + if (!kgdb_io_module_registered) + return NOTIFY_DONE; + + return __kgdb_notify(&args, cmd); +} +#endif /* CONFIG_KGDB_LOW_LEVEL_TRAP */ + static int kgdb_notify(struct notifier_block *self, unsigned long cmd, void *ptr) { diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index 02cfb9b8f5b1..7eaad4c5110a 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -451,6 +452,11 @@ void restart_nmi(void) /* May run on IST stack. */ dotraplinkage void __kprobes do_int3(struct pt_regs *regs, long error_code) { +#ifdef CONFIG_KGDB_LOW_LEVEL_TRAP + if (kgdb_ll_trap(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP) + == NOTIFY_STOP) + return; +#endif /* CONFIG_KGDB_LOW_LEVEL_TRAP */ #ifdef CONFIG_KPROBES if (notify_die(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP) == NOTIFY_STOP) diff --git a/include/linux/kgdb.h b/include/linux/kgdb.h index 406f6f9286f3..19d1b29a2694 100644 --- a/include/linux/kgdb.h +++ b/include/linux/kgdb.h @@ -60,6 +60,7 @@ struct uart_port; void kgdb_breakpoint(void); extern int kgdb_connected; +extern int kgdb_io_module_registered; extern atomic_t kgdb_setting_breakpoint; extern atomic_t kgdb_cpu_doing_single_step; diff --git a/kernel/debug/debug_core.c b/kernel/debug/debug_core.c index 88a83a225374..375e42f0baf0 100644 --- a/kernel/debug/debug_core.c +++ b/kernel/debug/debug_core.c @@ -66,7 +66,7 @@ int kgdb_connected; EXPORT_SYMBOL_GPL(kgdb_connected); /* All the KGDB handlers are installed */ -static int kgdb_io_module_registered; +int kgdb_io_module_registered; /* Guard for recursive entry */ static int exception_level; diff --git a/lib/Kconfig.kgdb b/lib/Kconfig.kgdb index ee8ae7132f20..c56ccb4ad292 100644 --- a/lib/Kconfig.kgdb +++ b/lib/Kconfig.kgdb @@ -57,6 +57,15 @@ config KGDB_TESTS_BOOT_STRING information about other strings you could use beyond the default of V1F100. +config KGDB_LOW_LEVEL_TRAP + bool "KGDB: Allow debugging with traps in notifiers" + depends on X86 + default n + help + This will add an extra call back to kgdb for the breakpoint + exception handler on which will will allow kgdb to step + through a notify handler. + config KGDB_KDB bool "KGDB_KDB: include kdb frontend for kgdb" default n