diff options
Diffstat (limited to 'arch/mips/kernel/kprobes.c')
-rw-r--r-- | arch/mips/kernel/kprobes.c | 177 |
1 files changed, 148 insertions, 29 deletions
diff --git a/arch/mips/kernel/kprobes.c b/arch/mips/kernel/kprobes.c index ee28683fc2ac..158467da9bc1 100644 --- a/arch/mips/kernel/kprobes.c +++ b/arch/mips/kernel/kprobes.c | |||
@@ -25,10 +25,12 @@ | |||
25 | 25 | ||
26 | #include <linux/kprobes.h> | 26 | #include <linux/kprobes.h> |
27 | #include <linux/preempt.h> | 27 | #include <linux/preempt.h> |
28 | #include <linux/uaccess.h> | ||
28 | #include <linux/kdebug.h> | 29 | #include <linux/kdebug.h> |
29 | #include <linux/slab.h> | 30 | #include <linux/slab.h> |
30 | 31 | ||
31 | #include <asm/ptrace.h> | 32 | #include <asm/ptrace.h> |
33 | #include <asm/branch.h> | ||
32 | #include <asm/break.h> | 34 | #include <asm/break.h> |
33 | #include <asm/inst.h> | 35 | #include <asm/inst.h> |
34 | 36 | ||
@@ -112,17 +114,49 @@ insn_ok: | |||
112 | return 0; | 114 | return 0; |
113 | } | 115 | } |
114 | 116 | ||
117 | /* | ||
118 | * insn_has_ll_or_sc function checks whether instruction is ll or sc | ||
119 | * one; putting breakpoint on top of atomic ll/sc pair is bad idea; | ||
120 | * so we need to prevent it and refuse kprobes insertion for such | ||
121 | * instructions; cannot do much about breakpoint in the middle of | ||
122 | * ll/sc pair; it is upto user to avoid those places | ||
123 | */ | ||
124 | static int __kprobes insn_has_ll_or_sc(union mips_instruction insn) | ||
125 | { | ||
126 | int ret = 0; | ||
127 | |||
128 | switch (insn.i_format.opcode) { | ||
129 | case ll_op: | ||
130 | case lld_op: | ||
131 | case sc_op: | ||
132 | case scd_op: | ||
133 | ret = 1; | ||
134 | break; | ||
135 | default: | ||
136 | break; | ||
137 | } | ||
138 | return ret; | ||
139 | } | ||
140 | |||
115 | int __kprobes arch_prepare_kprobe(struct kprobe *p) | 141 | int __kprobes arch_prepare_kprobe(struct kprobe *p) |
116 | { | 142 | { |
117 | union mips_instruction insn; | 143 | union mips_instruction insn; |
118 | union mips_instruction prev_insn; | 144 | union mips_instruction prev_insn; |
119 | int ret = 0; | 145 | int ret = 0; |
120 | 146 | ||
121 | prev_insn = p->addr[-1]; | ||
122 | insn = p->addr[0]; | 147 | insn = p->addr[0]; |
123 | 148 | ||
124 | if (insn_has_delayslot(insn) || insn_has_delayslot(prev_insn)) { | 149 | if (insn_has_ll_or_sc(insn)) { |
125 | pr_notice("Kprobes for branch and jump instructions are not supported\n"); | 150 | pr_notice("Kprobes for ll and sc instructions are not" |
151 | "supported\n"); | ||
152 | ret = -EINVAL; | ||
153 | goto out; | ||
154 | } | ||
155 | |||
156 | if ((probe_kernel_read(&prev_insn, p->addr - 1, | ||
157 | sizeof(mips_instruction)) == 0) && | ||
158 | insn_has_delayslot(prev_insn)) { | ||
159 | pr_notice("Kprobes for branch delayslot are not supported\n"); | ||
126 | ret = -EINVAL; | 160 | ret = -EINVAL; |
127 | goto out; | 161 | goto out; |
128 | } | 162 | } |
@@ -138,9 +172,20 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) | |||
138 | * In the kprobe->ainsn.insn[] array we store the original | 172 | * In the kprobe->ainsn.insn[] array we store the original |
139 | * instruction at index zero and a break trap instruction at | 173 | * instruction at index zero and a break trap instruction at |
140 | * index one. | 174 | * index one. |
175 | * | ||
176 | * On MIPS arch if the instruction at probed address is a | ||
177 | * branch instruction, we need to execute the instruction at | ||
178 | * Branch Delayslot (BD) at the time of probe hit. As MIPS also | ||
179 | * doesn't have single stepping support, the BD instruction can | ||
180 | * not be executed in-line and it would be executed on SSOL slot | ||
181 | * using a normal breakpoint instruction in the next slot. | ||
182 | * So, read the instruction and save it for later execution. | ||
141 | */ | 183 | */ |
184 | if (insn_has_delayslot(insn)) | ||
185 | memcpy(&p->ainsn.insn[0], p->addr + 1, sizeof(kprobe_opcode_t)); | ||
186 | else | ||
187 | memcpy(&p->ainsn.insn[0], p->addr, sizeof(kprobe_opcode_t)); | ||
142 | 188 | ||
143 | memcpy(&p->ainsn.insn[0], p->addr, sizeof(kprobe_opcode_t)); | ||
144 | p->ainsn.insn[1] = breakpoint2_insn; | 189 | p->ainsn.insn[1] = breakpoint2_insn; |
145 | p->opcode = *p->addr; | 190 | p->opcode = *p->addr; |
146 | 191 | ||
@@ -191,16 +236,96 @@ static void set_current_kprobe(struct kprobe *p, struct pt_regs *regs, | |||
191 | kcb->kprobe_saved_epc = regs->cp0_epc; | 236 | kcb->kprobe_saved_epc = regs->cp0_epc; |
192 | } | 237 | } |
193 | 238 | ||
194 | static void prepare_singlestep(struct kprobe *p, struct pt_regs *regs) | 239 | /** |
240 | * evaluate_branch_instrucion - | ||
241 | * | ||
242 | * Evaluate the branch instruction at probed address during probe hit. The | ||
243 | * result of evaluation would be the updated epc. The insturction in delayslot | ||
244 | * would actually be single stepped using a normal breakpoint) on SSOL slot. | ||
245 | * | ||
246 | * The result is also saved in the kprobe control block for later use, | ||
247 | * in case we need to execute the delayslot instruction. The latter will be | ||
248 | * false for NOP instruction in dealyslot and the branch-likely instructions | ||
249 | * when the branch is taken. And for those cases we set a flag as | ||
250 | * SKIP_DELAYSLOT in the kprobe control block | ||
251 | */ | ||
252 | static int evaluate_branch_instruction(struct kprobe *p, struct pt_regs *regs, | ||
253 | struct kprobe_ctlblk *kcb) | ||
195 | { | 254 | { |
255 | union mips_instruction insn = p->opcode; | ||
256 | long epc; | ||
257 | int ret = 0; | ||
258 | |||
259 | epc = regs->cp0_epc; | ||
260 | if (epc & 3) | ||
261 | goto unaligned; | ||
262 | |||
263 | if (p->ainsn.insn->word == 0) | ||
264 | kcb->flags |= SKIP_DELAYSLOT; | ||
265 | else | ||
266 | kcb->flags &= ~SKIP_DELAYSLOT; | ||
267 | |||
268 | ret = __compute_return_epc_for_insn(regs, insn); | ||
269 | if (ret < 0) | ||
270 | return ret; | ||
271 | |||
272 | if (ret == BRANCH_LIKELY_TAKEN) | ||
273 | kcb->flags |= SKIP_DELAYSLOT; | ||
274 | |||
275 | kcb->target_epc = regs->cp0_epc; | ||
276 | |||
277 | return 0; | ||
278 | |||
279 | unaligned: | ||
280 | pr_notice("%s: unaligned epc - sending SIGBUS.\n", current->comm); | ||
281 | force_sig(SIGBUS, current); | ||
282 | return -EFAULT; | ||
283 | |||
284 | } | ||
285 | |||
286 | static void prepare_singlestep(struct kprobe *p, struct pt_regs *regs, | ||
287 | struct kprobe_ctlblk *kcb) | ||
288 | { | ||
289 | int ret = 0; | ||
290 | |||
196 | regs->cp0_status &= ~ST0_IE; | 291 | regs->cp0_status &= ~ST0_IE; |
197 | 292 | ||
198 | /* single step inline if the instruction is a break */ | 293 | /* single step inline if the instruction is a break */ |
199 | if (p->opcode.word == breakpoint_insn.word || | 294 | if (p->opcode.word == breakpoint_insn.word || |
200 | p->opcode.word == breakpoint2_insn.word) | 295 | p->opcode.word == breakpoint2_insn.word) |
201 | regs->cp0_epc = (unsigned long)p->addr; | 296 | regs->cp0_epc = (unsigned long)p->addr; |
202 | else | 297 | else if (insn_has_delayslot(p->opcode)) { |
203 | regs->cp0_epc = (unsigned long)&p->ainsn.insn[0]; | 298 | ret = evaluate_branch_instruction(p, regs, kcb); |
299 | if (ret < 0) { | ||
300 | pr_notice("Kprobes: Error in evaluating branch\n"); | ||
301 | return; | ||
302 | } | ||
303 | } | ||
304 | regs->cp0_epc = (unsigned long)&p->ainsn.insn[0]; | ||
305 | } | ||
306 | |||
307 | /* | ||
308 | * Called after single-stepping. p->addr is the address of the | ||
309 | * instruction whose first byte has been replaced by the "break 0" | ||
310 | * instruction. To avoid the SMP problems that can occur when we | ||
311 | * temporarily put back the original opcode to single-step, we | ||
312 | * single-stepped a copy of the instruction. The address of this | ||
313 | * copy is p->ainsn.insn. | ||
314 | * | ||
315 | * This function prepares to return from the post-single-step | ||
316 | * breakpoint trap. In case of branch instructions, the target | ||
317 | * epc to be restored. | ||
318 | */ | ||
319 | static void __kprobes resume_execution(struct kprobe *p, | ||
320 | struct pt_regs *regs, | ||
321 | struct kprobe_ctlblk *kcb) | ||
322 | { | ||
323 | if (insn_has_delayslot(p->opcode)) | ||
324 | regs->cp0_epc = kcb->target_epc; | ||
325 | else { | ||
326 | unsigned long orig_epc = kcb->kprobe_saved_epc; | ||
327 | regs->cp0_epc = orig_epc + 4; | ||
328 | } | ||
204 | } | 329 | } |
205 | 330 | ||
206 | static int __kprobes kprobe_handler(struct pt_regs *regs) | 331 | static int __kprobes kprobe_handler(struct pt_regs *regs) |
@@ -239,8 +364,13 @@ static int __kprobes kprobe_handler(struct pt_regs *regs) | |||
239 | save_previous_kprobe(kcb); | 364 | save_previous_kprobe(kcb); |
240 | set_current_kprobe(p, regs, kcb); | 365 | set_current_kprobe(p, regs, kcb); |
241 | kprobes_inc_nmissed_count(p); | 366 | kprobes_inc_nmissed_count(p); |
242 | prepare_singlestep(p, regs); | 367 | prepare_singlestep(p, regs, kcb); |
243 | kcb->kprobe_status = KPROBE_REENTER; | 368 | kcb->kprobe_status = KPROBE_REENTER; |
369 | if (kcb->flags & SKIP_DELAYSLOT) { | ||
370 | resume_execution(p, regs, kcb); | ||
371 | restore_previous_kprobe(kcb); | ||
372 | preempt_enable_no_resched(); | ||
373 | } | ||
244 | return 1; | 374 | return 1; |
245 | } else { | 375 | } else { |
246 | if (addr->word != breakpoint_insn.word) { | 376 | if (addr->word != breakpoint_insn.word) { |
@@ -284,8 +414,16 @@ static int __kprobes kprobe_handler(struct pt_regs *regs) | |||
284 | } | 414 | } |
285 | 415 | ||
286 | ss_probe: | 416 | ss_probe: |
287 | prepare_singlestep(p, regs); | 417 | prepare_singlestep(p, regs, kcb); |
288 | kcb->kprobe_status = KPROBE_HIT_SS; | 418 | if (kcb->flags & SKIP_DELAYSLOT) { |
419 | kcb->kprobe_status = KPROBE_HIT_SSDONE; | ||
420 | if (p->post_handler) | ||
421 | p->post_handler(p, regs, 0); | ||
422 | resume_execution(p, regs, kcb); | ||
423 | preempt_enable_no_resched(); | ||
424 | } else | ||
425 | kcb->kprobe_status = KPROBE_HIT_SS; | ||
426 | |||
289 | return 1; | 427 | return 1; |
290 | 428 | ||
291 | no_kprobe: | 429 | no_kprobe: |
@@ -294,25 +432,6 @@ no_kprobe: | |||
294 | 432 | ||
295 | } | 433 | } |
296 | 434 | ||
297 | /* | ||
298 | * Called after single-stepping. p->addr is the address of the | ||
299 | * instruction whose first byte has been replaced by the "break 0" | ||
300 | * instruction. To avoid the SMP problems that can occur when we | ||
301 | * temporarily put back the original opcode to single-step, we | ||
302 | * single-stepped a copy of the instruction. The address of this | ||
303 | * copy is p->ainsn.insn. | ||
304 | * | ||
305 | * This function prepares to return from the post-single-step | ||
306 | * breakpoint trap. | ||
307 | */ | ||
308 | static void __kprobes resume_execution(struct kprobe *p, | ||
309 | struct pt_regs *regs, | ||
310 | struct kprobe_ctlblk *kcb) | ||
311 | { | ||
312 | unsigned long orig_epc = kcb->kprobe_saved_epc; | ||
313 | regs->cp0_epc = orig_epc + 4; | ||
314 | } | ||
315 | |||
316 | static inline int post_kprobe_handler(struct pt_regs *regs) | 435 | static inline int post_kprobe_handler(struct pt_regs *regs) |
317 | { | 436 | { |
318 | struct kprobe *cur = kprobe_running(); | 437 | struct kprobe *cur = kprobe_running(); |