linux-arch.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Vineet Gupta <Vineet.Gupta1@synopsys.com>
To: linux-arch@vger.kernel.org, linux-kernel@vger.kernel.org
Cc: arnd@arndb.de, Vineet Gupta <Vineet.Gupta1@synopsys.com>,
	Rajeshwar Ranga <rajeshwar.ranga@gmail.com>
Subject: [PATCH v3 48/71] ARC: kprobes support
Date: Thu, 24 Jan 2013 16:20:33 +0530	[thread overview]
Message-ID: <1359024639-21915-20-git-send-email-vgupta@synopsys.com> (raw)
In-Reply-To: <1359024639-21915-1-git-send-email-vgupta@synopsys.com>

Origin port done by Rajeshwar Ranga

Signed-off-by: Vineet Gupta <vgupta@synopsys.com>
Cc: Rajeshwar Ranga <rajeshwar.ranga@gmail.com>
---
 arch/arc/Kconfig               |    2 +
 arch/arc/include/asm/kprobes.h |   62 +++++
 arch/arc/include/asm/ptrace.h  |    5 +
 arch/arc/kernel/Makefile       |    1 +
 arch/arc/kernel/disasm.c       |    5 +-
 arch/arc/kernel/kprobes.c      |  525 ++++++++++++++++++++++++++++++++++++++++
 arch/arc/kernel/traps.c        |   13 +
 7 files changed, 610 insertions(+), 3 deletions(-)
 create mode 100644 arch/arc/include/asm/kprobes.h
 create mode 100644 arch/arc/kernel/kprobes.c

diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig
index 84b23fa..cde8d3f 100644
--- a/arch/arc/Kconfig
+++ b/arch/arc/Kconfig
@@ -24,6 +24,8 @@ config ARC
 	select GENERIC_SMP_IDLE_THREAD
 	select HAVE_ARCH_TRACEHOOK
 	select HAVE_GENERIC_HARDIRQS
+	select HAVE_KPROBES
+	select HAVE_KRETPROBES
 	select HAVE_MEMBLOCK
 	select HAVE_MOD_ARCH_SPECIFIC if ARC_DW2_UNWIND
 	select HAVE_OPROFILE
diff --git a/arch/arc/include/asm/kprobes.h b/arch/arc/include/asm/kprobes.h
new file mode 100644
index 0000000..4d9c211
--- /dev/null
+++ b/arch/arc/include/asm/kprobes.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _ARC_KPROBES_H
+#define _ARC_KPROBES_H
+
+#ifdef CONFIG_KPROBES
+
+typedef u16 kprobe_opcode_t;
+
+#define UNIMP_S_INSTRUCTION 0x79e0
+#define TRAP_S_2_INSTRUCTION 0x785e
+
+#define MAX_INSN_SIZE   8
+#define MAX_STACK_SIZE  64
+
+struct arch_specific_insn {
+	int is_short;
+	kprobe_opcode_t *t1_addr, *t2_addr;
+	kprobe_opcode_t t1_opcode, t2_opcode;
+};
+
+#define flush_insn_slot(p)  do {  } while (0)
+
+#define kretprobe_blacklist_size    0
+
+struct kprobe;
+
+void arch_remove_kprobe(struct kprobe *p);
+
+int kprobe_exceptions_notify(struct notifier_block *self,
+			     unsigned long val, void *data);
+
+struct prev_kprobe {
+	struct kprobe *kp;
+	unsigned long status;
+};
+
+struct kprobe_ctlblk {
+	unsigned int kprobe_status;
+	struct pt_regs jprobe_saved_regs;
+	char jprobes_stack[MAX_STACK_SIZE];
+	struct prev_kprobe prev_kprobe;
+};
+
+int kprobe_fault_handler(struct pt_regs *regs, unsigned long cause);
+void kretprobe_trampoline(void);
+void trap_is_kprobe(unsigned long cause, unsigned long address,
+			   struct pt_regs *regs);
+#else
+static void trap_is_kprobe(unsigned long cause, unsigned long address,
+			   struct pt_regs *regs)
+{
+}
+#endif
+
+#endif
diff --git a/arch/arc/include/asm/ptrace.h b/arch/arc/include/asm/ptrace.h
index 8bf7ff4..713f145 100644
--- a/arch/arc/include/asm/ptrace.h
+++ b/arch/arc/include/asm/ptrace.h
@@ -146,6 +146,11 @@ struct user_regs_struct {
 	(struct pt_regs *)(pg_start + THREAD_SIZE - 4) - 1;	\
 })
 
+static inline long regs_return_value(struct pt_regs *regs)
+{
+	return regs->r0;
+}
+
 #endif /* !__ASSEMBLY__ */
 
 #define orig_r8_IS_SCALL		0x0001
diff --git a/arch/arc/kernel/Makefile b/arch/arc/kernel/Makefile
index 8906531..a64a604 100644
--- a/arch/arc/kernel/Makefile
+++ b/arch/arc/kernel/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_OF)			+= devtree.o
 obj-$(CONFIG_MODULES)			+= arcksyms.o module.o
 obj-$(CONFIG_SMP) 			+= smp.o
 obj-$(CONFIG_ARC_DW2_UNWIND)		+= unwind.o
+obj-$(CONFIG_KPROBES)      		+= kprobes.o
 
 obj-$(CONFIG_ARC_FPU_SAVE_RESTORE)	+= fpu.o
 CFLAGS_fpu.o   += -mdpfp
diff --git a/arch/arc/kernel/disasm.c b/arch/arc/kernel/disasm.c
index 254d11a..51bad8f 100644
--- a/arch/arc/kernel/disasm.c
+++ b/arch/arc/kernel/disasm.c
@@ -497,9 +497,8 @@ void __kprobes set_reg(int reg, long val, struct pt_regs *regs,
  * @pc +2/4/6 (ARCompact ISA allows free intermixing of 16/32 bit insns).
  *
  * If @pc is a branch
- * 	-@tgt_if_br is set to branch target.
- * 	-If branch has delay slot, @next_pc updated with actual next PC.
- *
+ *	-@tgt_if_br is set to branch target.
+ *	-If branch has delay slot, @next_pc updated with actual next PC.
  */
 int __kprobes disasm_next_pc(unsigned long pc, struct pt_regs *regs,
 			     struct callee_regs *cregs,
diff --git a/arch/arc/kernel/kprobes.c b/arch/arc/kernel/kprobes.c
new file mode 100644
index 0000000..47e42f2
--- /dev/null
+++ b/arch/arc/kernel/kprobes.c
@@ -0,0 +1,525 @@
+/*
+ * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/types.h>
+#include <linux/kprobes.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kprobes.h>
+#include <linux/kdebug.h>
+#include <linux/sched.h>
+#include <linux/uaccess.h>
+#include <asm/cacheflush.h>
+#include <asm/current.h>
+#include <asm/disasm.h>
+
+#define MIN_STACK_SIZE(addr)	min((unsigned long)MAX_STACK_SIZE, \
+		(unsigned long)current_thread_info() + THREAD_SIZE - (addr))
+
+DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL;
+DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
+
+int __kprobes arch_prepare_kprobe(struct kprobe *p)
+{
+	/* Attempt to probe at unaligned address */
+	if ((unsigned long)p->addr & 0x01)
+		return -EINVAL;
+
+	/* Address should not be in exception handling code */
+
+	p->ainsn.is_short = is_short_instr((unsigned long)p->addr);
+	p->opcode = *p->addr;
+
+	return 0;
+}
+
+void __kprobes arch_arm_kprobe(struct kprobe *p)
+{
+	*p->addr = UNIMP_S_INSTRUCTION;
+
+	flush_icache_range((unsigned long)p->addr,
+			   (unsigned long)p->addr + sizeof(kprobe_opcode_t));
+}
+
+void __kprobes arch_disarm_kprobe(struct kprobe *p)
+{
+	*p->addr = p->opcode;
+
+	flush_icache_range((unsigned long)p->addr,
+			   (unsigned long)p->addr + sizeof(kprobe_opcode_t));
+}
+
+void __kprobes arch_remove_kprobe(struct kprobe *p)
+{
+	arch_disarm_kprobe(p);
+
+	/* Can we remove the kprobe in the middle of kprobe handling? */
+	if (p->ainsn.t1_addr) {
+		*(p->ainsn.t1_addr) = p->ainsn.t1_opcode;
+
+		flush_icache_range((unsigned long)p->ainsn.t1_addr,
+				   (unsigned long)p->ainsn.t1_addr +
+				   sizeof(kprobe_opcode_t));
+
+		p->ainsn.t1_addr = NULL;
+	}
+
+	if (p->ainsn.t2_addr) {
+		*(p->ainsn.t2_addr) = p->ainsn.t2_opcode;
+
+		flush_icache_range((unsigned long)p->ainsn.t2_addr,
+				   (unsigned long)p->ainsn.t2_addr +
+				   sizeof(kprobe_opcode_t));
+
+		p->ainsn.t2_addr = NULL;
+	}
+}
+
+static void __kprobes save_previous_kprobe(struct kprobe_ctlblk *kcb)
+{
+	kcb->prev_kprobe.kp = kprobe_running();
+	kcb->prev_kprobe.status = kcb->kprobe_status;
+}
+
+static void __kprobes restore_previous_kprobe(struct kprobe_ctlblk *kcb)
+{
+	__get_cpu_var(current_kprobe) = kcb->prev_kprobe.kp;
+	kcb->kprobe_status = kcb->prev_kprobe.status;
+}
+
+static inline void __kprobes set_current_kprobe(struct kprobe *p)
+{
+	__get_cpu_var(current_kprobe) = p;
+}
+
+static void __kprobes resume_execution(struct kprobe *p, unsigned long addr,
+				       struct pt_regs *regs)
+{
+	/* Remove the trap instructions inserted for single step and
+	 * restore the original instructions
+	 */
+	if (p->ainsn.t1_addr) {
+		*(p->ainsn.t1_addr) = p->ainsn.t1_opcode;
+
+		flush_icache_range((unsigned long)p->ainsn.t1_addr,
+				   (unsigned long)p->ainsn.t1_addr +
+				   sizeof(kprobe_opcode_t));
+
+		p->ainsn.t1_addr = NULL;
+	}
+
+	if (p->ainsn.t2_addr) {
+		*(p->ainsn.t2_addr) = p->ainsn.t2_opcode;
+
+		flush_icache_range((unsigned long)p->ainsn.t2_addr,
+				   (unsigned long)p->ainsn.t2_addr +
+				   sizeof(kprobe_opcode_t));
+
+		p->ainsn.t2_addr = NULL;
+	}
+
+	return;
+}
+
+static void __kprobes setup_singlestep(struct kprobe *p, struct pt_regs *regs)
+{
+	unsigned long next_pc;
+	unsigned long tgt_if_br = 0;
+	int is_branch;
+	unsigned long bta;
+
+	/* Copy the opcode back to the kprobe location and execute the
+	 * instruction. Because of this we will not be able to get into the
+	 * same kprobe until this kprobe is done
+	 */
+	*(p->addr) = p->opcode;
+
+	flush_icache_range((unsigned long)p->addr,
+			   (unsigned long)p->addr + sizeof(kprobe_opcode_t));
+
+	/* Now we insert the trap at the next location after this instruction to
+	 * single step. If it is a branch we insert the trap at possible branch
+	 * targets
+	 */
+
+	bta = regs->bta;
+
+	if (regs->status32 & 0x40) {
+		/* We are in a delay slot with the branch taken */
+
+		next_pc = bta & ~0x01;
+
+		if (!p->ainsn.is_short) {
+			if (bta & 0x01)
+				regs->blink += 2;
+			else {
+				/* Branch not taken */
+				next_pc += 2;
+
+				/* next pc is taken from bta after executing the
+				 * delay slot instruction
+				 */
+				regs->bta += 2;
+			}
+		}
+
+		is_branch = 0;
+	} else
+		is_branch =
+		    disasm_next_pc((unsigned long)p->addr, regs,
+			(struct callee_regs *) current->thread.callee_reg,
+			&next_pc, &tgt_if_br);
+
+	p->ainsn.t1_addr = (kprobe_opcode_t *) next_pc;
+	p->ainsn.t1_opcode = *(p->ainsn.t1_addr);
+	*(p->ainsn.t1_addr) = TRAP_S_2_INSTRUCTION;
+
+	flush_icache_range((unsigned long)p->ainsn.t1_addr,
+			   (unsigned long)p->ainsn.t1_addr +
+			   sizeof(kprobe_opcode_t));
+
+	if (is_branch) {
+		p->ainsn.t2_addr = (kprobe_opcode_t *) tgt_if_br;
+		p->ainsn.t2_opcode = *(p->ainsn.t2_addr);
+		*(p->ainsn.t2_addr) = TRAP_S_2_INSTRUCTION;
+
+		flush_icache_range((unsigned long)p->ainsn.t2_addr,
+				   (unsigned long)p->ainsn.t2_addr +
+				   sizeof(kprobe_opcode_t));
+	}
+}
+
+int __kprobes arc_kprobe_handler(unsigned long addr, struct pt_regs *regs)
+{
+	struct kprobe *p;
+	struct kprobe_ctlblk *kcb;
+
+	preempt_disable();
+
+	kcb = get_kprobe_ctlblk();
+	p = get_kprobe((unsigned long *)addr);
+
+	if (p) {
+		/*
+		 * We have reentered the kprobe_handler, since another kprobe
+		 * was hit while within the handler, we save the original
+		 * kprobes and single step on the instruction of the new probe
+		 * without calling any user handlers to avoid recursive
+		 * kprobes.
+		 */
+		if (kprobe_running()) {
+			save_previous_kprobe(kcb);
+			set_current_kprobe(p);
+			kprobes_inc_nmissed_count(p);
+			setup_singlestep(p, regs);
+			kcb->kprobe_status = KPROBE_REENTER;
+			return 1;
+		}
+
+		set_current_kprobe(p);
+		kcb->kprobe_status = KPROBE_HIT_ACTIVE;
+
+		/* If we have no pre-handler or it returned 0, we continue with
+		 * normal processing. If we have a pre-handler and it returned
+		 * non-zero - which is expected from setjmp_pre_handler for
+		 * jprobe, we return without single stepping and leave that to
+		 * the break-handler which is invoked by a kprobe from
+		 * jprobe_return
+		 */
+		if (!p->pre_handler || !p->pre_handler(p, regs)) {
+			setup_singlestep(p, regs);
+			kcb->kprobe_status = KPROBE_HIT_SS;
+		}
+
+		return 1;
+	} else if (kprobe_running()) {
+		p = __get_cpu_var(current_kprobe);
+		if (p->break_handler && p->break_handler(p, regs)) {
+			setup_singlestep(p, regs);
+			kcb->kprobe_status = KPROBE_HIT_SS;
+			return 1;
+		}
+	}
+
+	/* no_kprobe: */
+	preempt_enable_no_resched();
+	return 0;
+}
+
+static int __kprobes arc_post_kprobe_handler(unsigned long addr,
+					 struct pt_regs *regs)
+{
+	struct kprobe *cur = kprobe_running();
+	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+
+	if (!cur)
+		return 0;
+
+	resume_execution(cur, addr, regs);
+
+	/* Rearm the kprobe */
+	arch_arm_kprobe(cur);
+
+	/*
+	 * When we return from trap instruction we go to the next instruction
+	 * We restored the actual instruction in resume_exectuiont and we to
+	 * return to the same address and execute it
+	 */
+	regs->ret = addr;
+
+	if ((kcb->kprobe_status != KPROBE_REENTER) && cur->post_handler) {
+		kcb->kprobe_status = KPROBE_HIT_SSDONE;
+		cur->post_handler(cur, regs, 0);
+	}
+
+	if (kcb->kprobe_status == KPROBE_REENTER) {
+		restore_previous_kprobe(kcb);
+		goto out;
+	}
+
+	reset_current_kprobe();
+
+out:
+	preempt_enable_no_resched();
+	return 1;
+}
+
+/*
+ * Fault can be for the instruction being single stepped or for the
+ * pre/post handlers in the module.
+ * This is applicable for applications like user probes, where we have the
+ * probe in user space and the handlers in the kernel
+ */
+
+int __kprobes kprobe_fault_handler(struct pt_regs *regs, unsigned long trapnr)
+{
+	struct kprobe *cur = kprobe_running();
+	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+
+	switch (kcb->kprobe_status) {
+	case KPROBE_HIT_SS:
+	case KPROBE_REENTER:
+		/*
+		 * We are here because the instruction being single stepped
+		 * caused the fault. We reset the current kprobe and allow the
+		 * exception handler as if it is regular exception. In our
+		 * case it doesn't matter because the system will be halted
+		 */
+		resume_execution(cur, (unsigned long)cur->addr, regs);
+
+		if (kcb->kprobe_status == KPROBE_REENTER)
+			restore_previous_kprobe(kcb);
+		else
+			reset_current_kprobe();
+
+		preempt_enable_no_resched();
+		break;
+
+	case KPROBE_HIT_ACTIVE:
+	case KPROBE_HIT_SSDONE:
+		/*
+		 * We are here because the instructions in the pre/post handler
+		 * caused the fault.
+		 */
+
+		/* We increment the nmissed count for accounting,
+		 * we can also use npre/npostfault count for accouting
+		 * these specific fault cases.
+		 */
+		kprobes_inc_nmissed_count(cur);
+
+		/*
+		 * We come here because instructions in the pre/post
+		 * handler caused the page_fault, this could happen
+		 * if handler tries to access user space by
+		 * copy_from_user(), get_user() etc. Let the
+		 * user-specified handler try to fix it first.
+		 */
+		if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr))
+			return 1;
+
+		/*
+		 * In case the user-specified fault handler returned zero,
+		 * try to fix up.
+		 */
+		if (fixup_exception(regs))
+			return 1;
+
+		/*
+		 * fixup_exception() could not handle it,
+		 * Let do_page_fault() fix it.
+		 */
+		break;
+
+	default:
+		break;
+	}
+	return 0;
+}
+
+int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
+				       unsigned long val, void *data)
+{
+	struct die_args *args = data;
+	unsigned long addr = args->err;
+	int ret = NOTIFY_DONE;
+
+	switch (val) {
+	case DIE_IERR:
+		if (arc_kprobe_handler(addr, args->regs))
+			return NOTIFY_STOP;
+		break;
+
+	case DIE_TRAP:
+		if (arc_post_kprobe_handler(addr, args->regs))
+			return NOTIFY_STOP;
+		break;
+
+	default:
+		break;
+	}
+
+	return ret;
+}
+
+int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
+{
+	struct jprobe *jp = container_of(p, struct jprobe, kp);
+	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+	unsigned long sp_addr = regs->sp;
+
+	kcb->jprobe_saved_regs = *regs;
+	memcpy(kcb->jprobes_stack, (void *)sp_addr, MIN_STACK_SIZE(sp_addr));
+	regs->ret = (unsigned long)(jp->entry);
+
+	return 1;
+}
+
+void __kprobes jprobe_return(void)
+{
+	__asm__ __volatile__("unimp_s");
+	return;
+}
+
+int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
+{
+	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+	unsigned long sp_addr;
+
+	*regs = kcb->jprobe_saved_regs;
+	sp_addr = regs->sp;
+	memcpy((void *)sp_addr, kcb->jprobes_stack, MIN_STACK_SIZE(sp_addr));
+	preempt_enable_no_resched();
+
+	return 1;
+}
+
+static void __used kretprobe_trampoline_holder(void)
+{
+	__asm__ __volatile__(".global kretprobe_trampoline\n"
+			     "kretprobe_trampoline:\n" "nop\n");
+}
+
+void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
+				      struct pt_regs *regs)
+{
+
+	ri->ret_addr = (kprobe_opcode_t *) regs->blink;
+
+	/* Replace the return addr with trampoline addr */
+	regs->blink = (unsigned long)&kretprobe_trampoline;
+}
+
+static int __kprobes trampoline_probe_handler(struct kprobe *p,
+					      struct pt_regs *regs)
+{
+	struct kretprobe_instance *ri = NULL;
+	struct hlist_head *head, empty_rp;
+	struct hlist_node *node, *tmp;
+	unsigned long flags, orig_ret_address = 0;
+	unsigned long trampoline_address = (unsigned long)&kretprobe_trampoline;
+
+	INIT_HLIST_HEAD(&empty_rp);
+	kretprobe_hash_lock(current, &head, &flags);
+
+	/*
+	 * It is possible to have multiple instances associated with a given
+	 * task either because an multiple functions in the call path
+	 * have a return probe installed on them, and/or more than one return
+	 * return probe was registered for a target function.
+	 *
+	 * We can handle this because:
+	 *     - instances are always inserted at the head of the list
+	 *     - when multiple return probes are registered for the same
+	 *       function, the first instance's ret_addr will point to the
+	 *       real return address, and all the rest will point to
+	 *       kretprobe_trampoline
+	 */
+	hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {
+		if (ri->task != current)
+			/* another task is sharing our hash bucket */
+			continue;
+
+		if (ri->rp && ri->rp->handler)
+			ri->rp->handler(ri, regs);
+
+		orig_ret_address = (unsigned long)ri->ret_addr;
+		recycle_rp_inst(ri, &empty_rp);
+
+		if (orig_ret_address != trampoline_address) {
+			/*
+			 * This is the real return address. Any other
+			 * instances associated with this task are for
+			 * other calls deeper on the call stack
+			 */
+			break;
+		}
+	}
+
+	kretprobe_assert(ri, orig_ret_address, trampoline_address);
+	regs->ret = orig_ret_address;
+
+	reset_current_kprobe();
+	kretprobe_hash_unlock(current, &flags);
+	preempt_enable_no_resched();
+
+	hlist_for_each_entry_safe(ri, node, tmp, &empty_rp, hlist) {
+		hlist_del(&ri->hlist);
+		kfree(ri);
+	}
+
+	/* By returning a non zero value, we are telling the kprobe handler
+	 * that we don't want the post_handler to run
+	 */
+	return 1;
+}
+
+static struct kprobe trampoline_p = {
+	.addr = (kprobe_opcode_t *) &kretprobe_trampoline,
+	.pre_handler = trampoline_probe_handler
+};
+
+int __init arch_init_kprobes(void)
+{
+	/* Registering the trampoline code for the kret probe */
+	return register_kprobe(&trampoline_p);
+}
+
+int __kprobes arch_trampoline_kprobe(struct kprobe *p)
+{
+	if (p->addr == (kprobe_opcode_t *) &kretprobe_trampoline)
+		return 1;
+
+	return 0;
+}
+
+void trap_is_kprobe(unsigned long cause, unsigned long address,
+		    struct pt_regs *regs)
+{
+	notify_die(DIE_TRAP, "kprobe_trap", regs, address, cause, SIGTRAP);
+}
diff --git a/arch/arc/kernel/traps.c b/arch/arc/kernel/traps.c
index fd2457c..c6396b4 100644
--- a/arch/arc/kernel/traps.c
+++ b/arch/arc/kernel/traps.c
@@ -15,6 +15,7 @@
 #include <linux/uaccess.h>
 #include <asm/ptrace.h>
 #include <asm/setup.h>
+#include <asm/kprobes.h>
 
 void __init trap_init(void)
 {
@@ -90,6 +91,7 @@ void do_machine_check_fault(unsigned long cause, unsigned long address,
 	die("Machine Check Exception", regs, address, cause);
 }
 
+
 /*
  * Entry point for traps induced by ARCompact TRAP_S <n> insn
  * This is same family as TRAP0/SWI insn (use the same vector).
@@ -109,6 +111,10 @@ void do_non_swi_trap(unsigned long cause, unsigned long address,
 		trap_is_brkpt(cause, address, regs);
 		break;
 
+	case 2:
+		trap_is_kprobe(param, address, regs);
+		break;
+
 	default:
 		break;
 	}
@@ -116,10 +122,17 @@ void do_non_swi_trap(unsigned long cause, unsigned long address,
 
 /*
  * Entry point for Instruction Error Exception
+ *  -For a corner case, ARC kprobes implementation resorts to using
+ *   this exception, hence the check
  */
 void do_insterror_or_kprobe(unsigned long cause,
 				       unsigned long address,
 				       struct pt_regs *regs)
 {
+	/* Check if this exception is caused by kprobes */
+	if (notify_die(DIE_IERR, "kprobe_ierr", regs, address,
+		       cause, SIGILL) == NOTIFY_STOP)
+		return;
+
 	insterror_is_error(cause, address, regs);
 }
-- 
1.7.4.1

  parent reply	other threads:[~2013-01-24 10:50 UTC|newest]

Thread overview: 75+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-01-24 10:50 [PATCH v3 00/71] Synopsys ARC Linux kernel Port (Part #1) Vineet Gupta
2013-01-24 10:50 ` [PATCH v3 01/71] ARC: Generic Headers Vineet Gupta
2013-01-24 10:50 ` [PATCH v3 02/71] ARC: Build system: Makefiles, Kconfig, Linker script Vineet Gupta
2013-01-28  6:29   ` Vineet Gupta
2013-01-28 18:44     ` Sam Ravnborg
2013-01-29 13:45       ` Vineet Gupta
2013-01-29 17:52         ` Sam Ravnborg
2013-02-11 11:29   ` James Hogan
2013-02-11 11:44     ` Vineet Gupta
2013-01-24 10:50 ` [PATCH v3 06/71] ARC: uaccess friends Vineet Gupta
2013-01-24 10:50   ` Vineet Gupta
2013-01-24 10:50 ` [PATCH v3 11/71] ARC: Fundamental ARCH data-types/defines Vineet Gupta
2013-01-24 10:50 ` [PATCH v3 17/71] ARC: Syscall support (no-legacy-syscall ABI) Vineet Gupta
2013-01-24 10:50 ` [PATCH v3 18/71] ARC: Process-creation/scheduling/idle-loop Vineet Gupta
2013-01-24 10:50 ` [PATCH v3 19/71] ARC: Timers/counters/delay management Vineet Gupta
2013-01-24 10:50   ` Vineet Gupta
2013-01-24 10:50 ` [PATCH v3 20/71] ARC: Signal handling Vineet Gupta
2013-01-24 10:50   ` Vineet Gupta
2013-02-11  7:26   ` pt_regs leak into userspace (was Re: [PATCH v3 20/71] ARC: Signal handling) Vineet Gupta
2013-02-11  9:36     ` Jonas Bonn
2013-02-11 10:13       ` Vineet Gupta
2013-02-11 10:28         ` James Hogan
2013-02-11 10:53           ` Jonas Bonn
2013-02-11 10:57             ` James Hogan
2013-02-11 11:01             ` James Hogan
2013-02-11 11:22             ` Vineet Gupta
2013-02-11 12:12               ` Jonas Bonn
2013-02-11 12:37                 ` Vineet Gupta
2013-02-11 13:02                   ` Jonas Bonn
2013-02-11 13:08                     ` Vineet Gupta
2013-02-11 10:30         ` Jonas Bonn
2013-02-11 10:30           ` Jonas Bonn
2013-02-11 14:07           ` Al Viro
2013-02-15  7:23             ` Jonas Bonn
2013-02-15  7:35               ` Vineet Gupta
2013-01-24 10:50 ` [PATCH v3 21/71] ARC: [Review] Preparing to fix incorrect syscall restarts due to signals Vineet Gupta
2013-01-24 10:50   ` Vineet Gupta
2013-01-24 10:50 ` [PATCH v3 22/71] ARC: [Review] Prevent incorrect syscall restarts Vineet Gupta
2013-01-28  7:42   ` Vineet Gupta
2013-01-24 10:50 ` [PATCH v3 23/71] ARC: Cache Flush Management Vineet Gupta
2013-01-24 10:50   ` Vineet Gupta
2013-01-24 10:50 ` [PATCH v3 29/71] ARC: I/O and DMA Mappings Vineet Gupta
2013-01-24 10:50 ` [PATCH v3 30/71] ARC: Boot #1: low-level, setup_arch(), /proc/cpuinfo, mem init Vineet Gupta
     [not found] ` <1359024639-21915-1-git-send-email-vgupta-HKixBCOQz3hWk0Htik3J/w@public.gmane.org>
2013-01-24 10:50   ` [PATCH v3 32/71] ARC: [DeviceTree] Basic support Vineet Gupta
2013-01-24 10:50     ` Vineet Gupta
2013-01-28  7:40     ` Vineet Gupta
2013-01-28 10:21     ` James Hogan
2013-01-29  9:53       ` Vineet Gupta
2013-01-29  9:53         ` Vineet Gupta
2013-01-29 10:06         ` James Hogan
     [not found]     ` <1359024639-21915-15-git-send-email-vgupta-HKixBCOQz3hWk0Htik3J/w@public.gmane.org>
2013-01-29 13:25       ` Rob Herring
2013-01-29 13:25         ` Rob Herring
     [not found]         ` <5107CDD3.3050502-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2013-01-29 13:39           ` Vineet Gupta
2013-01-29 13:39             ` Vineet Gupta
2013-01-29 13:55         ` [PATCH v4 " Vineet Gupta
2013-01-30 11:08           ` James Hogan
2013-01-30 11:56             ` Vineet Gupta
2013-01-24 10:50 ` [PATCH v3 33/71] ARC: [DeviceTree] Convert some Kconfig items to runtime values Vineet Gupta
2013-01-24 10:50   ` Vineet Gupta
2013-01-24 10:50 ` [PATCH v3 34/71] ARC: [plat-arcfpga]: Enabling DeviceTree for Angel4 board Vineet Gupta
2013-01-24 10:50   ` Vineet Gupta
2013-01-24 10:50 ` [PATCH v3 42/71] ARC: Module support Vineet Gupta
2013-01-24 10:50 ` [PATCH v3 44/71] ARC: SMP support Vineet Gupta
2013-01-24 10:50 ` Vineet Gupta [this message]
2013-01-24 10:50   ` [PATCH v3 48/71] ARC: kprobes support Vineet Gupta
2013-01-24 10:50 ` [PATCH v3 57/71] ARC: Hostlink Pseudo-Driver for Metaware Debugger Vineet Gupta
2013-01-24 10:50 ` [PATCH v3 58/71] ARC: UAPI Disintegrate arch/arc/include/asm Vineet Gupta
2013-01-24 10:50   ` Vineet Gupta
2013-01-28  7:36   ` Vineet Gupta
2013-01-24 10:50 ` [PATCH v3 59/71] ARC: Add support for ioremap_prot API Vineet Gupta
2013-01-24 10:50 ` [PATCH v3 62/71] ARC: [Review] Multi-platform image #2: Board callback Infrastructure Vineet Gupta
2013-01-24 10:50   ` Vineet Gupta
2013-01-24 10:50 ` [PATCH v3 69/71] ARC: [plat-arcfpga] defconfig for fully loaded ARC Linux Vineet Gupta
2013-01-24 10:50 ` [PATCH v3 70/71] ARC: Provide a default serial.h for uart drivers needing BASE_BAUD Vineet Gupta
2013-01-24 11:01 ` [PATCH v3 45/71] ARC: DWARF2 .debug_frame based stack unwinder Vineet Gupta

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1359024639-21915-20-git-send-email-vgupta@synopsys.com \
    --to=vineet.gupta1@synopsys.com \
    --cc=arnd@arndb.de \
    --cc=linux-arch@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=rajeshwar.ranga@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).