Commit 6c536a17 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'for_linus-3.7' of git://git.kernel.org/pub/scm/linux/kernel/git/jwessel/kgdb

Pull KGDB/KDB fixes and cleanups from Jason Wessel:
 "Cleanups
   - Clean up compile warnings in kgdboc.c and x86/kernel/kgdb.c
   - Add module event hooks for simplified debugging with gdb
 Fixes
   - Fix kdb to stop paging with 'q' on bta and dmesg
   - Fix for data that scrolls off the vga console due to line wrapping
     when using the kdb pager
 New
   - The debug core registers for kernel module events which allows a
     kernel aware gdb to automatically load symbols and break on entry
     to a kernel module
   - Allow kgdboc=kdb to setup kdb on the vga console"

* tag 'for_linus-3.7' of git://git.kernel.org/pub/scm/linux/kernel/git/jwessel/kgdb:
  tty/console: fix warnings in drivers/tty/serial/kgdboc.c
  kdb,vt_console: Fix missed data due to pager overruns
  kdb: Fix dmesg/bta scroll to quit with 'q'
  kgdboc: Accept either kbd or kdb to activate the vga + keyboard kdb shell
  kgdb,x86: fix warning about unused variable
  mips,kgdb: fix recursive page fault with CONFIG_KPROBES
  kgdb: Add module event hooks
parents ba8a3d6c f2f0945e
...@@ -283,6 +283,15 @@ static int kgdb_mips_notify(struct notifier_block *self, unsigned long cmd, ...@@ -283,6 +283,15 @@ static int kgdb_mips_notify(struct notifier_block *self, unsigned long cmd,
struct pt_regs *regs = args->regs; struct pt_regs *regs = args->regs;
int trap = (regs->cp0_cause & 0x7c) >> 2; int trap = (regs->cp0_cause & 0x7c) >> 2;
#ifdef CONFIG_KPROBES
/*
* Return immediately if the kprobes fault notifier has set
* DIE_PAGE_FAULT.
*/
if (cmd == DIE_PAGE_FAULT)
return NOTIFY_DONE;
#endif /* CONFIG_KPROBES */
/* Userspace events, ignore. */ /* Userspace events, ignore. */
if (user_mode(regs)) if (user_mode(regs))
return NOTIFY_DONE; return NOTIFY_DONE;
......
...@@ -746,7 +746,9 @@ void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long ip) ...@@ -746,7 +746,9 @@ void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long ip)
int kgdb_arch_set_breakpoint(struct kgdb_bkpt *bpt) int kgdb_arch_set_breakpoint(struct kgdb_bkpt *bpt)
{ {
int err; int err;
#ifdef CONFIG_DEBUG_RODATA
char opc[BREAK_INSTR_SIZE]; char opc[BREAK_INSTR_SIZE];
#endif /* CONFIG_DEBUG_RODATA */
bpt->type = BP_BREAKPOINT; bpt->type = BP_BREAKPOINT;
err = probe_kernel_read(bpt->saved_instr, (char *)bpt->bpt_addr, err = probe_kernel_read(bpt->saved_instr, (char *)bpt->bpt_addr,
......
...@@ -97,7 +97,8 @@ static void kgdboc_restore_input(void) ...@@ -97,7 +97,8 @@ static void kgdboc_restore_input(void)
static int kgdboc_register_kbd(char **cptr) static int kgdboc_register_kbd(char **cptr)
{ {
if (strncmp(*cptr, "kbd", 3) == 0) { if (strncmp(*cptr, "kbd", 3) == 0 ||
strncmp(*cptr, "kdb", 3) == 0) {
if (kdb_poll_idx < KDB_POLL_FUNC_MAX) { if (kdb_poll_idx < KDB_POLL_FUNC_MAX) {
kdb_poll_funcs[kdb_poll_idx] = kdb_get_kbd_char; kdb_poll_funcs[kdb_poll_idx] = kdb_get_kbd_char;
kdb_poll_idx++; kdb_poll_idx++;
......
...@@ -3442,6 +3442,19 @@ int con_debug_enter(struct vc_data *vc) ...@@ -3442,6 +3442,19 @@ int con_debug_enter(struct vc_data *vc)
kdb_set(2, setargs); kdb_set(2, setargs);
} }
} }
if (vc->vc_cols < 999) {
int colcount;
char cols[4];
const char *setargs[3] = {
"set",
"COLUMNS",
cols,
};
if (kdbgetintenv(setargs[0], &colcount)) {
snprintf(cols, 4, "%i", vc->vc_cols);
kdb_set(2, setargs);
}
}
#endif /* CONFIG_KGDB_KDB */ #endif /* CONFIG_KGDB_KDB */
return ret; return ret;
} }
......
...@@ -83,8 +83,14 @@ void give_up_console(const struct consw *sw); ...@@ -83,8 +83,14 @@ void give_up_console(const struct consw *sw);
int con_debug_enter(struct vc_data *vc); int con_debug_enter(struct vc_data *vc);
int con_debug_leave(void); int con_debug_leave(void);
#else #else
#define con_debug_enter(vc) (0) static inline int con_debug_enter(struct vc_data *vc)
#define con_debug_leave() (0) {
return 0;
}
static inline int con_debug_leave(void)
{
return 0;
}
#endif #endif
/* scroll */ /* scroll */
......
...@@ -696,6 +696,22 @@ kgdb_handle_exception(int evector, int signo, int ecode, struct pt_regs *regs) ...@@ -696,6 +696,22 @@ kgdb_handle_exception(int evector, int signo, int ecode, struct pt_regs *regs)
return ret; return ret;
} }
/*
* GDB places a breakpoint at this function to know dynamically
* loaded objects. It's not defined static so that only one instance with this
* name exists in the kernel.
*/
static int module_event(struct notifier_block *self, unsigned long val,
void *data)
{
return 0;
}
static struct notifier_block dbg_module_load_nb = {
.notifier_call = module_event,
};
int kgdb_nmicallback(int cpu, void *regs) int kgdb_nmicallback(int cpu, void *regs)
{ {
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
...@@ -824,6 +840,7 @@ static void kgdb_register_callbacks(void) ...@@ -824,6 +840,7 @@ static void kgdb_register_callbacks(void)
kgdb_arch_init(); kgdb_arch_init();
if (!dbg_is_early) if (!dbg_is_early)
kgdb_arch_late(); kgdb_arch_late();
register_module_notifier(&dbg_module_load_nb);
register_reboot_notifier(&dbg_reboot_notifier); register_reboot_notifier(&dbg_reboot_notifier);
atomic_notifier_chain_register(&panic_notifier_list, atomic_notifier_chain_register(&panic_notifier_list,
&kgdb_panic_event_nb); &kgdb_panic_event_nb);
...@@ -847,6 +864,7 @@ static void kgdb_unregister_callbacks(void) ...@@ -847,6 +864,7 @@ static void kgdb_unregister_callbacks(void)
if (kgdb_io_module_registered) { if (kgdb_io_module_registered) {
kgdb_io_module_registered = 0; kgdb_io_module_registered = 0;
unregister_reboot_notifier(&dbg_reboot_notifier); unregister_reboot_notifier(&dbg_reboot_notifier);
unregister_module_notifier(&dbg_module_load_nb);
atomic_notifier_chain_unregister(&panic_notifier_list, atomic_notifier_chain_unregister(&panic_notifier_list,
&kgdb_panic_event_nb); &kgdb_panic_event_nb);
kgdb_arch_exit(); kgdb_arch_exit();
......
...@@ -129,6 +129,8 @@ kdb_bt(int argc, const char **argv) ...@@ -129,6 +129,8 @@ kdb_bt(int argc, const char **argv)
} }
/* Now the inactive tasks */ /* Now the inactive tasks */
kdb_do_each_thread(g, p) { kdb_do_each_thread(g, p) {
if (KDB_FLAG(CMD_INTERRUPT))
return 0;
if (task_curr(p)) if (task_curr(p))
continue; continue;
if (kdb_bt1(p, mask, argcount, btaprompt)) if (kdb_bt1(p, mask, argcount, btaprompt))
......
...@@ -552,6 +552,7 @@ int vkdb_printf(const char *fmt, va_list ap) ...@@ -552,6 +552,7 @@ int vkdb_printf(const char *fmt, va_list ap)
{ {
int diag; int diag;
int linecount; int linecount;
int colcount;
int logging, saved_loglevel = 0; int logging, saved_loglevel = 0;
int saved_trap_printk; int saved_trap_printk;
int got_printf_lock = 0; int got_printf_lock = 0;
...@@ -584,6 +585,10 @@ int vkdb_printf(const char *fmt, va_list ap) ...@@ -584,6 +585,10 @@ int vkdb_printf(const char *fmt, va_list ap)
if (diag || linecount <= 1) if (diag || linecount <= 1)
linecount = 24; linecount = 24;
diag = kdbgetintenv("COLUMNS", &colcount);
if (diag || colcount <= 1)
colcount = 80;
diag = kdbgetintenv("LOGGING", &logging); diag = kdbgetintenv("LOGGING", &logging);
if (diag) if (diag)
logging = 0; logging = 0;
...@@ -690,7 +695,7 @@ int vkdb_printf(const char *fmt, va_list ap) ...@@ -690,7 +695,7 @@ int vkdb_printf(const char *fmt, va_list ap)
gdbstub_msg_write(kdb_buffer, retlen); gdbstub_msg_write(kdb_buffer, retlen);
} else { } else {
if (dbg_io_ops && !dbg_io_ops->is_console) { if (dbg_io_ops && !dbg_io_ops->is_console) {
len = strlen(kdb_buffer); len = retlen;
cp = kdb_buffer; cp = kdb_buffer;
while (len--) { while (len--) {
dbg_io_ops->write_char(*cp); dbg_io_ops->write_char(*cp);
...@@ -709,11 +714,29 @@ int vkdb_printf(const char *fmt, va_list ap) ...@@ -709,11 +714,29 @@ int vkdb_printf(const char *fmt, va_list ap)
printk(KERN_INFO "%s", kdb_buffer); printk(KERN_INFO "%s", kdb_buffer);
} }
if (KDB_STATE(PAGER) && strchr(kdb_buffer, '\n')) if (KDB_STATE(PAGER)) {
/*
* Check printed string to decide how to bump the
* kdb_nextline to control when the more prompt should
* show up.
*/
int got = 0;
len = retlen;
while (len--) {
if (kdb_buffer[len] == '\n') {
kdb_nextline++; kdb_nextline++;
got = 0;
} else if (kdb_buffer[len] == '\r') {
got = 0;
} else {
got++;
}
}
kdb_nextline += got / (colcount + 1);
}
/* check for having reached the LINES number of printed lines */ /* check for having reached the LINES number of printed lines */
if (kdb_nextline == linecount) { if (kdb_nextline >= linecount) {
char buf1[16] = ""; char buf1[16] = "";
/* Watch out for recursion here. Any routine that calls /* Watch out for recursion here. Any routine that calls
...@@ -765,7 +788,7 @@ int vkdb_printf(const char *fmt, va_list ap) ...@@ -765,7 +788,7 @@ int vkdb_printf(const char *fmt, va_list ap)
kdb_grepping_flag = 0; kdb_grepping_flag = 0;
kdb_printf("\n"); kdb_printf("\n");
} else if (buf1[0] == ' ') { } else if (buf1[0] == ' ') {
kdb_printf("\n"); kdb_printf("\r");
suspend_grep = 1; /* for this recursion */ suspend_grep = 1; /* for this recursion */
} else if (buf1[0] == '\n') { } else if (buf1[0] == '\n') {
kdb_nextline = linecount - 1; kdb_nextline = linecount - 1;
......
...@@ -2101,6 +2101,8 @@ static int kdb_dmesg(int argc, const char **argv) ...@@ -2101,6 +2101,8 @@ static int kdb_dmesg(int argc, const char **argv)
} }
if (!lines--) if (!lines--)
break; break;
if (KDB_FLAG(CMD_INTERRUPT))
return 0;
kdb_printf("%.*s\n", (int)len - 1, buf); kdb_printf("%.*s\n", (int)len - 1, buf);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment