summaryrefslogtreecommitdiff
path: root/arch/tile/kernel/traps.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/tile/kernel/traps.c')
-rw-r--r--arch/tile/kernel/traps.c45
1 files changed, 44 insertions, 1 deletions
diff --git a/arch/tile/kernel/traps.c b/arch/tile/kernel/traps.c
index a1bbc5de4d00..cfff6f958d58 100644
--- a/arch/tile/kernel/traps.c
+++ b/arch/tile/kernel/traps.c
@@ -15,6 +15,7 @@
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/kprobes.h>
+#include <linux/kdebug.h>
#include <linux/module.h>
#include <linux/reboot.h>
#include <linux/uaccess.h>
@@ -214,6 +215,43 @@ static const char *const int_name[] = {
#endif
};
+static int do_bpt(struct pt_regs *regs)
+{
+ unsigned long bundle, bcode, bpt;
+
+ bundle = *(unsigned long *)instruction_pointer(regs);
+
+ /*
+ * bpt shoule be { bpt; nop }, which is 0x286a44ae51485000ULL.
+ * we encode the unused least significant bits for other purpose.
+ */
+ bpt = bundle & ~((1ULL << 12) - 1);
+ if (bpt != TILE_BPT_BUNDLE)
+ return 0;
+
+ bcode = bundle & ((1ULL << 12) - 1);
+ /*
+ * notify the kprobe handlers, if instruction is likely to
+ * pertain to them.
+ */
+ switch (bcode) {
+ /* breakpoint_insn */
+ case 0:
+ notify_die(DIE_BREAK, "debug", regs, bundle,
+ INT_ILL, SIGTRAP);
+ break;
+ /* breakpoint2_insn */
+ case DIE_SSTEPBP:
+ notify_die(DIE_SSTEPBP, "single_step", regs, bundle,
+ INT_ILL, SIGTRAP);
+ break;
+ default:
+ return 0;
+ }
+
+ return 1;
+}
+
void __kprobes do_trap(struct pt_regs *regs, int fault_num,
unsigned long reason)
{
@@ -221,6 +259,11 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num,
int signo, code;
unsigned long address = 0;
bundle_bits instr;
+ int is_kernel = !user_mode(regs);
+
+ /* Handle breakpoints, etc. */
+ if (is_kernel && fault_num == INT_ILL && do_bpt(regs))
+ return;
/* Re-enable interrupts, if they were previously enabled. */
if (!(regs->flags & PT_FLAGS_DISABLE_IRQ))
@@ -230,7 +273,7 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num,
* If it hits in kernel mode and we can't fix it up, just exit the
* current process and hope for the best.
*/
- if (!user_mode(regs)) {
+ if (is_kernel) {
const char *name;
char buf[100];
if (fixup_exception(regs)) /* ILL_TRANS or UNALIGN_DATA */