diff options
Diffstat (limited to 'kernel/debug/kdb/kdb_debugger.c')
| -rw-r--r-- | kernel/debug/kdb/kdb_debugger.c | 54 | 
1 files changed, 34 insertions, 20 deletions
diff --git a/kernel/debug/kdb/kdb_debugger.c b/kernel/debug/kdb/kdb_debugger.c index dd0b1b7dd02..8859ca34dcf 100644 --- a/kernel/debug/kdb/kdb_debugger.c +++ b/kernel/debug/kdb/kdb_debugger.c @@ -11,6 +11,8 @@  #include <linux/kgdb.h>  #include <linux/kdb.h>  #include <linux/kdebug.h> +#include <linux/export.h> +#include <linux/hardirq.h>  #include "kdb_private.h"  #include "../debug_core.h" @@ -30,6 +32,24 @@ EXPORT_SYMBOL_GPL(kdb_poll_funcs);  int kdb_poll_idx = 1;  EXPORT_SYMBOL_GPL(kdb_poll_idx); +static struct kgdb_state *kdb_ks; + +int kdb_common_init_state(struct kgdb_state *ks) +{ +	kdb_initial_cpu = atomic_read(&kgdb_active); +	kdb_current_task = kgdb_info[ks->cpu].task; +	kdb_current_regs = kgdb_info[ks->cpu].debuggerinfo; +	return 0; +} + +int kdb_common_deinit_state(void) +{ +	kdb_initial_cpu = -1; +	kdb_current_task = NULL; +	kdb_current_regs = NULL; +	return 0; +} +  int kdb_stub(struct kgdb_state *ks)  {  	int error = 0; @@ -39,6 +59,7 @@ int kdb_stub(struct kgdb_state *ks)  	kdb_dbtrap_t db_result = KDB_DB_NOBPT;  	int i; +	kdb_ks = ks;  	if (KDB_STATE(REENTRY)) {  		reason = KDB_REASON_SWITCH;  		KDB_STATE_CLEAR(REENTRY); @@ -48,6 +69,12 @@ int kdb_stub(struct kgdb_state *ks)  	if (atomic_read(&kgdb_setting_breakpoint))  		reason = KDB_REASON_KEYBOARD; +	if (ks->err_code == KDB_REASON_SYSTEM_NMI && ks->signo == SIGTRAP) +		reason = KDB_REASON_SYSTEM_NMI; + +	else if (in_nmi()) +		reason = KDB_REASON_NMI; +  	for (i = 0, bp = kdb_breakpoints; i < KDB_MAXBPT; i++, bp++) {  		if ((bp->bp_enabled) && (bp->bp_addr == addr)) {  			reason = KDB_REASON_BREAK; @@ -86,13 +113,10 @@ int kdb_stub(struct kgdb_state *ks)  	}  	/* Set initial kdb state variables */  	KDB_STATE_CLEAR(KGDB_TRANS); -	kdb_initial_cpu = atomic_read(&kgdb_active); -	kdb_current_task = kgdb_info[ks->cpu].task; -	kdb_current_regs = kgdb_info[ks->cpu].debuggerinfo; +	kdb_common_init_state(ks);  	/* Remove any breakpoints as needed by kdb and clear single step */  	kdb_bp_remove();  	KDB_STATE_CLEAR(DOING_SS); -	KDB_STATE_CLEAR(DOING_SSB);  	KDB_STATE_SET(PAGER);  	/* zero out any offline cpu data */  	for_each_present_cpu(i) { @@ -117,26 +141,12 @@ int kdb_stub(struct kgdb_state *ks)  	 * Upon exit from the kdb main loop setup break points and restart  	 * the system based on the requested continue state  	 */ -	kdb_initial_cpu = -1; -	kdb_current_task = NULL; -	kdb_current_regs = NULL; +	kdb_common_deinit_state();  	KDB_STATE_CLEAR(PAGER);  	kdbnearsym_cleanup();  	if (error == KDB_CMD_KGDB) { -		if (KDB_STATE(DOING_KGDB) || KDB_STATE(DOING_KGDB2)) { -	/* -	 * This inteface glue which allows kdb to transition in into -	 * the gdb stub.  In order to do this the '?' or '' gdb serial -	 * packet response is processed here.  And then control is -	 * passed to the gdbstub. -	 */ -			if (KDB_STATE(DOING_KGDB)) -				gdbstub_state(ks, "?"); -			else -				gdbstub_state(ks, ""); +		if (KDB_STATE(DOING_KGDB))  			KDB_STATE_CLEAR(DOING_KGDB); -			KDB_STATE_CLEAR(DOING_KGDB2); -		}  		return DBG_PASS_EVENT;  	}  	kdb_bp_install(ks->linux_regs); @@ -166,3 +176,7 @@ int kdb_stub(struct kgdb_state *ks)  	return kgdb_info[ks->cpu].ret_state;  } +void kdb_gdb_state_pass(char *buf) +{ +	gdbstub_state(kdb_ks, buf); +}  | 
