diff options
Diffstat (limited to 'arch/sh/kernel/kgdb.c')
-rw-r--r-- | arch/sh/kernel/kgdb.c | 64 |
1 files changed, 54 insertions, 10 deletions
diff --git a/arch/sh/kernel/kgdb.c b/arch/sh/kernel/kgdb.c index 305aad742aec..efb6d398dec3 100644 --- a/arch/sh/kernel/kgdb.c +++ b/arch/sh/kernel/kgdb.c @@ -1,7 +1,7 @@ /* * SuperH KGDB support * - * Copyright (C) 2008 Paul Mundt + * Copyright (C) 2008 - 2009 Paul Mundt * * Single stepping taken from the old stub by Henry Bell and Jeremy Siegel. * @@ -15,8 +15,6 @@ #include <linux/io.h> #include <asm/cacheflush.h> -char in_nmi = 0; /* Set during NMI to prevent re-entry */ - /* Macros for single step instruction identification */ #define OPCODE_BT(op) (((op) & 0xff00) == 0x8900) #define OPCODE_BF(op) (((op) & 0xff00) == 0x8b00) @@ -195,8 +193,6 @@ void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs) regs->gbr = gdb_regs[GDB_GBR]; regs->mach = gdb_regs[GDB_MACH]; regs->macl = gdb_regs[GDB_MACL]; - - __asm__ __volatile__ ("ldc %0, vbr" : : "r" (gdb_regs[GDB_VBR])); } void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) @@ -241,6 +237,18 @@ int kgdb_arch_handle_exception(int e_vector, int signo, int err_code, 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. */ @@ -251,28 +259,64 @@ BUILD_TRAP_HANDLER(singlestep) local_irq_save(flags); 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); } +static int __kgdb_notify(struct die_args *args, unsigned long cmd) +{ + int ret; + + switch (cmd) { + case DIE_BREAKPOINT: + /* + * This means a user thread is single stepping + * a system call which should be ignored + */ + if (test_thread_flag(TIF_SINGLESTEP)) + return NOTIFY_DONE; + + ret = kgdb_handle_exception(args->trapnr & 0xff, args->signr, + args->err, args->regs); + if (ret) + return NOTIFY_DONE; + + break; + } + + return NOTIFY_STOP; +} -BUILD_TRAP_HANDLER(breakpoint) +static int +kgdb_notify(struct notifier_block *self, unsigned long cmd, void *ptr) { unsigned long flags; - TRAP_HANDLER_DECL; + int ret; local_irq_save(flags); - kgdb_handle_exception(vec >> 2, SIGTRAP, 0, regs); + ret = __kgdb_notify(ptr, cmd); local_irq_restore(flags); + + return ret; } +static struct notifier_block kgdb_notifier = { + .notifier_call = kgdb_notify, + + /* + * Lowest-prio notifier priority, we want to be notified last: + */ + .priority = -INT_MAX, +}; + int kgdb_arch_init(void) { - return 0; + return register_die_notifier(&kgdb_notifier); } void kgdb_arch_exit(void) { + unregister_die_notifier(&kgdb_notifier); } struct kgdb_arch arch_kgdb_ops = { |