summaryrefslogtreecommitdiff
path: root/arch/sh/kernel/kgdb.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sh/kernel/kgdb.c')
-rw-r--r--arch/sh/kernel/kgdb.c64
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 = {