Commit a20ae85abaefb02cc0edf19c34f78d19437c1cf1
Exists in
master
and in
20 other branches
Merge tag 'for_linus-3.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jwessel/kgdb
Pull KGDB/KDB updates from Jason Wessel: "Fixes: - Fix KDB keyboard repeat scan codes and leaked keyboard events - Fix kernel crash with kdb_printf() for users who compile new kdb_printf()'s in early code - Return all segment registers to gdb on x86_64 Features: - KDB/KGDB hook the reboot notifier and end user can control if it stops, detaches or does nothing (updated docs as well) - Notify users who use CONFIG_DEBUG_RODATA to use hw breakpoints" * tag 'for_linus-3.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jwessel/kgdb: kdb: Add message about CONFIG_DEBUG_RODATA on failure to install breakpoint kdb: Avoid using dbg_io_ops until it is initialized kgdb,debug_core: add the ability to control the reboot notifier KDB: Fix usability issues relating to the 'enter' key. kgdb,debug-core,gdbstub: Hook the reboot notifier for debugger detach kgdb: Respect that flush op is optional kgdb: x86: Return all segment registers also in 64-bit mode
Showing 10 changed files Side-by-side Diff
Documentation/DocBook/kgdb.tmpl
... | ... | @@ -362,6 +362,23 @@ |
362 | 362 | </para> |
363 | 363 | </para> |
364 | 364 | </sect1> |
365 | + <sect1 id="kgdbreboot"> | |
366 | + <title>Run time parameter: kgdbreboot</title> | |
367 | + <para> The kgdbreboot feature allows you to change how the debugger | |
368 | + deals with the reboot notification. You have 3 choices for the | |
369 | + behavior. The default behavior is always set to 0.</para> | |
370 | + <orderedlist> | |
371 | + <listitem><para>echo -1 > /sys/module/debug_core/parameters/kgdbreboot</para> | |
372 | + <para>Ignore the reboot notification entirely.</para> | |
373 | + </listitem> | |
374 | + <listitem><para>echo 0 > /sys/module/debug_core/parameters/kgdbreboot</para> | |
375 | + <para>Send the detach message to any attached debugger client.</para> | |
376 | + </listitem> | |
377 | + <listitem><para>echo 1 > /sys/module/debug_core/parameters/kgdbreboot</para> | |
378 | + <para>Enter the debugger on reboot notify.</para> | |
379 | + </listitem> | |
380 | + </orderedlist> | |
381 | + </sect1> | |
365 | 382 | </chapter> |
366 | 383 | <chapter id="usingKDB"> |
367 | 384 | <title>Using kdb</title> |
arch/x86/include/asm/kgdb.h
... | ... | @@ -64,11 +64,15 @@ |
64 | 64 | GDB_PS, /* 17 */ |
65 | 65 | GDB_CS, /* 18 */ |
66 | 66 | GDB_SS, /* 19 */ |
67 | + GDB_DS, /* 20 */ | |
68 | + GDB_ES, /* 21 */ | |
69 | + GDB_FS, /* 22 */ | |
70 | + GDB_GS, /* 23 */ | |
67 | 71 | }; |
68 | 72 | #define GDB_ORIG_AX 57 |
69 | -#define DBG_MAX_REG_NUM 20 | |
70 | -/* 17 64 bit regs and 3 32 bit regs */ | |
71 | -#define NUMREGBYTES ((17 * 8) + (3 * 4)) | |
73 | +#define DBG_MAX_REG_NUM 24 | |
74 | +/* 17 64 bit regs and 5 32 bit regs */ | |
75 | +#define NUMREGBYTES ((17 * 8) + (5 * 4)) | |
72 | 76 | #endif /* ! CONFIG_X86_32 */ |
73 | 77 | |
74 | 78 | static inline void arch_kgdb_breakpoint(void) |
arch/x86/kernel/kgdb.c
... | ... | @@ -67,8 +67,6 @@ |
67 | 67 | { "ss", 4, offsetof(struct pt_regs, ss) }, |
68 | 68 | { "ds", 4, offsetof(struct pt_regs, ds) }, |
69 | 69 | { "es", 4, offsetof(struct pt_regs, es) }, |
70 | - { "fs", 4, -1 }, | |
71 | - { "gs", 4, -1 }, | |
72 | 70 | #else |
73 | 71 | { "ax", 8, offsetof(struct pt_regs, ax) }, |
74 | 72 | { "bx", 8, offsetof(struct pt_regs, bx) }, |
75 | 73 | |
... | ... | @@ -90,7 +88,11 @@ |
90 | 88 | { "flags", 4, offsetof(struct pt_regs, flags) }, |
91 | 89 | { "cs", 4, offsetof(struct pt_regs, cs) }, |
92 | 90 | { "ss", 4, offsetof(struct pt_regs, ss) }, |
91 | + { "ds", 4, -1 }, | |
92 | + { "es", 4, -1 }, | |
93 | 93 | #endif |
94 | + { "fs", 4, -1 }, | |
95 | + { "gs", 4, -1 }, | |
94 | 96 | }; |
95 | 97 | |
96 | 98 | int dbg_set_reg(int regno, void *mem, struct pt_regs *regs) |
kernel/debug/debug_core.c
... | ... | @@ -41,6 +41,7 @@ |
41 | 41 | #include <linux/delay.h> |
42 | 42 | #include <linux/sched.h> |
43 | 43 | #include <linux/sysrq.h> |
44 | +#include <linux/reboot.h> | |
44 | 45 | #include <linux/init.h> |
45 | 46 | #include <linux/kgdb.h> |
46 | 47 | #include <linux/kdb.h> |
... | ... | @@ -75,6 +76,8 @@ |
75 | 76 | struct kgdb_io *dbg_io_ops; |
76 | 77 | static DEFINE_SPINLOCK(kgdb_registration_lock); |
77 | 78 | |
79 | +/* Action for the reboot notifiter, a global allow kdb to change it */ | |
80 | +static int kgdbreboot; | |
78 | 81 | /* kgdb console driver is loaded */ |
79 | 82 | static int kgdb_con_registered; |
80 | 83 | /* determine if kgdb console output should be used */ |
... | ... | @@ -96,6 +99,7 @@ |
96 | 99 | early_param("kgdbcon", opt_kgdb_con); |
97 | 100 | |
98 | 101 | module_param(kgdb_use_con, int, 0644); |
102 | +module_param(kgdbreboot, int, 0644); | |
99 | 103 | |
100 | 104 | /* |
101 | 105 | * Holds information about breakpoints in a kernel. These breakpoints are |
... | ... | @@ -784,6 +788,33 @@ |
784 | 788 | kdb_init(KDB_INIT_FULL); |
785 | 789 | } |
786 | 790 | |
791 | +static int | |
792 | +dbg_notify_reboot(struct notifier_block *this, unsigned long code, void *x) | |
793 | +{ | |
794 | + /* | |
795 | + * Take the following action on reboot notify depending on value: | |
796 | + * 1 == Enter debugger | |
797 | + * 0 == [the default] detatch debug client | |
798 | + * -1 == Do nothing... and use this until the board resets | |
799 | + */ | |
800 | + switch (kgdbreboot) { | |
801 | + case 1: | |
802 | + kgdb_breakpoint(); | |
803 | + case -1: | |
804 | + goto done; | |
805 | + } | |
806 | + if (!dbg_kdb_mode) | |
807 | + gdbstub_exit(code); | |
808 | +done: | |
809 | + return NOTIFY_DONE; | |
810 | +} | |
811 | + | |
812 | +static struct notifier_block dbg_reboot_notifier = { | |
813 | + .notifier_call = dbg_notify_reboot, | |
814 | + .next = NULL, | |
815 | + .priority = INT_MAX, | |
816 | +}; | |
817 | + | |
787 | 818 | static void kgdb_register_callbacks(void) |
788 | 819 | { |
789 | 820 | if (!kgdb_io_module_registered) { |
... | ... | @@ -791,6 +822,7 @@ |
791 | 822 | kgdb_arch_init(); |
792 | 823 | if (!dbg_is_early) |
793 | 824 | kgdb_arch_late(); |
825 | + register_reboot_notifier(&dbg_reboot_notifier); | |
794 | 826 | atomic_notifier_chain_register(&panic_notifier_list, |
795 | 827 | &kgdb_panic_event_nb); |
796 | 828 | #ifdef CONFIG_MAGIC_SYSRQ |
... | ... | @@ -812,6 +844,7 @@ |
812 | 844 | */ |
813 | 845 | if (kgdb_io_module_registered) { |
814 | 846 | kgdb_io_module_registered = 0; |
847 | + unregister_reboot_notifier(&dbg_reboot_notifier); | |
815 | 848 | atomic_notifier_chain_unregister(&panic_notifier_list, |
816 | 849 | &kgdb_panic_event_nb); |
817 | 850 | kgdb_arch_exit(); |
kernel/debug/gdbstub.c
... | ... | @@ -1111,6 +1111,13 @@ |
1111 | 1111 | unsigned char checksum, ch, buffer[3]; |
1112 | 1112 | int loop; |
1113 | 1113 | |
1114 | + if (!kgdb_connected) | |
1115 | + return; | |
1116 | + kgdb_connected = 0; | |
1117 | + | |
1118 | + if (!dbg_io_ops || dbg_kdb_mode) | |
1119 | + return; | |
1120 | + | |
1114 | 1121 | buffer[0] = 'W'; |
1115 | 1122 | buffer[1] = hex_asc_hi(status); |
1116 | 1123 | buffer[2] = hex_asc_lo(status); |
... | ... | @@ -1129,6 +1136,7 @@ |
1129 | 1136 | dbg_io_ops->write_char(hex_asc_lo(checksum)); |
1130 | 1137 | |
1131 | 1138 | /* make sure the output is flushed, lest the bootloader clobber it */ |
1132 | - dbg_io_ops->flush(); | |
1139 | + if (dbg_io_ops->flush) | |
1140 | + dbg_io_ops->flush(); | |
1133 | 1141 | } |
kernel/debug/kdb/kdb_bp.c
... | ... | @@ -153,6 +153,13 @@ |
153 | 153 | } else { |
154 | 154 | kdb_printf("%s: failed to set breakpoint at 0x%lx\n", |
155 | 155 | __func__, bp->bp_addr); |
156 | +#ifdef CONFIG_DEBUG_RODATA | |
157 | + if (!bp->bp_type) { | |
158 | + kdb_printf("Software breakpoints are unavailable.\n" | |
159 | + " Change the kernel CONFIG_DEBUG_RODATA=n\n" | |
160 | + " OR use hw breaks: help bph\n"); | |
161 | + } | |
162 | +#endif | |
156 | 163 | return 1; |
157 | 164 | } |
158 | 165 | return 0; |
kernel/debug/kdb/kdb_io.c
... | ... | @@ -689,7 +689,7 @@ |
689 | 689 | if (!dbg_kdb_mode && kgdb_connected) { |
690 | 690 | gdbstub_msg_write(kdb_buffer, retlen); |
691 | 691 | } else { |
692 | - if (!dbg_io_ops->is_console) { | |
692 | + if (dbg_io_ops && !dbg_io_ops->is_console) { | |
693 | 693 | len = strlen(kdb_buffer); |
694 | 694 | cp = kdb_buffer; |
695 | 695 | while (len--) { |
kernel/debug/kdb/kdb_keyboard.c
... | ... | @@ -25,6 +25,7 @@ |
25 | 25 | #define KBD_STAT_MOUSE_OBF 0x20 /* Mouse output buffer full */ |
26 | 26 | |
27 | 27 | static int kbd_exists; |
28 | +static int kbd_last_ret; | |
28 | 29 | |
29 | 30 | /* |
30 | 31 | * Check if the keyboard controller has a keypress for us. |
31 | 32 | |
... | ... | @@ -90,8 +91,11 @@ |
90 | 91 | return -1; |
91 | 92 | } |
92 | 93 | |
93 | - if ((scancode & 0x80) != 0) | |
94 | + if ((scancode & 0x80) != 0) { | |
95 | + if (scancode == 0x9c) | |
96 | + kbd_last_ret = 0; | |
94 | 97 | return -1; |
98 | + } | |
95 | 99 | |
96 | 100 | scancode &= 0x7f; |
97 | 101 | |
98 | 102 | |
99 | 103 | |
100 | 104 | |
101 | 105 | |
102 | 106 | |
103 | 107 | |
104 | 108 | |
... | ... | @@ -178,36 +182,83 @@ |
178 | 182 | return -1; /* ignore unprintables */ |
179 | 183 | } |
180 | 184 | |
181 | - if ((scancode & 0x7f) == 0x1c) { | |
182 | - /* | |
183 | - * enter key. All done. Absorb the release scancode. | |
184 | - */ | |
185 | + if (scancode == 0x1c) { | |
186 | + kbd_last_ret = 1; | |
187 | + return 13; | |
188 | + } | |
189 | + | |
190 | + return keychar & 0xff; | |
191 | +} | |
192 | +EXPORT_SYMBOL_GPL(kdb_get_kbd_char); | |
193 | + | |
194 | +/* | |
195 | + * Best effort cleanup of ENTER break codes on leaving KDB. Called on | |
196 | + * exiting KDB, when we know we processed an ENTER or KP ENTER scan | |
197 | + * code. | |
198 | + */ | |
199 | +void kdb_kbd_cleanup_state(void) | |
200 | +{ | |
201 | + int scancode, scanstatus; | |
202 | + | |
203 | + /* | |
204 | + * Nothing to clean up, since either | |
205 | + * ENTER was never pressed, or has already | |
206 | + * gotten cleaned up. | |
207 | + */ | |
208 | + if (!kbd_last_ret) | |
209 | + return; | |
210 | + | |
211 | + kbd_last_ret = 0; | |
212 | + /* | |
213 | + * Enter key. Need to absorb the break code here, lest it gets | |
214 | + * leaked out if we exit KDB as the result of processing 'g'. | |
215 | + * | |
216 | + * This has several interesting implications: | |
217 | + * + Need to handle KP ENTER, which has break code 0xe0 0x9c. | |
218 | + * + Need to handle repeat ENTER and repeat KP ENTER. Repeats | |
219 | + * only get a break code at the end of the repeated | |
220 | + * sequence. This means we can't propagate the repeated key | |
221 | + * press, and must swallow it away. | |
222 | + * + Need to handle possible PS/2 mouse input. | |
223 | + * + Need to handle mashed keys. | |
224 | + */ | |
225 | + | |
226 | + while (1) { | |
185 | 227 | while ((inb(KBD_STATUS_REG) & KBD_STAT_OBF) == 0) |
186 | - ; | |
228 | + cpu_relax(); | |
187 | 229 | |
188 | 230 | /* |
189 | - * Fetch the scancode | |
231 | + * Fetch the scancode. | |
190 | 232 | */ |
191 | 233 | scancode = inb(KBD_DATA_REG); |
192 | 234 | scanstatus = inb(KBD_STATUS_REG); |
193 | 235 | |
194 | - while (scanstatus & KBD_STAT_MOUSE_OBF) { | |
195 | - scancode = inb(KBD_DATA_REG); | |
196 | - scanstatus = inb(KBD_STATUS_REG); | |
197 | - } | |
236 | + /* | |
237 | + * Skip mouse input. | |
238 | + */ | |
239 | + if (scanstatus & KBD_STAT_MOUSE_OBF) | |
240 | + continue; | |
198 | 241 | |
199 | - if (scancode != 0x9c) { | |
200 | - /* | |
201 | - * Wasn't an enter-release, why not? | |
202 | - */ | |
203 | - kdb_printf("kdb: expected enter got 0x%x status 0x%x\n", | |
204 | - scancode, scanstatus); | |
205 | - } | |
242 | + /* | |
243 | + * If we see 0xe0, this is either a break code for KP | |
244 | + * ENTER, or a repeat make for KP ENTER. Either way, | |
245 | + * since the second byte is equivalent to an ENTER, | |
246 | + * skip the 0xe0 and try again. | |
247 | + * | |
248 | + * If we see 0x1c, this must be a repeat ENTER or KP | |
249 | + * ENTER (and we swallowed 0xe0 before). Try again. | |
250 | + * | |
251 | + * We can also see make and break codes for other keys | |
252 | + * mashed before or after pressing ENTER. Thus, if we | |
253 | + * see anything other than 0x9c, we have to try again. | |
254 | + * | |
255 | + * Note, if you held some key as ENTER was depressed, | |
256 | + * that break code would get leaked out. | |
257 | + */ | |
258 | + if (scancode != 0x9c) | |
259 | + continue; | |
206 | 260 | |
207 | - return 13; | |
261 | + return; | |
208 | 262 | } |
209 | - | |
210 | - return keychar & 0xff; | |
211 | 263 | } |
212 | -EXPORT_SYMBOL_GPL(kdb_get_kbd_char); |
kernel/debug/kdb/kdb_main.c
kernel/debug/kdb/kdb_private.h
... | ... | @@ -246,6 +246,13 @@ |
246 | 246 | |
247 | 247 | extern void kdb_set_current_task(struct task_struct *); |
248 | 248 | extern struct task_struct *kdb_current_task; |
249 | + | |
250 | +#ifdef CONFIG_KDB_KEYBOARD | |
251 | +extern void kdb_kbd_cleanup_state(void); | |
252 | +#else /* ! CONFIG_KDB_KEYBOARD */ | |
253 | +#define kdb_kbd_cleanup_state() | |
254 | +#endif /* ! CONFIG_KDB_KEYBOARD */ | |
255 | + | |
249 | 256 | #ifdef CONFIG_MODULES |
250 | 257 | extern struct list_head *kdb_modules; |
251 | 258 | #endif /* CONFIG_MODULES */ |