[PATCH] Kprobes IA64: arch_prepare_kprobes() cleanup

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>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
diff --git a/arch/ia64/kernel/kprobes.c b/arch/ia64/kernel/kprobes.c
index 98bef04..5d53446 100644
--- a/arch/ia64/kernel/kprobes.c
+++ b/arch/ia64/kernel/kprobes.c
@@ -81,90 +81,141 @@
   { u, u, u },  			/* 1F */
 };
 
-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)) {
+/*
+ * 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;
+	}
+
+	/*
+	 * 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;
+		break;
+	  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;
+		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;
+}
 
- 	if (slot == 1 && bundle_encoding[template][1] == L) {
- 		lx_type_inst = 1;
-  		slot = 2;
- 	}
+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;
 
-	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);
-		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));
-		break;
-	case 2:
- 		major_opcode = (bundle->quad1.slot2 >> SLOT2_OPCODE_SHIFT);
- 		kprobe_inst = bundle->quad1.slot2;
-		bundle->quad1.slot2 = BREAK_INST | (0x3f & kprobe_inst);
-		break;
-	}
+	memcpy(&p->opcode.bundle, kprobe_addr, sizeof(bundle_t));
+	memcpy(&p->ainsn.insn.bundle, kprobe_addr, sizeof(bundle_t));
 
- 	/*
- 	 * 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;
- 		}
-	}
+ 	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;
 }
@@ -260,7 +311,7 @@
  		if (regs->cr_iip == bundle_addr) {
  			regs->cr_iip = resume_addr;
  		}
- 	}
+	}
 
 turn_ss_off:
   	/* Turn off Single Step bit */