aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnil S Keshavamurthy <anil.s.keshavamurthy@intel.com>2005-06-23 03:09:32 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-06-23 12:45:23 -0400
commita5403183d84d419651672f1aee5ff2273d185efa (patch)
treec9bcdf302b6dfc2e7230e486791ec48785d9d78f
parent13608d6433eb34840224ef632cc444f3eb59bc13 (diff)
[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>
-rw-r--r--arch/ia64/kernel/kprobes.c191
1 files changed, 121 insertions, 70 deletions
diff --git a/arch/ia64/kernel/kprobes.c b/arch/ia64/kernel/kprobes.c
index 98bef04d9484..5d5344681555 100644
--- a/arch/ia64/kernel/kprobes.c
+++ b/arch/ia64/kernel/kprobes.c
@@ -81,90 +81,141 @@ static enum instruction_type bundle_encoding[32][3] = {
81 { u, u, u }, /* 1F */ 81 { u, u, u }, /* 1F */
82}; 82};
83 83
84int arch_prepare_kprobe(struct kprobe *p) 84/*
85 * In this function we check to see if the instruction
86 * is IP relative instruction and update the kprobe
87 * inst flag accordingly
88 */
89static void update_kprobe_inst_flag(uint template, uint slot, uint major_opcode,
90 unsigned long kprobe_inst, struct kprobe *p)
85{ 91{
86 unsigned long addr = (unsigned long) p->addr;
87 unsigned long *bundle_addr = (unsigned long *)(addr & ~0xFULL);
88 unsigned long slot = addr & 0xf;
89 unsigned long template;
90 unsigned long major_opcode = 0;
91 unsigned long lx_type_inst = 0;
92 unsigned long kprobe_inst = 0;
93 bundle_t *bundle = &p->ainsn.insn.bundle;
94
95 memcpy(&p->opcode.bundle, bundle_addr, sizeof(bundle_t));
96 memcpy(&p->ainsn.insn.bundle, bundle_addr, sizeof(bundle_t));
97
98 p->ainsn.inst_flag = 0; 92 p->ainsn.inst_flag = 0;
99 p->ainsn.target_br_reg = 0; 93 p->ainsn.target_br_reg = 0;
100 94
101 template = bundle->quad0.template; 95 if (bundle_encoding[template][slot] == B) {
96 switch (major_opcode) {
97 case INDIRECT_CALL_OPCODE:
98 p->ainsn.inst_flag |= INST_FLAG_FIX_BRANCH_REG;
99 p->ainsn.target_br_reg = ((kprobe_inst >> 6) & 0x7);
100 break;
101 case IP_RELATIVE_PREDICT_OPCODE:
102 case IP_RELATIVE_BRANCH_OPCODE:
103 p->ainsn.inst_flag |= INST_FLAG_FIX_RELATIVE_IP_ADDR;
104 break;
105 case IP_RELATIVE_CALL_OPCODE:
106 p->ainsn.inst_flag |= INST_FLAG_FIX_RELATIVE_IP_ADDR;
107 p->ainsn.inst_flag |= INST_FLAG_FIX_BRANCH_REG;
108 p->ainsn.target_br_reg = ((kprobe_inst >> 6) & 0x7);
109 break;
110 }
111 } else if (bundle_encoding[template][slot] == X) {
112 switch (major_opcode) {
113 case LONG_CALL_OPCODE:
114 p->ainsn.inst_flag |= INST_FLAG_FIX_BRANCH_REG;
115 p->ainsn.target_br_reg = ((kprobe_inst >> 6) & 0x7);
116 break;
117 }
118 }
119 return;
120}
102 121
103 if (((bundle_encoding[template][1] == L) && slot > 1) || (slot > 2)) { 122/*
104 printk(KERN_WARNING "Attempting to insert unaligned kprobe at 0x%lx\n", 123 * In this function we override the bundle with
105 addr); 124 * the break instruction at the given slot.
106 return -EINVAL; 125 */
126static void prepare_break_inst(uint template, uint slot, uint major_opcode,
127 unsigned long kprobe_inst, struct kprobe *p)
128{
129 unsigned long break_inst = BREAK_INST;
130 bundle_t *bundle = &p->ainsn.insn.bundle;
131
132 /*
133 * Copy the original kprobe_inst qualifying predicate(qp)
134 * to the break instruction
135 */
136 break_inst |= (0x3f & kprobe_inst);
137
138 switch (slot) {
139 case 0:
140 bundle->quad0.slot0 = break_inst;
141 break;
142 case 1:
143 bundle->quad0.slot1_p0 = break_inst;
144 bundle->quad1.slot1_p1 = break_inst >> (64-46);
145 break;
146 case 2:
147 bundle->quad1.slot2 = break_inst;
148 break;
107 } 149 }
108 150
109 if (slot == 1 && bundle_encoding[template][1] == L) { 151 /*
110 lx_type_inst = 1; 152 * Update the instruction flag, so that we can
111 slot = 2; 153 * emulate the instruction properly after we
112 } 154 * single step on original instruction
155 */
156 update_kprobe_inst_flag(template, slot, major_opcode, kprobe_inst, p);
157}
158
159static inline void get_kprobe_inst(bundle_t *bundle, uint slot,
160 unsigned long *kprobe_inst, uint *major_opcode)
161{
162 unsigned long kprobe_inst_p0, kprobe_inst_p1;
163 unsigned int template;
164
165 template = bundle->quad0.template;
113 166
114 switch (slot) { 167 switch (slot) {
115 case 0: 168 case 0:
116 major_opcode = (bundle->quad0.slot0 >> SLOT0_OPCODE_SHIFT); 169 *major_opcode = (bundle->quad0.slot0 >> SLOT0_OPCODE_SHIFT);
117 kprobe_inst = bundle->quad0.slot0; 170 *kprobe_inst = bundle->quad0.slot0;
118 bundle->quad0.slot0 = BREAK_INST | (0x3f & kprobe_inst);
119 break; 171 break;
120 case 1: 172 case 1:
121 major_opcode = (bundle->quad1.slot1_p1 >> SLOT1_p1_OPCODE_SHIFT); 173 *major_opcode = (bundle->quad1.slot1_p1 >> SLOT1_p1_OPCODE_SHIFT);
122 kprobe_inst = (bundle->quad0.slot1_p0 | 174 kprobe_inst_p0 = bundle->quad0.slot1_p0;
123 (bundle->quad1.slot1_p1 << (64-46))); 175 kprobe_inst_p1 = bundle->quad1.slot1_p1;
124 bundle->quad0.slot1_p0 = BREAK_INST | (0x3f & kprobe_inst); 176 *kprobe_inst = kprobe_inst_p0 | (kprobe_inst_p1 << (64-46));
125 bundle->quad1.slot1_p1 = (BREAK_INST >> (64-46));
126 break; 177 break;
127 case 2: 178 case 2:
128 major_opcode = (bundle->quad1.slot2 >> SLOT2_OPCODE_SHIFT); 179 *major_opcode = (bundle->quad1.slot2 >> SLOT2_OPCODE_SHIFT);
129 kprobe_inst = bundle->quad1.slot2; 180 *kprobe_inst = bundle->quad1.slot2;
130 bundle->quad1.slot2 = BREAK_INST | (0x3f & kprobe_inst);
131 break; 181 break;
132 } 182 }
183}
133 184
134 /* 185static int valid_kprobe_addr(int template, int slot, unsigned long addr)
135 * Look for IP relative Branches, IP relative call or 186{
136 * IP relative predicate instructions 187 if ((slot > 2) || ((bundle_encoding[template][1] == L) && slot > 1)) {
137 */ 188 printk(KERN_WARNING "Attempting to insert unaligned kprobe at 0x%lx\n",
138 if (bundle_encoding[template][slot] == B) { 189 addr);
139 switch (major_opcode) { 190 return -EINVAL;
140 case INDIRECT_CALL_OPCODE:
141 p->ainsn.inst_flag |= INST_FLAG_FIX_BRANCH_REG;
142 p->ainsn.target_br_reg = ((kprobe_inst >> 6) & 0x7);
143 break;
144 case IP_RELATIVE_PREDICT_OPCODE:
145 case IP_RELATIVE_BRANCH_OPCODE:
146 p->ainsn.inst_flag |= INST_FLAG_FIX_RELATIVE_IP_ADDR;
147 break;
148 case IP_RELATIVE_CALL_OPCODE:
149 p->ainsn.inst_flag |= INST_FLAG_FIX_RELATIVE_IP_ADDR;
150 p->ainsn.inst_flag |= INST_FLAG_FIX_BRANCH_REG;
151 p->ainsn.target_br_reg = ((kprobe_inst >> 6) & 0x7);
152 break;
153 default:
154 /* Do nothing */
155 break;
156 }
157 } else if (lx_type_inst) {
158 switch (major_opcode) {
159 case LONG_CALL_OPCODE:
160 p->ainsn.inst_flag |= INST_FLAG_FIX_BRANCH_REG;
161 p->ainsn.target_br_reg = ((kprobe_inst >> 6) & 0x7);
162 break;
163 default:
164 /* Do nothing */
165 break;
166 }
167 } 191 }
192 return 0;
193}
194
195int arch_prepare_kprobe(struct kprobe *p)
196{
197 unsigned long addr = (unsigned long) p->addr;
198 unsigned long *kprobe_addr = (unsigned long *)(addr & ~0xFULL);
199 unsigned long kprobe_inst=0;
200 unsigned int slot = addr & 0xf, template, major_opcode = 0;
201 bundle_t *bundle = &p->ainsn.insn.bundle;
202
203 memcpy(&p->opcode.bundle, kprobe_addr, sizeof(bundle_t));
204 memcpy(&p->ainsn.insn.bundle, kprobe_addr, sizeof(bundle_t));
205
206 template = bundle->quad0.template;
207
208 if(valid_kprobe_addr(template, slot, addr))
209 return -EINVAL;
210
211 /* Move to slot 2, if bundle is MLX type and kprobe slot is 1 */
212 if (slot == 1 && bundle_encoding[template][1] == L)
213 slot++;
214
215 /* Get kprobe_inst and major_opcode from the bundle */
216 get_kprobe_inst(bundle, slot, &kprobe_inst, &major_opcode);
217
218 prepare_break_inst(template, slot, major_opcode, kprobe_inst, p);
168 219
169 return 0; 220 return 0;
170} 221}
@@ -260,7 +311,7 @@ static void resume_execution(struct kprobe *p, struct pt_regs *regs)
260 if (regs->cr_iip == bundle_addr) { 311 if (regs->cr_iip == bundle_addr) {
261 regs->cr_iip = resume_addr; 312 regs->cr_iip = resume_addr;
262 } 313 }
263 } 314 }
264 315
265turn_ss_off: 316turn_ss_off:
266 /* Turn off Single Step bit */ 317 /* Turn off Single Step bit */