Commit 90b9a32d authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'kdb-merge' of git://git.kernel.org/pub/scm/linux/kernel/git/jwessel/linux-2.6-kgdb

* 'kdb-merge' of git://git.kernel.org/pub/scm/linux/kernel/git/jwessel/linux-2.6-kgdb: (25 commits)
  kdb,debug_core: Allow the debug core to receive a panic notification
  MAINTAINERS: update kgdb, kdb, and debug_core info
  debug_core,kdb: Allow the debug core to process a recursive debug entry
  printk,kdb: capture printk() when in kdb shell
  kgdboc,kdb: Allow kdb to work on a non open console port
  kgdb: Add the ability to schedule a breakpoint via a tasklet
  mips,kgdb: kdb low level trap catch and stack trace
  powerpc,kgdb: Introduce low level trap catching
  x86,kgdb: Add low level debug hook
  kgdb: remove post_primary_code references
  kgdb,docs: Update the kgdb docs to include kdb
  kgdboc,keyboard: Keyboard driver for kdb with kgdb
  kgdb: gdb "monitor" -> kdb passthrough
  sparc,sunzilog: Add console polling support for sunzilog serial driver
  sh,sh-sci: Use NO_POLL_CHAR in the SCIF polled console code
  kgdb,8250,pl011: Return immediately from console poll
  kgdb: core changes to support kdb
  kdb: core for kgdb back end (2 of 2)
  kdb: core for kgdb back end (1 of 2)
  kgdb,blackfin: Add in kgdb_arch_set_pc for blackfin
  ...
parents 8b108c60 4402c153
This diff is collapsed.
...@@ -58,6 +58,7 @@ parameter is applicable: ...@@ -58,6 +58,7 @@ parameter is applicable:
ISAPNP ISA PnP code is enabled. ISAPNP ISA PnP code is enabled.
ISDN Appropriate ISDN support is enabled. ISDN Appropriate ISDN support is enabled.
JOY Appropriate joystick support is enabled. JOY Appropriate joystick support is enabled.
KGDB Kernel debugger support is enabled.
KVM Kernel Virtual Machine support is enabled. KVM Kernel Virtual Machine support is enabled.
LIBATA Libata driver is enabled LIBATA Libata driver is enabled
LP Printer support is enabled. LP Printer support is enabled.
...@@ -1120,10 +1121,15 @@ and is between 256 and 4096 characters. It is defined in the file ...@@ -1120,10 +1121,15 @@ and is between 256 and 4096 characters. It is defined in the file
use the HighMem zone if it exists, and the Normal use the HighMem zone if it exists, and the Normal
zone if it does not. zone if it does not.
kgdboc= [HW] kgdb over consoles. kgdboc= [KGDB,HW] kgdb over consoles.
Requires a tty driver that supports console polling. Requires a tty driver that supports console polling,
(only serial supported for now) or a supported polling keyboard driver (non-usb).
Format: <serial_device>[,baud] Serial only format: <serial_device>[,baud]
keyboard only format: kbd
keyboard and serial format: kbd,<serial_device>[,baud]
kgdbwait [KGDB] Stop kernel execution and enter the
kernel debugger at the earliest opportunity.
kmac= [MIPS] korina ethernet MAC address. kmac= [MIPS] korina ethernet MAC address.
Configure the RouterBoard 532 series on-chip Configure the RouterBoard 532 series on-chip
......
...@@ -3319,15 +3319,17 @@ F: include/linux/key-type.h ...@@ -3319,15 +3319,17 @@ F: include/linux/key-type.h
F: include/keys/ F: include/keys/
F: security/keys/ F: security/keys/
KGDB KGDB / KDB /debug_core
M: Jason Wessel <jason.wessel@windriver.com> M: Jason Wessel <jason.wessel@windriver.com>
W: http://kgdb.wiki.kernel.org/
L: kgdb-bugreport@lists.sourceforge.net L: kgdb-bugreport@lists.sourceforge.net
S: Maintained S: Maintained
F: Documentation/DocBook/kgdb.tmpl F: Documentation/DocBook/kgdb.tmpl
F: drivers/misc/kgdbts.c F: drivers/misc/kgdbts.c
F: drivers/serial/kgdboc.c F: drivers/serial/kgdboc.c
F: include/linux/kdb.h
F: include/linux/kgdb.h F: include/linux/kgdb.h
F: kernel/kgdb.c F: kernel/debug/
KMEMCHECK KMEMCHECK
M: Vegard Nossum <vegardno@ifi.uio.no> M: Vegard Nossum <vegardno@ifi.uio.no>
......
...@@ -20,6 +20,7 @@ enum km_type { ...@@ -20,6 +20,7 @@ enum km_type {
KM_SOFTIRQ1, KM_SOFTIRQ1,
KM_L1_CACHE, KM_L1_CACHE,
KM_L2_CACHE, KM_L2_CACHE,
KM_KDB,
KM_TYPE_NR KM_TYPE_NR
}; };
......
...@@ -98,6 +98,11 @@ sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *task) ...@@ -98,6 +98,11 @@ sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *task)
gdb_regs[_CPSR] = thread_regs->ARM_cpsr; gdb_regs[_CPSR] = thread_regs->ARM_cpsr;
} }
void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc)
{
regs->ARM_pc = pc;
}
static int compiled_break; static int compiled_break;
int kgdb_arch_handle_exception(int exception_vector, int signo, int kgdb_arch_handle_exception(int exception_vector, int signo,
......
...@@ -439,6 +439,11 @@ int kgdb_validate_break_address(unsigned long addr) ...@@ -439,6 +439,11 @@ int kgdb_validate_break_address(unsigned long addr)
return -EFAULT; return -EFAULT;
} }
void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long ip)
{
regs->retx = ip;
}
int kgdb_arch_init(void) int kgdb_arch_init(void)
{ {
kgdb_single_step = 0; kgdb_single_step = 0;
......
...@@ -38,6 +38,8 @@ extern int kgdb_early_setup; ...@@ -38,6 +38,8 @@ extern int kgdb_early_setup;
extern void *saved_vectors[32]; extern void *saved_vectors[32];
extern void handle_exception(struct pt_regs *regs); extern void handle_exception(struct pt_regs *regs);
extern void breakinst(void); extern void breakinst(void);
extern int kgdb_ll_trap(int cmd, const char *str,
struct pt_regs *regs, long err, int trap, int sig);
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
......
...@@ -180,6 +180,11 @@ void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) ...@@ -180,6 +180,11 @@ void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
*(ptr++) = regs->cp0_epc; *(ptr++) = regs->cp0_epc;
} }
void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc)
{
regs->cp0_epc = pc;
}
/* /*
* Calls linux_debug_hook before the kernel dies. If KGDB is enabled, * Calls linux_debug_hook before the kernel dies. If KGDB is enabled,
* then try to fall into the debugger * then try to fall into the debugger
...@@ -198,7 +203,7 @@ static int kgdb_mips_notify(struct notifier_block *self, unsigned long cmd, ...@@ -198,7 +203,7 @@ static int kgdb_mips_notify(struct notifier_block *self, unsigned long cmd,
if (atomic_read(&kgdb_active) != -1) if (atomic_read(&kgdb_active) != -1)
kgdb_nmicallback(smp_processor_id(), regs); kgdb_nmicallback(smp_processor_id(), regs);
if (kgdb_handle_exception(trap, compute_signal(trap), 0, regs)) if (kgdb_handle_exception(trap, compute_signal(trap), cmd, regs))
return NOTIFY_DONE; return NOTIFY_DONE;
if (atomic_read(&kgdb_setting_breakpoint)) if (atomic_read(&kgdb_setting_breakpoint))
...@@ -212,6 +217,26 @@ static int kgdb_mips_notify(struct notifier_block *self, unsigned long cmd, ...@@ -212,6 +217,26 @@ static int kgdb_mips_notify(struct notifier_block *self, unsigned long cmd,
return NOTIFY_STOP; 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_mips_notify(NULL, cmd, &args);
}
#endif /* CONFIG_KGDB_LOW_LEVEL_TRAP */
static struct notifier_block kgdb_notifier = { static struct notifier_block kgdb_notifier = {
.notifier_call = kgdb_mips_notify, .notifier_call = kgdb_mips_notify,
}; };
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <linux/kgdb.h> #include <linux/kgdb.h>
#include <linux/kdebug.h> #include <linux/kdebug.h>
#include <linux/notifier.h> #include <linux/notifier.h>
#include <linux/kdb.h>
#include <asm/bootinfo.h> #include <asm/bootinfo.h>
#include <asm/branch.h> #include <asm/branch.h>
...@@ -185,6 +186,11 @@ void show_stack(struct task_struct *task, unsigned long *sp) ...@@ -185,6 +186,11 @@ void show_stack(struct task_struct *task, unsigned long *sp)
regs.regs[29] = task->thread.reg29; regs.regs[29] = task->thread.reg29;
regs.regs[31] = 0; regs.regs[31] = 0;
regs.cp0_epc = task->thread.reg31; regs.cp0_epc = task->thread.reg31;
#ifdef CONFIG_KGDB_KDB
} else if (atomic_read(&kgdb_active) != -1 &&
kdb_current_regs) {
memcpy(&regs, kdb_current_regs, sizeof(regs));
#endif /* CONFIG_KGDB_KDB */
} else { } else {
prepare_frametrace(&regs); prepare_frametrace(&regs);
} }
...@@ -360,6 +366,8 @@ void __noreturn die(const char * str, struct pt_regs * regs) ...@@ -360,6 +366,8 @@ void __noreturn die(const char * str, struct pt_regs * regs)
unsigned long dvpret = dvpe(); unsigned long dvpret = dvpe();
#endif /* CONFIG_MIPS_MT_SMTC */ #endif /* CONFIG_MIPS_MT_SMTC */
notify_die(DIE_OOPS, str, (struct pt_regs *)regs, SIGSEGV, 0, 0);
console_verbose(); console_verbose();
spin_lock_irq(&die_lock); spin_lock_irq(&die_lock);
bust_spinlocks(1); bust_spinlocks(1);
...@@ -704,6 +712,11 @@ static void do_trap_or_bp(struct pt_regs *regs, unsigned int code, ...@@ -704,6 +712,11 @@ static void do_trap_or_bp(struct pt_regs *regs, unsigned int code,
siginfo_t info; siginfo_t info;
char b[40]; char b[40];
#ifdef CONFIG_KGDB_LOW_LEVEL_TRAP
if (kgdb_ll_trap(DIE_TRAP, str, regs, code, 0, 0) == NOTIFY_STOP)
return;
#endif /* CONFIG_KGDB_LOW_LEVEL_TRAP */
if (notify_die(DIE_TRAP, str, regs, code, 0, 0) == NOTIFY_STOP) if (notify_die(DIE_TRAP, str, regs, code, 0, 0) == NOTIFY_STOP)
return; return;
......
...@@ -26,6 +26,7 @@ enum km_type { ...@@ -26,6 +26,7 @@ enum km_type {
KM_SOFTIRQ1, KM_SOFTIRQ1,
KM_PPC_SYNC_PAGE, KM_PPC_SYNC_PAGE,
KM_PPC_SYNC_ICACHE, KM_PPC_SYNC_ICACHE,
KM_KDB,
KM_TYPE_NR KM_TYPE_NR
}; };
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <linux/smp.h> #include <linux/smp.h>
#include <linux/signal.h> #include <linux/signal.h>
#include <linux/ptrace.h> #include <linux/ptrace.h>
#include <linux/kdebug.h>
#include <asm/current.h> #include <asm/current.h>
#include <asm/processor.h> #include <asm/processor.h>
#include <asm/machdep.h> #include <asm/machdep.h>
...@@ -115,7 +116,8 @@ void kgdb_roundup_cpus(unsigned long flags) ...@@ -115,7 +116,8 @@ void kgdb_roundup_cpus(unsigned long flags)
/* KGDB functions to use existing PowerPC64 hooks. */ /* KGDB functions to use existing PowerPC64 hooks. */
static int kgdb_debugger(struct pt_regs *regs) static int kgdb_debugger(struct pt_regs *regs)
{ {
return kgdb_handle_exception(0, computeSignal(TRAP(regs)), 0, regs); return !kgdb_handle_exception(1, computeSignal(TRAP(regs)),
DIE_OOPS, regs);
} }
static int kgdb_handle_breakpoint(struct pt_regs *regs) static int kgdb_handle_breakpoint(struct pt_regs *regs)
...@@ -123,7 +125,7 @@ static int kgdb_handle_breakpoint(struct pt_regs *regs) ...@@ -123,7 +125,7 @@ static int kgdb_handle_breakpoint(struct pt_regs *regs)
if (user_mode(regs)) if (user_mode(regs))
return 0; return 0;
if (kgdb_handle_exception(0, SIGTRAP, 0, regs) != 0) if (kgdb_handle_exception(1, SIGTRAP, 0, regs) != 0)
return 0; return 0;
if (*(u32 *) (regs->nip) == *(u32 *) (&arch_kgdb_ops.gdb_bpt_instr)) if (*(u32 *) (regs->nip) == *(u32 *) (&arch_kgdb_ops.gdb_bpt_instr))
...@@ -309,6 +311,11 @@ void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs) ...@@ -309,6 +311,11 @@ void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs)
(unsigned long)(((void *)gdb_regs) + NUMREGBYTES)); (unsigned long)(((void *)gdb_regs) + NUMREGBYTES));
} }
void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc)
{
regs->nip = pc;
}
/* /*
* This function does PowerPC specific procesing for interfacing to gdb. * This function does PowerPC specific procesing for interfacing to gdb.
*/ */
......
...@@ -815,12 +815,15 @@ void __kprobes program_check_exception(struct pt_regs *regs) ...@@ -815,12 +815,15 @@ void __kprobes program_check_exception(struct pt_regs *regs)
return; return;
} }
if (reason & REASON_TRAP) { if (reason & REASON_TRAP) {
/* Debugger is first in line to stop recursive faults in
* rcu_lock, notify_die, or atomic_notifier_call_chain */
if (debugger_bpt(regs))
return;
/* trap exception */ /* trap exception */
if (notify_die(DIE_BPT, "breakpoint", regs, 5, 5, SIGTRAP) if (notify_die(DIE_BPT, "breakpoint", regs, 5, 5, SIGTRAP)
== NOTIFY_STOP) == NOTIFY_STOP)
return; return;
if (debugger_bpt(regs))
return;
if (!(regs->msr & MSR_PR) && /* not user-mode */ if (!(regs->msr & MSR_PR) && /* not user-mode */
report_bug(regs->nip, regs) == BUG_TRAP_TYPE_WARN) { report_bug(regs->nip, regs) == BUG_TRAP_TYPE_WARN) {
......
...@@ -237,6 +237,18 @@ int kgdb_arch_handle_exception(int e_vector, int signo, int err_code, ...@@ -237,6 +237,18 @@ int kgdb_arch_handle_exception(int e_vector, int signo, int err_code,
return -1; return -1;
} }
unsigned long kgdb_arch_pc(int exception, struct pt_regs *regs)
{
if (exception == 60)
return instruction_pointer(regs) - 2;
return instruction_pointer(regs);
}
void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long ip)
{
regs->pc = ip;
}
/* /*
* The primary entry points for the kgdb debug trap table entries. * The primary entry points for the kgdb debug trap table entries.
*/ */
...@@ -247,7 +259,7 @@ BUILD_TRAP_HANDLER(singlestep) ...@@ -247,7 +259,7 @@ BUILD_TRAP_HANDLER(singlestep)
local_irq_save(flags); local_irq_save(flags);
regs->pc -= instruction_size(__raw_readw(regs->pc - 4)); regs->pc -= instruction_size(__raw_readw(regs->pc - 4));
kgdb_handle_exception(vec >> 2, SIGTRAP, 0, regs); kgdb_handle_exception(0, SIGTRAP, 0, regs);
local_irq_restore(flags); local_irq_restore(flags);
} }
......
...@@ -158,6 +158,12 @@ void kgdb_arch_exit(void) ...@@ -158,6 +158,12 @@ void kgdb_arch_exit(void)
{ {
} }
void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long ip)
{
regs->pc = ip;
regs->npc = regs->pc + 4;
}
struct kgdb_arch arch_kgdb_ops = { struct kgdb_arch arch_kgdb_ops = {
/* Breakpoint instruction: ta 0x7d */ /* Breakpoint instruction: ta 0x7d */
.gdb_bpt_instr = { 0x91, 0xd0, 0x20, 0x7d }, .gdb_bpt_instr = { 0x91, 0xd0, 0x20, 0x7d },
......
...@@ -181,6 +181,12 @@ void kgdb_arch_exit(void) ...@@ -181,6 +181,12 @@ void kgdb_arch_exit(void)
{ {
} }
void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long ip)
{
regs->tpc = ip;
regs->tnpc = regs->tpc + 4;
}
struct kgdb_arch arch_kgdb_ops = { struct kgdb_arch arch_kgdb_ops = {
/* Breakpoint instruction: ta 0x72 */ /* Breakpoint instruction: ta 0x72 */
.gdb_bpt_instr = { 0x91, 0xd0, 0x20, 0x72 }, .gdb_bpt_instr = { 0x91, 0xd0, 0x20, 0x72 },
......
...@@ -76,4 +76,7 @@ static inline void arch_kgdb_breakpoint(void) ...@@ -76,4 +76,7 @@ static inline void arch_kgdb_breakpoint(void)
#define BREAK_INSTR_SIZE 1 #define BREAK_INSTR_SIZE 1
#define CACHE_FLUSH_IS_SAFE 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 */ #endif /* _ASM_X86_KGDB_H */
...@@ -47,20 +47,8 @@ ...@@ -47,20 +47,8 @@
#include <asm/debugreg.h> #include <asm/debugreg.h>
#include <asm/apicdef.h> #include <asm/apicdef.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/apic.h> #include <asm/apic.h>
/*
* Put the error code here just in case the user cares:
*/
static int gdb_x86errcode;
/*
* Likewise, the vector number here (since GDB only gets the signal
* number through the usual means, and that's not very specific):
*/
static int gdb_x86vector = -1;
/** /**
* pt_regs_to_gdb_regs - Convert ptrace regs to GDB regs * pt_regs_to_gdb_regs - Convert ptrace regs to GDB regs
* @gdb_regs: A pointer to hold the registers in the order GDB wants. * @gdb_regs: A pointer to hold the registers in the order GDB wants.
...@@ -399,23 +387,6 @@ void kgdb_disable_hw_debug(struct pt_regs *regs) ...@@ -399,23 +387,6 @@ void kgdb_disable_hw_debug(struct pt_regs *regs)
} }
} }
/**
* kgdb_post_primary_code - Save error vector/code numbers.
* @regs: Original pt_regs.
* @e_vector: Original error vector.
* @err_code: Original error code.
*
* This is needed on architectures which support SMP and KGDB.
* This function is called after all the slave cpus have been put
* to a know spin state and the primary CPU has control over KGDB.
*/
void kgdb_post_primary_code(struct pt_regs *regs, int e_vector, int err_code)
{
/* primary processor is completely in the debugger */
gdb_x86vector = e_vector;
gdb_x86errcode = err_code;
}
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
/** /**
* kgdb_roundup_cpus - Get other CPUs into a holding pattern * kgdb_roundup_cpus - Get other CPUs into a holding pattern
...@@ -567,7 +538,7 @@ static int __kgdb_notify(struct die_args *args, unsigned long cmd) ...@@ -567,7 +538,7 @@ static int __kgdb_notify(struct die_args *args, unsigned long cmd)
return NOTIFY_DONE; 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; return NOTIFY_DONE;
/* Must touch watchdog before return to normal operation */ /* Must touch watchdog before return to normal operation */
...@@ -575,6 +546,26 @@ static int __kgdb_notify(struct die_args *args, unsigned long cmd) ...@@ -575,6 +546,26 @@ static int __kgdb_notify(struct die_args *args, unsigned long cmd)
return NOTIFY_STOP; 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 static int
kgdb_notify(struct notifier_block *self, unsigned long cmd, void *ptr) kgdb_notify(struct notifier_block *self, unsigned long cmd, void *ptr)
{ {
...@@ -690,6 +681,11 @@ unsigned long kgdb_arch_pc(int exception, struct pt_regs *regs) ...@@ -690,6 +681,11 @@ unsigned long kgdb_arch_pc(int exception, struct pt_regs *regs)
return instruction_pointer(regs); return instruction_pointer(regs);
} }
void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long ip)
{
regs->ip = ip;
}
struct kgdb_arch arch_kgdb_ops = { struct kgdb_arch arch_kgdb_ops = {
/* Breakpoint instruction: */ /* Breakpoint instruction: */
.gdb_bpt_instr = { 0xcc }, .gdb_bpt_instr = { 0xcc },
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/kprobes.h> #include <linux/kprobes.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/kdebug.h> #include <linux/kdebug.h>
#include <linux/kgdb.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/ptrace.h> #include <linux/ptrace.h>
...@@ -451,6 +452,11 @@ void restart_nmi(void) ...@@ -451,6 +452,11 @@ void restart_nmi(void)
/* May run on IST stack. */ /* May run on IST stack. */
dotraplinkage void __kprobes do_int3(struct pt_regs *regs, long error_code) 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 #ifdef CONFIG_KPROBES
if (notify_die(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP) if (notify_die(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP)
== NOTIFY_STOP) == NOTIFY_STOP)
......
...@@ -1891,8 +1891,8 @@ static int serial8250_get_poll_char(struct uart_port *port) ...@@ -1891,8 +1891,8 @@ static int serial8250_get_poll_char(struct uart_port *port)
struct uart_8250_port *up = (struct uart_8250_port *)port; struct uart_8250_port *up = (struct uart_8250_port *)port;
unsigned char lsr = serial_inp(up, UART_LSR); unsigned char lsr = serial_inp(up, UART_LSR);
while (!(lsr & UART_LSR_DR)) if (!(lsr & UART_LSR_DR))
lsr = serial_inp(up, UART_LSR); return NO_POLL_CHAR;
return serial_inp(up, UART_RX); return serial_inp(up, UART_RX);
} }
......
...@@ -342,9 +342,9 @@ static int pl010_get_poll_char(struct uart_port *port) ...@@ -342,9 +342,9 @@ static int pl010_get_poll_char(struct uart_port *port)
struct uart_amba_port *uap = (struct uart_amba_port *)port; struct uart_amba_port *uap = (struct uart_amba_port *)port;
unsigned int status; unsigned int status;
do { status = readw(uap->port.membase + UART01x_FR);
status = readw(uap->port.membase + UART01x_FR); if (status & UART01x_FR_RXFE)
} while (status & UART01x_FR_RXFE); return NO_POLL_CHAR;
return readw(uap->port.membase + UART01x_DR); return readw(uap->port.membase + UART01x_DR);
} }
......
...@@ -14,7 +14,9 @@ ...@@ -14,7 +14,9 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/ctype.h> #include <linux/ctype.h>
#include <linux/kgdb.h> #include <linux/kgdb.h>
#include <linux/kdb.h>
#include <linux/tty.h> #include <linux/tty.h>
#include <linux/console.h>
#define MAX_CONFIG_LEN 40 #define MAX_CONFIG_LEN 40
...@@ -32,6 +34,40 @@ static struct kparam_string kps = { ...@@ -32,6 +34,40 @@ static struct kparam_string kps = {
static struct tty_driver *kgdb_tty_driver; static struct tty_driver *kgdb_tty_driver;
static int kgdb_tty_line; static int kgdb_tty_line;
#ifdef CONFIG_KDB_KEYBOARD
static int kgdboc_register_kbd(char **cptr)
{
if (strncmp(*cptr, "kbd", 3) == 0) {
if (kdb_poll_idx < KDB_POLL_FUNC_MAX) {
kdb_poll_funcs[kdb_poll_idx] = kdb_get_kbd_char;
kdb_poll_idx++;
if (cptr[0][3] == ',')
*cptr += 4;
else
return 1;
}
}
return 0;
}
static void kgdboc_unregister_kbd(void)
{
int i;
for (i = 0; i < kdb_poll_idx; i++) {
if (kdb_poll_funcs[i] == kdb_get_kbd_char) {
kdb_poll_idx--;
kdb_poll_funcs[i] = kdb_poll_funcs[kdb_poll_idx];
kdb_poll_funcs[kdb_poll_idx] = NULL;
i--;
}
}
}
#else /* ! CONFIG_KDB_KEYBOARD */
#define kgdboc_register_kbd(x) 0
#define kgdboc_unregister_kbd()
#endif /* ! CONFIG_KDB_KEYBOARD */
static int kgdboc_option_setup(char *opt) static int kgdboc_option_setup(char *opt)
{ {
if (strlen(opt) > MAX_CONFIG_LEN) { if (strlen(opt) > MAX_CONFIG_LEN) {
...@@ -45,25 +81,51 @@ static int kgdboc_option_setup(char *opt) ...@@ -45,25 +81,51 @@ static int kgdboc_option_setup(char *opt)
__setup("kgdboc=", kgdboc_option_setup); __setup("kgdboc=", kgdboc_option_setup);
static void cleanup_kgdboc(void)
{
kgdboc_unregister_kbd();
if (configured == 1)
kgdb_unregister_io_module(&kgdboc_io_ops);
}
static int configure_kgdboc(void) static int configure_kgdboc(void)
{ {
struct tty_driver *p; struct tty_driver *p;
int tty_line = 0; int tty_line = 0;
int err; int err;
char *cptr = config;
struct console *cons;
err = kgdboc_option_setup(config); err = kgdboc_option_setup(config);
if (err || !strlen(config) || isspace(config[0])) if (err || !strlen(config) || isspace(config[0]))
goto noconfig; goto noconfig;
err = -ENODEV; err = -ENODEV;
kgdboc_io_ops.is_console = 0;
kgdb_tty_driver = NULL;
p = tty_find_polling_driver(config, &tty_line); if (kgdboc_register_kbd(&cptr))
goto do_register;
p = tty_find_polling_driver(cptr, &tty_line);
if (!p) if (!p)
goto noconfig; goto noconfig;
cons = console_drivers;
while (cons) {
int idx;
if (cons->device && cons->device(cons, &idx) == p &&
idx == tty_line) {
kgdboc_io_ops.is_console = 1;
break;
}
cons = cons->next;
}
kgdb_tty_driver = p; kgdb_tty_driver = p;
kgdb_tty_line = tty_line; kgdb_tty_line = tty_line;
do_register:
err = kgdb_register_io_module(&kgdboc_io_ops); err = kgdb_register_io_module(&kgdboc_io_ops);
if (err) if (err)
goto noconfig; goto noconfig;
...@@ -75,6 +137,7 @@ static int configure_kgdboc(void) ...@@ -75,6 +137,7 @@ static int configure_kgdboc(void)
noconfig: noconfig:
config[0] = 0; config[0] = 0;
configured = 0; configured = 0;
cleanup_kgdboc();
return err; return err;
} }
...@@ -88,20 +151,18 @@ static int __init init_kgdboc(void) ...@@ -88,20 +151,18 @@ static int __init init_kgdboc(void)
return configure_kgdboc(); return configure_kgdboc();
} }
static void cleanup_kgdboc(void)
{
if (configured == 1)
kgdb_unregister_io_module(&kgdboc_io_ops);
}
static int kgdboc_get_char(void) static int kgdboc_get_char(void)
{ {
if (!kgdb_tty_driver)
return -1;
return kgdb_tty_driver->ops->poll_get_char(kgdb_tty_driver, return kgdb_tty_driver->ops->poll_get_char(kgdb_tty_driver,
kgdb_tty_line); kgdb_tty_line);
} }
static void kgdboc_put_char(u8 chr) static void kgdboc_put_char(u8 chr)
{ {
if (!kgdb_tty_driver)
return;
kgdb_tty_driver->ops->poll_put_char(kgdb_tty_driver, kgdb_tty_driver->ops->poll_put_char(kgdb_tty_driver,
kgdb_tty_line, chr); kgdb_tty_line, chr);
} }
......
...@@ -151,7 +151,11 @@ static int sci_poll_get_char(struct uart_port *port) ...@@ -151,7 +151,11 @@ static int sci_poll_get_char(struct uart_port *port)
handle_error(port); handle_error(port);
continue; continue;
} }
} while (!(status & SCxSR_RDxF(port))); break;
} while (1);
if (!(status & SCxSR_RDxF(port)))
return NO_POLL_CHAR;
c = sci_in(port, SCxRDR); c = sci_in(port, SCxRDR);
......
...@@ -102,6 +102,8 @@ struct uart_sunzilog_port { ...@@ -102,6 +102,8 @@ struct uart_sunzilog_port {
#endif #endif
}; };
static void sunzilog_putchar(struct uart_port *port, int ch);
#define ZILOG_CHANNEL_FROM_PORT(PORT) ((struct zilog_channel __iomem *)((PORT)->membase)) #define ZILOG_CHANNEL_FROM_PORT(PORT) ((struct zilog_channel __iomem *)((PORT)->membase))
#define UART_ZILOG(PORT) ((struct uart_sunzilog_port *)(PORT)) #define UART_ZILOG(PORT) ((struct uart_sunzilog_port *)(PORT))
...@@ -996,6 +998,50 @@ static int sunzilog_verify_port(struct uart_port *port, struct serial_struct *se ...@@ -996,6 +998,50 @@ static int sunzilog_verify_port(struct uart_port *port, struct serial_struct *se
return -EINVAL; return -EINVAL;
} }
#ifdef CONFIG_CONSOLE_POLL
static int sunzilog_get_poll_char(struct uart_port *port)
{
unsigned char ch, r1;
struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port;
struct zilog_channel __iomem *channel
= ZILOG_CHANNEL_FROM_PORT(&up->port);
r1 = read_zsreg(channel, R1);
if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR)) {
writeb(ERR_RES, &channel->control);
ZSDELAY();
ZS_WSYNC(channel);
}
ch = readb(&channel->control);
ZSDELAY();
/* This funny hack depends upon BRK_ABRT not interfering
* with the other bits we care about in R1.
*/
if (ch & BRK_ABRT)
r1 |= BRK_ABRT;
if (!(ch & Rx_CH_AV))
return NO_POLL_CHAR;
ch = readb(&channel->data);
ZSDELAY();
ch &= up->parity_mask;
return ch;
}
static void sunzilog_put_poll_char(struct uart_port *port,
unsigned char ch)
{
struct uart_sunzilog_port *up = (struct uart_sunzilog_port *)port;
sunzilog_putchar(&up->port, ch);
}
#endif /* CONFIG_CONSOLE_POLL */
static struct uart_ops sunzilog_pops = { static struct uart_ops sunzilog_pops = {
.tx_empty = sunzilog_tx_empty, .tx_empty = sunzilog_tx_empty,
.set_mctrl = sunzilog_set_mctrl, .set_mctrl = sunzilog_set_mctrl,
...@@ -1013,6 +1059,10 @@ static struct uart_ops sunzilog_pops = { ...@@ -1013,6 +1059,10 @@ static struct uart_ops sunzilog_pops = {
.request_port = sunzilog_request_port, .request_port = sunzilog_request_port,
.config_port = sunzilog_config_port, .config_port = sunzilog_config_port,
.verify_port = sunzilog_verify_port, .verify_port = sunzilog_verify_port,
#ifdef CONFIG_CONSOLE_POLL
.poll_get_char = sunzilog_get_poll_char,
.poll_put_char = sunzilog_put_poll_char,
#endif
}; };
static int uart_chip_count; static int uart_chip_count;
......
...@@ -28,7 +28,8 @@ KMAP_D(15) KM_UML_USERCOPY, ...@@ -28,7 +28,8 @@ KMAP_D(15) KM_UML_USERCOPY,
KMAP_D(16) KM_IRQ_PTE, KMAP_D(16) KM_IRQ_PTE,
KMAP_D(17) KM_NMI, KMAP_D(17) KM_NMI,
KMAP_D(18) KM_NMI_PTE, KMAP_D(18) KM_NMI_PTE,
KMAP_D(19) KM_TYPE_NR KMAP_D(19) KM_KDB,
KMAP_D(20) KM_TYPE_NR
}; };
#undef KMAP_D #undef KMAP_D
......
#ifndef _KDB_H
#define _KDB_H
/*
* Kernel Debugger Architecture Independent Global Headers
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (c) 2000-2007 Silicon Graphics, Inc. All Rights Reserved.
* Copyright (C) 2000 Stephane Eranian <eranian@hpl.hp.com>
* Copyright (C) 2009 Jason Wessel <jason.wessel@windriver.com>
*/
#ifdef CONFIG_KGDB_KDB
#include <linux/init.h>
#include <linux/sched.h>
#include <asm/atomic.h>
#define KDB_POLL_FUNC_MAX 5
extern int kdb_poll_idx;
/*
* kdb_initial_cpu is initialized to -1, and is set to the cpu
* number whenever the kernel debugger is entered.
*/
extern int kdb_initial_cpu;
extern atomic_t kdb_event;
/*
* kdb_diemsg
*
* Contains a pointer to the last string supplied to the
* kernel 'die' panic function.
*/
extern const char *kdb_diemsg;
#define KDB_FLAG_EARLYKDB (1 << 0) /* set from boot parameter kdb=early */
#define KDB_FLAG_CATASTROPHIC (1 << 1) /* A catastrophic event has occurred */
#define KDB_FLAG_CMD_INTERRUPT (1 << 2) /* Previous command was interrupted */
#define KDB_FLAG_NOIPI (1 << 3) /* Do not send IPIs */
#define KDB_FLAG_ONLY_DO_DUMP (1 << 4) /* Only do a dump, used when
* kdb is off */
#define KDB_FLAG_NO_CONSOLE (1 << 5) /* No console is available,
* kdb is disabled */
#define KDB_FLAG_NO_VT_CONSOLE (1 << 6) /* No VT console is available, do
* not use keyboard */
#define KDB_FLAG_NO_I8042 (1 << 7) /* No i8042 chip is available, do
* not use keyboard */
extern int kdb_flags; /* Global flags, see kdb_state for per cpu state */
extern void kdb_save_flags(void);
extern void kdb_restore_flags(void);
#define KDB_FLAG(flag) (kdb_flags & KDB_FLAG_##flag)
#define KDB_FLAG_SET(flag) ((void)(kdb_flags |= KDB_FLAG_##flag))
#define KDB_FLAG_CLEAR(flag) ((void)(kdb_flags &= ~KDB_FLAG_##flag))
/*
* External entry point for the kernel debugger. The pt_regs
* at the time of entry are supplied along with the reason for
* entry to the kernel debugger.
*/
typedef enum {
KDB_REASON_ENTER = 1, /* KDB_ENTER() trap/fault - regs valid */
KDB_REASON_ENTER_SLAVE, /* KDB_ENTER_SLAVE() trap/fault - regs valid */
KDB_REASON_BREAK, /* Breakpoint inst. - regs valid */
KDB_REASON_DEBUG, /* Debug Fault - regs valid */
KDB_REASON_OOPS, /* Kernel Oops - regs valid */
KDB_REASON_SWITCH, /* CPU switch - regs valid*/
KDB_REASON_KEYBOARD, /* Keyboard entry - regs valid */
KDB_REASON_NMI, /* Non-maskable interrupt; regs valid */
KDB_REASON_RECURSE, /* Recursive entry to kdb;
* regs probably valid */
KDB_REASON_SSTEP, /* Single Step trap. - regs valid */
} kdb_reason_t;
extern int kdb_trap_printk;
extern int vkdb_printf(const char *fmt, va_list args)
__attribute__ ((format (printf, 1, 0)));
extern int kdb_printf(const char *, ...)
__attribute__ ((format (printf, 1, 2)));
typedef int (*kdb_printf_t)(const char *, ...)
__attribute__ ((format (printf, 1, 2)));
extern void kdb_init(int level);
/* Access to kdb specific polling devices */
typedef int (*get_char_func)(void);
extern get_char_func kdb_poll_funcs[];
extern int kdb_get_kbd_char(void);
static inline
int kdb_process_cpu(const struct task_struct *p)
{
unsigned int cpu = task_thread_info(p)->cpu;
if (cpu > num_possible_cpus())
cpu = 0;
return cpu;
}
/* kdb access to register set for stack dumping */
extern struct pt_regs *kdb_current_regs;
#else /* ! CONFIG_KGDB_KDB */
#define kdb_printf(...)
#define kdb_init(x)
#endif /* CONFIG_KGDB_KDB */
enum {
KDB_NOT_INITIALIZED,
KDB_INIT_EARLY,
KDB_INIT_FULL,
};
#endif /* !_KDB_H */
...@@ -16,10 +16,12 @@ ...@@ -16,10 +16,12 @@
#include <linux/serial_8250.h> #include <linux/serial_8250.h>
#include <linux/linkage.h> #include <linux/linkage.h>
#include <linux/init.h> #include <linux/init.h>
#include <asm/atomic.h> #include <asm/atomic.h>
#ifdef CONFIG_HAVE_ARCH_KGDB
#include <asm/kgdb.h> #include <asm/kgdb.h>
#endif
#ifdef CONFIG_KGDB
struct pt_regs; struct pt_regs;
/** /**
...@@ -33,20 +35,6 @@ struct pt_regs; ...@@ -33,20 +35,6 @@ struct pt_regs;
*/ */
extern int kgdb_skipexception(int exception, struct pt_regs *regs); extern int kgdb_skipexception(int exception, struct pt_regs *regs);
/**
* kgdb_post_primary_code - (optional) Save error vector/code numbers.
* @regs: Original pt_regs.
* @e_vector: Original error vector.
* @err_code: Original error code.
*
* This is usually needed on architectures which support SMP and
* KGDB. This function is called after all the secondary cpus have
* been put to a know spin state and the primary CPU has control over
* KGDB.
*/
extern void kgdb_post_primary_code(struct pt_regs *regs, int e_vector,
int err_code);
/** /**
* kgdb_disable_hw_debug - (optional) Disable hardware debugging hook * kgdb_disable_hw_debug - (optional) Disable hardware debugging hook
* @regs: Current &struct pt_regs. * @regs: Current &struct pt_regs.
...@@ -72,6 +60,7 @@ struct uart_port; ...@@ -72,6 +60,7 @@ struct uart_port;
void kgdb_breakpoint(void); void kgdb_breakpoint(void);
extern int kgdb_connected; extern int kgdb_connected;
extern int kgdb_io_module_registered;
extern atomic_t kgdb_setting_breakpoint; extern atomic_t kgdb_setting_breakpoint;
extern atomic_t kgdb_cpu_doing_single_step; extern atomic_t kgdb_cpu_doing_single_step;
...@@ -202,6 +191,17 @@ kgdb_arch_handle_exception(int vector, int signo, int err_code, ...@@ -202,6 +191,17 @@ kgdb_arch_handle_exception(int vector, int signo, int err_code,
*/ */
extern void kgdb_roundup_cpus(unsigned long flags); extern void kgdb_roundup_cpus(unsigned long flags);
/**
* kgdb_arch_set_pc - Generic call back to the program counter
* @regs: Current &struct pt_regs.
* @pc: The new value for the program counter
*
* This function handles updating the program counter and requires an
* architecture specific implementation.
*/
extern void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc);
/* Optional functions. */ /* Optional functions. */
extern int kgdb_validate_break_address(unsigned long addr); extern int kgdb_validate_break_address(unsigned long addr);
extern int kgdb_arch_set_breakpoint(unsigned long addr, char *saved_instr); extern int kgdb_arch_set_breakpoint(unsigned long addr, char *saved_instr);
...@@ -247,6 +247,8 @@ struct kgdb_arch { ...@@ -247,6 +247,8 @@ struct kgdb_arch {
* the I/O driver. * the I/O driver.
* @post_exception: Pointer to a function that will do any cleanup work * @post_exception: Pointer to a function that will do any cleanup work
* for the I/O driver. * for the I/O driver.
* @is_console: 1 if the end device is a console 0 if the I/O device is
* not a console
*/ */
struct kgdb_io { struct kgdb_io {
const char *name; const char *name;
...@@ -256,6 +258,7 @@ struct kgdb_io { ...@@ -256,6 +258,7 @@ struct kgdb_io {
int (*init) (void); int (*init) (void);
void (*pre_exception) (void); void (*pre_exception) (void);
void (*post_exception) (void); void (*post_exception) (void);
int is_console;
}; };
extern struct kgdb_arch arch_kgdb_ops; extern struct kgdb_arch arch_kgdb_ops;
...@@ -264,12 +267,14 @@ extern unsigned long __weak kgdb_arch_pc(int exception, struct pt_regs *regs); ...@@ -264,12 +267,14 @@ extern unsigned long __weak kgdb_arch_pc(int exception, struct pt_regs *regs);
extern int kgdb_register_io_module(struct kgdb_io *local_kgdb_io_ops); extern int kgdb_register_io_module(struct kgdb_io *local_kgdb_io_ops);
extern void kgdb_unregister_io_module(struct kgdb_io *local_kgdb_io_ops); extern void kgdb_unregister_io_module(struct kgdb_io *local_kgdb_io_ops);
extern struct kgdb_io *dbg_io_ops;
extern int kgdb_hex2long(char **ptr, unsigned long *long_val); extern int kgdb_hex2long(char **ptr, unsigned long *long_val);
extern int kgdb_mem2hex(char *mem, char *buf, int count); extern int kgdb_mem2hex(char *mem, char *buf, int count);
extern int kgdb_hex2mem(char *buf, char *mem, int count); extern int kgdb_hex2mem(char *buf, char *mem, int count);
extern int kgdb_isremovedbreak(unsigned long addr); extern int kgdb_isremovedbreak(unsigned long addr);
extern void kgdb_schedule_breakpoint(void);
extern int extern int
kgdb_handle_exception(int ex_vector, int signo, int err_code, kgdb_handle_exception(int ex_vector, int signo, int err_code,
...@@ -278,5 +283,9 @@ extern int kgdb_nmicallback(int cpu, void *regs); ...@@ -278,5 +283,9 @@ extern int kgdb_nmicallback(int cpu, void *regs);
extern int kgdb_single_step; extern int kgdb_single_step;
extern atomic_t kgdb_active; extern atomic_t kgdb_active;
#define in_dbg_master() \
(raw_smp_processor_id() == atomic_read(&kgdb_active))
#else /* ! CONFIG_KGDB */
#define in_dbg_master() (0)
#endif /* ! CONFIG_KGDB */
#endif /* _KGDB_H_ */ #endif /* _KGDB_H_ */
...@@ -250,6 +250,7 @@ struct uart_ops { ...@@ -250,6 +250,7 @@ struct uart_ops {
#endif #endif
}; };
#define NO_POLL_CHAR 0x00ff0000
#define UART_CONFIG_TYPE (1 << 0) #define UART_CONFIG_TYPE (1 << 0)
#define UART_CONFIG_IRQ (1 << 1) #define UART_CONFIG_IRQ (1 << 1)
......
...@@ -62,6 +62,7 @@ ...@@ -62,6 +62,7 @@
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/signal.h> #include <linux/signal.h>
#include <linux/idr.h> #include <linux/idr.h>
#include <linux/kdb.h>
#include <linux/ftrace.h> #include <linux/ftrace.h>
#include <linux/async.h> #include <linux/async.h>
#include <linux/kmemcheck.h> #include <linux/kmemcheck.h>
...@@ -675,6 +676,7 @@ asmlinkage void __init start_kernel(void) ...@@ -675,6 +676,7 @@ asmlinkage void __init start_kernel(void)
buffer_init(); buffer_init();
key_init(); key_init();
security_init(); security_init();
kdb_init(KDB_INIT_FULL);
vfs_caches_init(totalram_pages); vfs_caches_init(totalram_pages);
signals_init(); signals_init();
/* rootfs populating might need page-writeback */ /* rootfs populating might need page-writeback */
......
...@@ -75,7 +75,7 @@ obj-$(CONFIG_AUDITSYSCALL) += auditsc.o ...@@ -75,7 +75,7 @@ obj-$(CONFIG_AUDITSYSCALL) += auditsc.o
obj-$(CONFIG_GCOV_KERNEL) += gcov/ obj-$(CONFIG_GCOV_KERNEL) += gcov/
obj-$(CONFIG_AUDIT_TREE) += audit_tree.o obj-$(CONFIG_AUDIT_TREE) += audit_tree.o
obj-$(CONFIG_KPROBES) += kprobes.o obj-$(CONFIG_KPROBES) += kprobes.o
obj-$(CONFIG_KGDB) += kgdb.o obj-$(CONFIG_KGDB) += debug/
obj-$(CONFIG_DETECT_SOFTLOCKUP) += softlockup.o obj-$(CONFIG_DETECT_SOFTLOCKUP) += softlockup.o
obj-$(CONFIG_DETECT_HUNG_TASK) += hung_task.o obj-$(CONFIG_DETECT_HUNG_TASK) += hung_task.o
obj-$(CONFIG_GENERIC_HARDIRQS) += irq/ obj-$(CONFIG_GENERIC_HARDIRQS) += irq/
......
#
# Makefile for the linux kernel debugger
#
obj-$(CONFIG_KGDB) += debug_core.o gdbstub.o
obj-$(CONFIG_KGDB_KDB) += kdb/
This diff is collapsed.
/*
* Created by: Jason Wessel <jason.wessel@windriver.com>
*
* Copyright (c) 2009 Wind River Systems, Inc. All Rights Reserved.
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#ifndef _DEBUG_CORE_H_
#define _DEBUG_CORE_H_
/*
* These are the private implementation headers between the kernel
* debugger core and the debugger front end code.
*/
/* kernel debug core data structures */
struct kgdb_state {
int ex_vector;
int signo;
int err_code;
int cpu;
int pass_exception;
unsigned long thr_query;
unsigned long threadid;
long kgdb_usethreadid;
struct pt_regs *linux_regs;
};
/* Exception state values */
#define DCPU_WANT_MASTER 0x1 /* Waiting to become a master kgdb cpu */
#define DCPU_NEXT_MASTER 0x2 /* Transition from one master cpu to another */
#define DCPU_IS_SLAVE 0x4 /* Slave cpu enter exception */
#define DCPU_SSTEP 0x8 /* CPU is single stepping */
struct debuggerinfo_struct {
void *debuggerinfo;
struct task_struct *task;
int exception_state;
int ret_state;
int irq_depth;
};
extern struct debuggerinfo_struct kgdb_info[];
/* kernel debug core break point routines */
extern int dbg_remove_all_break(void);
extern int dbg_set_sw_break(unsigned long addr);
extern int dbg_remove_sw_break(unsigned long addr);
extern int dbg_activate_sw_breakpoints(void);
extern int dbg_deactivate_sw_breakpoints(void);
/* polled character access to i/o module */
extern int dbg_io_get_char(void);
/* stub return value for switching between the gdbstub and kdb */
#define DBG_PASS_EVENT -12345
/* Switch from one cpu to another */
#define DBG_SWITCH_CPU_EVENT -123456
extern int dbg_switch_cpu;
/* gdbstub interface functions */
extern int gdb_serial_stub(struct kgdb_state *ks);
extern void gdbstub_msg_write(const char *s, int len);
/* gdbstub functions used for kdb <-> gdbstub transition */
extern int gdbstub_state(struct kgdb_state *ks, char *cmd);
extern int dbg_kdb_mode;
#ifdef CONFIG_KGDB_KDB
extern int kdb_stub(struct kgdb_state *ks);
extern int kdb_parse(const char *cmdstr);
#else /* ! CONFIG_KGDB_KDB */
static inline int kdb_stub(struct kgdb_state *ks)
{
return DBG_PASS_EVENT;
}
#endif /* CONFIG_KGDB_KDB */
#endif /* _DEBUG_CORE_H_ */
This diff is collapsed.
# This file is subject to the terms and conditions of the GNU General Public
# License. See the file "COPYING" in the main directory of this archive
# for more details.
#
# Copyright (c) 1999-2004 Silicon Graphics, Inc. All Rights Reserved.
# Copyright (c) 2009 Wind River Systems, Inc. All Rights Reserved.
#
CCVERSION := $(shell $(CC) -v 2>&1 | sed -ne '$$p')
obj-y := kdb_io.o kdb_main.o kdb_support.o kdb_bt.o gen-kdb_cmds.o kdb_bp.o kdb_debugger.o
obj-$(CONFIG_KDB_KEYBOARD) += kdb_keyboard.o
clean-files := gen-kdb_cmds.c
quiet_cmd_gen-kdb = GENKDB $@
cmd_gen-kdb = $(AWK) 'BEGIN {print "\#include <linux/stddef.h>"; print "\#include <linux/init.h>"} \
/^\#/{next} \
/^[ \t]*$$/{next} \
{gsub(/"/, "\\\"", $$0); \
print "static __initdata char kdb_cmd" cmds++ "[] = \"" $$0 "\\n\";"} \
END {print "extern char *kdb_cmds[]; char __initdata *kdb_cmds[] = {"; for (i = 0; i < cmds; ++i) {print " kdb_cmd" i ","}; print(" NULL\n};");}' \
$(filter-out %/Makefile,$^) > $@#
$(obj)/gen-kdb_cmds.c: $(src)/kdb_cmds $(src)/Makefile
$(call cmd,gen-kdb)
This diff is collapsed.
/*
* Kernel Debugger Architecture Independent Stack Traceback
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (c) 1999-2004 Silicon Graphics, Inc. All Rights Reserved.
* Copyright (c) 2009 Wind River Systems, Inc. All Rights Reserved.
*/
#include <linux/ctype.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/kdb.h>
#include <linux/nmi.h>
#include <asm/system.h>
#include "kdb_private.h"
static void kdb_show_stack(struct task_struct *p, void *addr)
{
int old_lvl = console_loglevel;
console_loglevel = 15;
kdb_trap_printk++;
kdb_set_current_task(p);
if (addr) {
show_stack((struct task_struct *)p, addr);
} else if (kdb_current_regs) {
#ifdef CONFIG_X86
show_stack(p, &kdb_current_regs->sp);
#else
show_stack(p, NULL);
#endif
} else {
show_stack(p, NULL);
}
console_loglevel = old_lvl;
kdb_trap_printk--;
}
/*
* kdb_bt
*
* This function implements the 'bt' command. Print a stack
* traceback.
*
* bt [<address-expression>] (addr-exp is for alternate stacks)
* btp <pid> Kernel stack for <pid>
* btt <address-expression> Kernel stack for task structure at
* <address-expression>
* bta [DRSTCZEUIMA] All useful processes, optionally
* filtered by state
* btc [<cpu>] The current process on one cpu,
* default is all cpus
*
* bt <address-expression> refers to a address on the stack, that location
* is assumed to contain a return address.
*
* btt <address-expression> refers to the address of a struct task.
*
* Inputs:
* argc argument count
* argv argument vector
* Outputs:
* None.
* Returns:
* zero for success, a kdb diagnostic if error
* Locking:
* none.
* Remarks:
* Backtrack works best when the code uses frame pointers. But even
* without frame pointers we should get a reasonable trace.
*
* mds comes in handy when examining the stack to do a manual traceback or
* to get a starting point for bt <address-expression>.
*/
static int
kdb_bt1(struct task_struct *p, unsigned long mask,
int argcount, int btaprompt)
{
char buffer[2];
if (kdb_getarea(buffer[0], (unsigned long)p) ||
kdb_getarea(buffer[0], (unsigned long)(p+1)-1))
return KDB_BADADDR;
if (!kdb_task_state(p, mask))
return 0;
kdb_printf("Stack traceback for pid %d\n", p->pid);
kdb_ps1(p);
kdb_show_stack(p, NULL);
if (btaprompt) {
kdb_getstr(buffer, sizeof(buffer),
"Enter <q> to end, <cr> to continue:");
if (buffer[0] == 'q') {
kdb_printf("\n");
return 1;
}
}
touch_nmi_watchdog();
return 0;
}
int
kdb_bt(int argc, const char **argv)
{
int diag;
int argcount = 5;
int btaprompt = 1;
int nextarg;
unsigned long addr;
long offset;
kdbgetintenv("BTARGS", &argcount); /* Arguments to print */
kdbgetintenv("BTAPROMPT", &btaprompt); /* Prompt after each
* proc in bta */
if (strcmp(argv[0], "bta") == 0) {
struct task_struct *g, *p;
unsigned long cpu;
unsigned long mask = kdb_task_state_string(argc ? argv[1] :
NULL);
if (argc == 0)
kdb_ps_suppressed();
/* Run the active tasks first */
for_each_online_cpu(cpu) {
p = kdb_curr_task(cpu);
if (kdb_bt1(p, mask, argcount, btaprompt))
return 0;
}
/* Now the inactive tasks */
kdb_do_each_thread(g, p) {
if (task_curr(p))
continue;
if (kdb_bt1(p, mask, argcount, btaprompt))
return 0;
} kdb_while_each_thread(g, p);
} else if (strcmp(argv[0], "btp") == 0) {
struct task_struct *p;
unsigned long pid;
if (argc != 1)
return KDB_ARGCOUNT;
diag = kdbgetularg((char *)argv[1], &pid);
if (diag)
return diag;
p = find_task_by_pid_ns(pid, &init_pid_ns);
if (p) {
kdb_set_current_task(p);
return kdb_bt1(p, ~0UL, argcount, 0);
}
kdb_printf("No process with pid == %ld found\n", pid);
return 0;
} else if (strcmp(argv[0], "btt") == 0) {
if (argc != 1)
return KDB_ARGCOUNT;
diag = kdbgetularg((char *)argv[1], &addr);
if (diag)
return diag;
kdb_set_current_task((struct task_struct *)addr);
return kdb_bt1((struct task_struct *)addr, ~0UL, argcount, 0);
} else if (strcmp(argv[0], "btc") == 0) {
unsigned long cpu = ~0;
struct task_struct *save_current_task = kdb_current_task;
char buf[80];
if (argc > 1)
return KDB_ARGCOUNT;
if (argc == 1) {
diag = kdbgetularg((char *)argv[1], &cpu);
if (diag)
return diag;
}
/* Recursive use of kdb_parse, do not use argv after
* this point */
argv = NULL;
if (cpu != ~0) {
if (cpu >= num_possible_cpus() || !cpu_online(cpu)) {
kdb_printf("no process for cpu %ld\n", cpu);
return 0;
}
sprintf(buf, "btt 0x%p\n", KDB_TSK(cpu));
kdb_parse(buf);
return 0;
}
kdb_printf("btc: cpu status: ");
kdb_parse("cpu\n");
for_each_online_cpu(cpu) {
sprintf(buf, "btt 0x%p\n", KDB_TSK(cpu));
kdb_parse(buf);
touch_nmi_watchdog();
}
kdb_set_current_task(save_current_task);
return 0;
} else {
if (argc) {
nextarg = 1;
diag = kdbgetaddrarg(argc, argv, &nextarg, &addr,
&offset, NULL);
if (diag)
return diag;
kdb_show_stack(kdb_current_task, (void *)addr);
return 0;
} else {
return kdb_bt1(kdb_current_task, ~0UL, argcount, 0);
}
}
/* NOTREACHED */
return 0;
}
# Initial commands for kdb, alter to suit your needs.
# These commands are executed in kdb_init() context, no SMP, no
# processes. Commands that require process data (including stack or
# registers) are not reliable this early. set and bp commands should
# be safe. Global breakpoint commands affect each cpu as it is booted.
# Standard debugging information for first level support, just type archkdb
# or archkdbcpu or archkdbshort at the kdb prompt.
defcmd dumpcommon "" "Common kdb debugging"
set BTAPROMPT 0
set LINES 10000
-summary
-cpu
-ps
-dmesg 600
-bt
endefcmd
defcmd dumpall "" "First line debugging"
set BTSYMARG 1
set BTARGS 9
pid R
-dumpcommon
-bta
endefcmd
defcmd dumpcpu "" "Same as dumpall but only tasks on cpus"
set BTSYMARG 1
set BTARGS 9
pid R
-dumpcommon
-btc
endefcmd
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/kdb.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/sched.h> /* for cond_resched */ #include <linux/sched.h> /* for cond_resched */
...@@ -516,6 +517,26 @@ static int kallsyms_open(struct inode *inode, struct file *file) ...@@ -516,6 +517,26 @@ static int kallsyms_open(struct inode *inode, struct file *file)
return ret; return ret;
} }
#ifdef CONFIG_KGDB_KDB
const char *kdb_walk_kallsyms(loff_t *pos)
{
static struct kallsym_iter kdb_walk_kallsyms_iter;
if (*pos == 0) {
memset(&kdb_walk_kallsyms_iter, 0,
sizeof(kdb_walk_kallsyms_iter));
reset_iter(&kdb_walk_kallsyms_iter, 0);
}
while (1) {
if (!update_iter(&kdb_walk_kallsyms_iter, *pos))
return NULL;
++*pos;
/* Some debugging symbols have no name. Ignore them. */
if (kdb_walk_kallsyms_iter.name[0])
return kdb_walk_kallsyms_iter.name;
}
}
#endif /* CONFIG_KGDB_KDB */
static const struct file_operations kallsyms_operations = { static const struct file_operations kallsyms_operations = {
.open = kallsyms_open, .open = kallsyms_open,
.read = seq_read, .read = seq_read,
......
...@@ -77,6 +77,10 @@ ...@@ -77,6 +77,10 @@
DEFINE_MUTEX(module_mutex); DEFINE_MUTEX(module_mutex);
EXPORT_SYMBOL_GPL(module_mutex); EXPORT_SYMBOL_GPL(module_mutex);
static LIST_HEAD(modules); static LIST_HEAD(modules);
#ifdef CONFIG_KGDB_KDB
struct list_head *kdb_modules = &modules; /* kdb needs the list of modules */
#endif /* CONFIG_KGDB_KDB */
/* Block module loading/unloading? */ /* Block module loading/unloading? */
int modules_disabled = 0; int modules_disabled = 0;
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include <linux/bootmem.h> #include <linux/bootmem.h>
#include <linux/syscalls.h> #include <linux/syscalls.h>
#include <linux/kexec.h> #include <linux/kexec.h>
#include <linux/kdb.h>
#include <linux/ratelimit.h> #include <linux/ratelimit.h>
#include <linux/kmsg_dump.h> #include <linux/kmsg_dump.h>
#include <linux/syslog.h> #include <linux/syslog.h>
...@@ -413,6 +414,22 @@ SYSCALL_DEFINE3(syslog, int, type, char __user *, buf, int, len) ...@@ -413,6 +414,22 @@ SYSCALL_DEFINE3(syslog, int, type, char __user *, buf, int, len)
return do_syslog(type, buf, len, SYSLOG_FROM_CALL); return do_syslog(type, buf, len, SYSLOG_FROM_CALL);
} }
#ifdef CONFIG_KGDB_KDB
/* kdb dmesg command needs access to the syslog buffer. do_syslog()
* uses locks so it cannot be used during debugging. Just tell kdb
* where the start and end of the physical and logical logs are. This
* is equivalent to do_syslog(3).
*/
void kdb_syslog_data(char *syslog_data[4])
{
syslog_data[0] = log_buf;
syslog_data[1] = log_buf + log_buf_len;
syslog_data[2] = log_buf + log_end -
(logged_chars < log_buf_len ? logged_chars : log_buf_len);
syslog_data[3] = log_buf + log_end;
}
#endif /* CONFIG_KGDB_KDB */
/* /*
* Call the console drivers on a range of log_buf * Call the console drivers on a range of log_buf
*/ */
...@@ -586,6 +603,14 @@ asmlinkage int printk(const char *fmt, ...) ...@@ -586,6 +603,14 @@ asmlinkage int printk(const char *fmt, ...)
va_list args; va_list args;
int r; int r;
#ifdef CONFIG_KGDB_KDB
if (unlikely(kdb_trap_printk)) {
va_start(args, fmt);
r = vkdb_printf(fmt, args);
va_end(args);
return r;
}
#endif
va_start(args, fmt); va_start(args, fmt);
r = vprintk(fmt, args); r = vprintk(fmt, args);
va_end(args); va_end(args);
......
...@@ -7759,9 +7759,9 @@ void normalize_rt_tasks(void) ...@@ -7759,9 +7759,9 @@ void normalize_rt_tasks(void)
#endif /* CONFIG_MAGIC_SYSRQ */ #endif /* CONFIG_MAGIC_SYSRQ */
#ifdef CONFIG_IA64 #if defined(CONFIG_IA64) || defined(CONFIG_KGDB_KDB)
/* /*
* These functions are only useful for the IA64 MCA handling. * These functions are only useful for the IA64 MCA handling, or kdb.
* *
* They can only be called when the whole system has been * They can only be called when the whole system has been
* stopped - every CPU needs to be quiescent, and no scheduling * stopped - every CPU needs to be quiescent, and no scheduling
...@@ -7781,6 +7781,9 @@ struct task_struct *curr_task(int cpu) ...@@ -7781,6 +7781,9 @@ struct task_struct *curr_task(int cpu)
return cpu_curr(cpu); return cpu_curr(cpu);
} }
#endif /* defined(CONFIG_IA64) || defined(CONFIG_KGDB_KDB) */
#ifdef CONFIG_IA64
/** /**
* set_curr_task - set the current task for a given cpu. * set_curr_task - set the current task for a given cpu.
* @cpu: the processor in question. * @cpu: the processor in question.
......
This diff is collapsed.
...@@ -3,7 +3,7 @@ config HAVE_ARCH_KGDB ...@@ -3,7 +3,7 @@ config HAVE_ARCH_KGDB
bool bool
menuconfig KGDB menuconfig KGDB
bool "KGDB: kernel debugging with remote gdb" bool "KGDB: kernel debugger"
depends on HAVE_ARCH_KGDB depends on HAVE_ARCH_KGDB
depends on DEBUG_KERNEL && EXPERIMENTAL depends on DEBUG_KERNEL && EXPERIMENTAL
help help
...@@ -57,4 +57,26 @@ config KGDB_TESTS_BOOT_STRING ...@@ -57,4 +57,26 @@ config KGDB_TESTS_BOOT_STRING
information about other strings you could use beyond the information about other strings you could use beyond the
default of V1F100. default of V1F100.
config KGDB_LOW_LEVEL_TRAP
bool "KGDB: Allow debugging with traps in notifiers"
depends on X86 || MIPS
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
help
KDB frontend for kernel
config KDB_KEYBOARD
bool "KGDB_KDB: keyboard as input device"
depends on VT && KGDB_KDB
default n
help
KDB can use a PS/2 type keyboard for an input device
endif # KGDB endif # KGDB
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