public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [patch 0/3] Kprobes Ia64 more fixes....
@ 2005-06-06 17:36 Anil S Keshavamurthy
  2005-06-06 17:36 ` [patch 1/3] Kprobes IA64 arch prepare kprobes cleanup Anil S Keshavamurthy
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Anil S Keshavamurthy @ 2005-06-06 17:36 UTC (permalink / raw)
  To: akpm
  Cc: linux-kernel, linux-ia64, systemtap, rusty.lynch, davidm,
	alen.brunelle, anil.s.keshavamurthy

Hi All,
	Based on the feedback obtained from the community, I have
have address the below issues in the Kprobes.

1) When patching the original instruction with the break instruction,
we need to preserve the original qualifying predicate for all instruction
except for some special instruction like
(qp) cmp.crel.ctype p1,p2=r1,r2
where ctype == unc, which always needs to be emulated irrespective of
original qp.

2) Fail register_kprobes() for unsupported instruction. Currently
Kprobes of some speculation chk instruction and mov r1=ip 
kind of instructions are not supported. Hence when user
tries to register kprobes on these instruction, fail register_kprobe()
instead of handling badly.

Comments welcome.

Thanks,
Anil Keshavamurthy
--


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [patch 1/3] Kprobes IA64 arch prepare kprobes cleanup
  2005-06-06 17:36 [patch 0/3] Kprobes Ia64 more fixes Anil S Keshavamurthy
@ 2005-06-06 17:36 ` Anil S Keshavamurthy
  2005-06-06 17:36 ` [patch 2/3] Kprobes IA64 cmp ctype unc support Anil S Keshavamurthy
  2005-06-06 17:36 ` [patch 3/3] Kprobes IA64 safe register kprobe Anil S Keshavamurthy
  2 siblings, 0 replies; 4+ messages in thread
From: Anil S Keshavamurthy @ 2005-06-06 17:36 UTC (permalink / raw)
  To: akpm
  Cc: linux-kernel, linux-ia64, systemtap, rusty.lynch, davidm,
	alen.brunelle, anil.s.keshavamurthy

[-- Attachment #1: kprobes-ia64-arch-prepare-cleanup.patch --]
[-- Type: text/plain, Size: 7875 bytes --]

arch_prepare_kprobes() was doing lots of functionality
in just one single function. This patch
attempts to clean up arch_prepare_kprobes() by moving
specific sub task to the following (new)functions
1)valid_kprobe_addr() -->> validate the given kprobe address
2)get_kprobe_inst(slot..)->> Retrives the instruction for a given slot from the bundle 
3)prepare_break_inst() -->> Prepares break instruction within the bundle
	3a)update_kprobe_inst_flag()-->>Updates the internal flags, required
			for proper emulation of the instruction at later
			point in time.

Signed-off-by: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>

===================================================================
 arch/ia64/kernel/kprobes.c |  191 ++++++++++++++++++++++++++++-----------------
 1 files changed, 121 insertions(+), 70 deletions(-)

Index: linux-2.6.12-rc5/arch/ia64/kernel/kprobes.c
===================================================================
--- linux-2.6.12-rc5.orig/arch/ia64/kernel/kprobes.c
+++ linux-2.6.12-rc5/arch/ia64/kernel/kprobes.c
@@ -98,90 +98,141 @@ static inline void set_current_kprobe(st
 	current_kprobe = p;
 }
 
-int arch_prepare_kprobe(struct kprobe *p)
+/*
+ * In this function we check to see if the instruction
+ * is IP relative instruction and update the kprobe
+ * inst flag accordingly
+ */
+static void update_kprobe_inst_flag(uint template, uint  slot, uint major_opcode,
+	unsigned long kprobe_inst, struct kprobe *p)
 {
-	unsigned long addr = (unsigned long) p->addr;
-	unsigned long *bundle_addr = (unsigned long *)(addr & ~0xFULL);
-	unsigned long slot = addr & 0xf;
-	unsigned long template;
- 	unsigned long major_opcode = 0;
- 	unsigned long lx_type_inst = 0;
- 	unsigned long kprobe_inst = 0;
-	bundle_t *bundle = &p->ainsn.insn.bundle;
-
-	memcpy(&p->opcode.bundle, bundle_addr, sizeof(bundle_t));
-	memcpy(&p->ainsn.insn.bundle, bundle_addr, sizeof(bundle_t));
-
 	p->ainsn.inst_flag = 0;
 	p->ainsn.target_br_reg = 0;
 
- 	template = bundle->quad0.template;
+	if (bundle_encoding[template][slot] == B) {
+		switch (major_opcode) {
+		  case INDIRECT_CALL_OPCODE:
+	 		p->ainsn.inst_flag |= INST_FLAG_FIX_BRANCH_REG;
+ 			p->ainsn.target_br_reg = ((kprobe_inst >> 6) & 0x7);
+ 			break;
+		  case IP_RELATIVE_PREDICT_OPCODE:
+		  case IP_RELATIVE_BRANCH_OPCODE:
+			p->ainsn.inst_flag |= INST_FLAG_FIX_RELATIVE_IP_ADDR;
+ 			break;
+		  case IP_RELATIVE_CALL_OPCODE:
+ 			p->ainsn.inst_flag |= INST_FLAG_FIX_RELATIVE_IP_ADDR;
+ 			p->ainsn.inst_flag |= INST_FLAG_FIX_BRANCH_REG;
+ 			p->ainsn.target_br_reg = ((kprobe_inst >> 6) & 0x7);
+ 			break;
+		}
+ 	} else if (bundle_encoding[template][slot] == X) {
+		switch (major_opcode) {
+		  case LONG_CALL_OPCODE:
+			p->ainsn.inst_flag |= INST_FLAG_FIX_BRANCH_REG;
+			p->ainsn.target_br_reg = ((kprobe_inst >> 6) & 0x7);
+		  break;
+		}
+	}
+	return;
+}
 
-	if (((bundle_encoding[template][1] == L) && slot > 1) || (slot > 2)) {
-		printk(KERN_WARNING "Attempting to insert unaligned kprobe at 0x%lx\n",
-				addr);
-		return -EINVAL;
+/* 
+ * In this function we override the bundle with
+ * the break instruction at the given slot.
+ */
+static void prepare_break_inst(uint template, uint  slot, uint major_opcode,
+	unsigned long kprobe_inst, struct kprobe *p)
+{
+	unsigned long break_inst = BREAK_INST;
+	bundle_t *bundle = &p->ainsn.insn.bundle;
+
+	/*
+	 * Copy the original kprobe_inst qualifying predicate(qp)
+	 * to the break instruction
+	 */
+	break_inst |= (0x3f & kprobe_inst);
+
+	switch (slot) {
+	  case 0:
+		bundle->quad0.slot0 = break_inst;
+		break;
+	  case 1:
+		bundle->quad0.slot1_p0 = break_inst;
+		bundle->quad1.slot1_p1 = break_inst >> (64-46);
+		break;
+	  case 2:
+		bundle->quad1.slot2 = break_inst;
+		break;
 	}
 
- 	if (slot == 1 && bundle_encoding[template][1] == L) {
- 		lx_type_inst = 1;
-  		slot = 2;
- 	}
+	/* 
+	 * Update the instruction flag, so that we can
+	 * emulate the instruction properly after we 
+	 * single step on original instruction
+	 */
+	update_kprobe_inst_flag(template, slot, major_opcode, kprobe_inst, p);
+}
+
+static inline void get_kprobe_inst(bundle_t *bundle, uint slot,
+	       	unsigned long *kprobe_inst, uint *major_opcode)
+{
+	unsigned long kprobe_inst_p0, kprobe_inst_p1;
+	unsigned int template;
+
+	template = bundle->quad0.template;
 
 	switch (slot) {
-	case 0:
- 		major_opcode = (bundle->quad0.slot0 >> SLOT0_OPCODE_SHIFT);
- 		kprobe_inst = bundle->quad0.slot0;
-		bundle->quad0.slot0 = BREAK_INST | (0x3f & kprobe_inst);
+	  case 0:
+ 		*major_opcode = (bundle->quad0.slot0 >> SLOT0_OPCODE_SHIFT);
+ 		*kprobe_inst = bundle->quad0.slot0;
 		break;
-	case 1:
- 		major_opcode = (bundle->quad1.slot1_p1 >> SLOT1_p1_OPCODE_SHIFT);
- 		kprobe_inst = (bundle->quad0.slot1_p0 |
- 				(bundle->quad1.slot1_p1 << (64-46)));
-		bundle->quad0.slot1_p0 = BREAK_INST | (0x3f & kprobe_inst);
-		bundle->quad1.slot1_p1 = (BREAK_INST >> (64-46));
+	  case 1:
+ 		*major_opcode = (bundle->quad1.slot1_p1 >> SLOT1_p1_OPCODE_SHIFT);
+  		kprobe_inst_p0 = bundle->quad0.slot1_p0;
+  		kprobe_inst_p1 = bundle->quad1.slot1_p1;
+  		*kprobe_inst = kprobe_inst_p0 | (kprobe_inst_p1 << (64-46));
 		break;
-	case 2:
- 		major_opcode = (bundle->quad1.slot2 >> SLOT2_OPCODE_SHIFT);
- 		kprobe_inst = bundle->quad1.slot2;
-		bundle->quad1.slot2 = BREAK_INST | (0x3f & kprobe_inst);
+	  case 2:
+ 		*major_opcode = (bundle->quad1.slot2 >> SLOT2_OPCODE_SHIFT);
+ 		*kprobe_inst = bundle->quad1.slot2;
 		break;
 	}
+}
 
- 	/*
- 	 * Look for IP relative Branches, IP relative call or
- 	 * IP relative predicate instructions
- 	 */
- 	if (bundle_encoding[template][slot] == B) {
- 		switch (major_opcode) {
- 			case INDIRECT_CALL_OPCODE:
- 				p->ainsn.inst_flag |= INST_FLAG_FIX_BRANCH_REG;
- 				p->ainsn.target_br_reg = ((kprobe_inst >> 6) & 0x7);
- 				break;
- 			case IP_RELATIVE_PREDICT_OPCODE:
- 			case IP_RELATIVE_BRANCH_OPCODE:
- 				p->ainsn.inst_flag |= INST_FLAG_FIX_RELATIVE_IP_ADDR;
- 				break;
- 			case IP_RELATIVE_CALL_OPCODE:
- 				p->ainsn.inst_flag |= INST_FLAG_FIX_RELATIVE_IP_ADDR;
- 				p->ainsn.inst_flag |= INST_FLAG_FIX_BRANCH_REG;
- 				p->ainsn.target_br_reg = ((kprobe_inst >> 6) & 0x7);
- 				break;
- 			default:
- 				/* Do nothing */
- 				break;
- 		}
- 	} else if (lx_type_inst) {
- 		switch (major_opcode) {
- 			case LONG_CALL_OPCODE:
- 				p->ainsn.inst_flag |= INST_FLAG_FIX_BRANCH_REG;
- 				p->ainsn.target_br_reg = ((kprobe_inst >> 6) & 0x7);
-				break;
- 			default:
- 				/* Do nothing */
- 				break;
- 		}
+static int valid_kprobe_addr(int template, int slot, unsigned long addr)
+{
+	if ((slot > 2) || ((bundle_encoding[template][1] == L) && slot > 1)) {
+		printk(KERN_WARNING "Attempting to insert unaligned kprobe at 0x%lx\n",
+				addr);
+		return -EINVAL;
 	}
+	return 0;
+}
+
+int arch_prepare_kprobe(struct kprobe *p)
+{
+	unsigned long addr = (unsigned long) p->addr;
+	unsigned long *kprobe_addr = (unsigned long *)(addr & ~0xFULL);
+	unsigned long kprobe_inst=0;
+	unsigned int slot = addr & 0xf, template, major_opcode = 0;
+	bundle_t *bundle = &p->ainsn.insn.bundle;
+
+	memcpy(&p->opcode.bundle, kprobe_addr, sizeof(bundle_t));
+	memcpy(&p->ainsn.insn.bundle, kprobe_addr, sizeof(bundle_t));
+
+ 	template = bundle->quad0.template;
+
+	if(valid_kprobe_addr(template, slot, addr))
+		return -EINVAL;
+
+	/* Move to slot 2, if bundle is MLX type and kprobe slot is 1 */
+ 	if (slot == 1 && bundle_encoding[template][1] == L)
+  		slot++;
+
+	/* Get kprobe_inst and major_opcode from the bundle */
+	get_kprobe_inst(bundle, slot, &kprobe_inst, &major_opcode);
+
+	prepare_break_inst(template, slot, major_opcode, kprobe_inst, p);
 
 	return 0;
 }
@@ -277,7 +328,7 @@ static void resume_execution(struct kpro
  		if (regs->cr_iip == bundle_addr) {
  			regs->cr_iip = resume_addr;
  		}
- 	}
+	}
 
 turn_ss_off:
   	/* Turn off Single Step bit */

--


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [patch 2/3] Kprobes IA64 cmp ctype unc support
  2005-06-06 17:36 [patch 0/3] Kprobes Ia64 more fixes Anil S Keshavamurthy
  2005-06-06 17:36 ` [patch 1/3] Kprobes IA64 arch prepare kprobes cleanup Anil S Keshavamurthy
@ 2005-06-06 17:36 ` Anil S Keshavamurthy
  2005-06-06 17:36 ` [patch 3/3] Kprobes IA64 safe register kprobe Anil S Keshavamurthy
  2 siblings, 0 replies; 4+ messages in thread
From: Anil S Keshavamurthy @ 2005-06-06 17:36 UTC (permalink / raw)
  To: akpm
  Cc: linux-kernel, linux-ia64, systemtap, rusty.lynch, davidm,
	alen.brunelle, anil.s.keshavamurthy

[-- Attachment #1: kprobes-ia64-qp-fix2.patch --]
[-- Type: text/plain, Size: 3578 bytes --]

The current Kprobes when patching the original instruction
with the break instruction tries to retain the original
qualifying predicate(qp), however for cmp.crel.ctype where
ctype == unc, which is a special instruction always needs to be
executed irrespective of qp. Hence, if the instruction we are patching
is of this type, then we should not copy the original qp to 
the break instruction, this is because we always want the
break fault to happen so that we can emulate the instruction.

This patch is based on the feedback given by David Mosberger

Signed-off-by: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
===================================================================
 arch/ia64/kernel/kprobes.c |   43 +++++++++++++++++++++++++++++++++++++++++--
 include/asm-ia64/kprobes.h |   17 +++++++++++++++++
 2 files changed, 58 insertions(+), 2 deletions(-)

Index: linux-2.6.12-rc5/arch/ia64/kernel/kprobes.c
===================================================================
--- linux-2.6.12-rc5.orig/arch/ia64/kernel/kprobes.c
+++ linux-2.6.12-rc5/arch/ia64/kernel/kprobes.c
@@ -137,6 +137,41 @@ static void update_kprobe_inst_flag(uint
 }
 
 /* 
+ * In this function we check to see if the instruction
+ * (qp) cmpx.crel.ctype p1,p2=r2,r3
+ * on which we are inserting kprobe is cmp instruction
+ * with ctype as unc.
+ */
+static uint is_cmp_ctype_unc_inst(uint template, uint slot, uint major_opcode,
+unsigned long kprobe_inst)
+{
+	cmp_inst_t cmp_inst;
+	uint ctype_unc = 0;
+
+	if (!((bundle_encoding[template][slot] == I) ||
+		(bundle_encoding[template][slot] == M)))
+		goto out;
+
+	if (!((major_opcode == 0xC) || (major_opcode == 0xD) ||
+		(major_opcode == 0xE)))
+		goto out;
+
+	cmp_inst.l = kprobe_inst;
+	if ((cmp_inst.f.x2 == 0) || (cmp_inst.f.x2 == 1)) {
+		/* Integere compare - Register Register (A6 type)*/
+		if ((cmp_inst.f.tb == 0) && (cmp_inst.f.ta == 0)
+				&&(cmp_inst.f.c == 1))
+			ctype_unc = 1;
+	} else if ((cmp_inst.f.x2 == 2)||(cmp_inst.f.x2 == 3)) {
+		/* Integere compare - Immediate Register (A8 type)*/
+		if ((cmp_inst.f.ta == 0) &&(cmp_inst.f.c == 1))
+			ctype_unc = 1;
+	}
+out:
+	return ctype_unc;
+}
+
+/* 
  * In this function we override the bundle with
  * the break instruction at the given slot.
  */
@@ -148,9 +183,13 @@ static void prepare_break_inst(uint temp
 
 	/*
 	 * Copy the original kprobe_inst qualifying predicate(qp)
-	 * to the break instruction
+	 * to the break instruction iff !is_cmp_ctype_unc_inst
+	 * because for cmp instruction with ctype equal to unc,
+	 * which is a special instruction always needs to be
+	 * executed regradless of qp
 	 */
-	break_inst |= (0x3f & kprobe_inst);
+	if (!is_cmp_ctype_unc_inst(template, slot, major_opcode, kprobe_inst))
+		break_inst |= (0x3f & kprobe_inst);
 
 	switch (slot) {
 	  case 0:
Index: linux-2.6.12-rc5/include/asm-ia64/kprobes.h
===================================================================
--- linux-2.6.12-rc5.orig/include/asm-ia64/kprobes.h
+++ linux-2.6.12-rc5/include/asm-ia64/kprobes.h
@@ -30,6 +30,23 @@
 
 #define BREAK_INST	(long)(__IA64_BREAK_KPROBE << 6)
 
+typedef union cmp_inst {
+	struct {
+	unsigned long long qp : 6;
+	unsigned long long p1 : 6;
+	unsigned long long c  : 1;
+	unsigned long long r2 : 7;
+	unsigned long long r3 : 7;
+	unsigned long long p2 : 6;
+	unsigned long long ta : 1;
+	unsigned long long x2 : 2;
+	unsigned long long tb : 1;
+	unsigned long long opcode : 4;
+	unsigned long long reserved : 23;
+	}f;
+	unsigned long long l;
+} cmp_inst_t; 
+
 struct kprobe;
 
 typedef struct _bundle {

--


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [patch 3/3] Kprobes IA64 safe register kprobe
  2005-06-06 17:36 [patch 0/3] Kprobes Ia64 more fixes Anil S Keshavamurthy
  2005-06-06 17:36 ` [patch 1/3] Kprobes IA64 arch prepare kprobes cleanup Anil S Keshavamurthy
  2005-06-06 17:36 ` [patch 2/3] Kprobes IA64 cmp ctype unc support Anil S Keshavamurthy
@ 2005-06-06 17:36 ` Anil S Keshavamurthy
  2 siblings, 0 replies; 4+ messages in thread
From: Anil S Keshavamurthy @ 2005-06-06 17:36 UTC (permalink / raw)
  To: akpm
  Cc: linux-kernel, linux-ia64, systemtap, rusty.lynch, davidm,
	alen.brunelle, anil.s.keshavamurthy

[-- Attachment #1: kprobes-ia64-safe-register-kprobe.patch --]
[-- Type: text/plain, Size: 2379 bytes --]

The current kprobes does not yet handle register
kprobes on some of the following kind of instruction
which needs to be emulated in a special way.
1) mov r1=ip
2) chk -- Speculation check instruction
This patch attempts to fail register_kprobes() when
user tries to insert kprobes on the above kind of
instruction.

Signed-off-by: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
===================================================================
 arch/ia64/kernel/kprobes.c |   45 +++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 45 insertions(+)

Index: linux-2.6.12-rc5/arch/ia64/kernel/kprobes.c
===================================================================
--- linux-2.6.12-rc5.orig/arch/ia64/kernel/kprobes.c
+++ linux-2.6.12-rc5/arch/ia64/kernel/kprobes.c
@@ -98,6 +98,48 @@ static inline void set_current_kprobe(st
 	current_kprobe = p;
 }
 
+/* 
+ * In this function we check to see if the instruction
+ * on which we are inserting kprobe is supported.
+ * Returns 0 if supported
+ * Returns -EINVAL if unsupported
+ */
+static int unsupported_inst(uint template, uint  slot, uint major_opcode,
+	unsigned long kprobe_inst, struct kprobe *p)
+{
+	unsigned long addr = (unsigned long)p->addr;
+	
+	if (bundle_encoding[template][slot] == I) {
+		switch (major_opcode) {
+			case 0x0: //I_UNIT_MISC_OPCODE:
+			/*
+			 * Check for Integer speculation instruction
+			 * - Bit 33-35 to be equal to 0x1
+			 */
+			if (((kprobe_inst >> 33) & 0x7) == 1) {
+				printk(KERN_WARNING 
+					"Kprobes on speculation inst at <0x%lx> not supported\n",
+					addr);
+				return -EINVAL;
+			}
+
+			/*
+			 * IP relative mov instruction
+			 *  - Bit 27-35 to be equal to 0x30
+			 */
+			if (((kprobe_inst >> 27) & 0x1FF) == 0x30) {
+				printk(KERN_WARNING 
+					"Kprobes on \"mov r1=ip\" at <0x%lx> not supported\n",
+					addr);
+				return -EINVAL;
+
+			}
+		}
+	}
+	return 0;
+}
+
+
 /*
  * In this function we check to see if the instruction
  * is IP relative instruction and update the kprobe
@@ -270,6 +312,9 @@ int arch_prepare_kprobe(struct kprobe *p
 
 	/* Get kprobe_inst and major_opcode from the bundle */
 	get_kprobe_inst(bundle, slot, &kprobe_inst, &major_opcode);
+	
+	if (unsupported_inst(template, slot, major_opcode, kprobe_inst, p))
+			return -EINVAL;
 
 	prepare_break_inst(template, slot, major_opcode, kprobe_inst, p);
 

--


^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2005-06-06 17:57 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-06-06 17:36 [patch 0/3] Kprobes Ia64 more fixes Anil S Keshavamurthy
2005-06-06 17:36 ` [patch 1/3] Kprobes IA64 arch prepare kprobes cleanup Anil S Keshavamurthy
2005-06-06 17:36 ` [patch 2/3] Kprobes IA64 cmp ctype unc support Anil S Keshavamurthy
2005-06-06 17:36 ` [patch 3/3] Kprobes IA64 safe register kprobe Anil S Keshavamurthy

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox