diff options
-rw-r--r-- | include/linux/kgdb.h | 1 | ||||
-rw-r--r-- | kernel/debug/debug_core.c | 26 |
2 files changed, 27 insertions, 0 deletions
diff --git a/include/linux/kgdb.h b/include/linux/kgdb.h index 19d1b29a2694..ee007ea341b8 100644 --- a/include/linux/kgdb.h +++ b/include/linux/kgdb.h | |||
@@ -271,6 +271,7 @@ extern int kgdb_mem2hex(char *mem, char *buf, int count); | |||
271 | extern int kgdb_hex2mem(char *buf, char *mem, int count); | 271 | extern int kgdb_hex2mem(char *buf, char *mem, int count); |
272 | 272 | ||
273 | extern int kgdb_isremovedbreak(unsigned long addr); | 273 | extern int kgdb_isremovedbreak(unsigned long addr); |
274 | extern void kgdb_schedule_breakpoint(void); | ||
274 | 275 | ||
275 | extern int | 276 | extern int |
276 | kgdb_handle_exception(int ex_vector, int signo, int err_code, | 277 | kgdb_handle_exception(int ex_vector, int signo, int err_code, |
diff --git a/kernel/debug/debug_core.c b/kernel/debug/debug_core.c index 375e42f0baf0..fff59019cca0 100644 --- a/kernel/debug/debug_core.c +++ b/kernel/debug/debug_core.c | |||
@@ -114,6 +114,7 @@ EXPORT_SYMBOL_GPL(kgdb_active); | |||
114 | */ | 114 | */ |
115 | static atomic_t passive_cpu_wait[NR_CPUS]; | 115 | static atomic_t passive_cpu_wait[NR_CPUS]; |
116 | static atomic_t cpu_in_kgdb[NR_CPUS]; | 116 | static atomic_t cpu_in_kgdb[NR_CPUS]; |
117 | static atomic_t kgdb_break_tasklet_var; | ||
117 | atomic_t kgdb_setting_breakpoint; | 118 | atomic_t kgdb_setting_breakpoint; |
118 | 119 | ||
119 | struct task_struct *kgdb_usethread; | 120 | struct task_struct *kgdb_usethread; |
@@ -789,6 +790,31 @@ static void kgdb_unregister_callbacks(void) | |||
789 | } | 790 | } |
790 | } | 791 | } |
791 | 792 | ||
793 | /* | ||
794 | * There are times a tasklet needs to be used vs a compiled in | ||
795 | * break point so as to cause an exception outside a kgdb I/O module, | ||
796 | * such as is the case with kgdboe, where calling a breakpoint in the | ||
797 | * I/O driver itself would be fatal. | ||
798 | */ | ||
799 | static void kgdb_tasklet_bpt(unsigned long ing) | ||
800 | { | ||
801 | kgdb_breakpoint(); | ||
802 | atomic_set(&kgdb_break_tasklet_var, 0); | ||
803 | } | ||
804 | |||
805 | static DECLARE_TASKLET(kgdb_tasklet_breakpoint, kgdb_tasklet_bpt, 0); | ||
806 | |||
807 | void kgdb_schedule_breakpoint(void) | ||
808 | { | ||
809 | if (atomic_read(&kgdb_break_tasklet_var) || | ||
810 | atomic_read(&kgdb_active) != -1 || | ||
811 | atomic_read(&kgdb_setting_breakpoint)) | ||
812 | return; | ||
813 | atomic_inc(&kgdb_break_tasklet_var); | ||
814 | tasklet_schedule(&kgdb_tasklet_breakpoint); | ||
815 | } | ||
816 | EXPORT_SYMBOL_GPL(kgdb_schedule_breakpoint); | ||
817 | |||
792 | static void kgdb_initial_breakpoint(void) | 818 | static void kgdb_initial_breakpoint(void) |
793 | { | 819 | { |
794 | kgdb_break_asap = 0; | 820 | kgdb_break_asap = 0; |