diff options
author | Maneesh Soni <manesoni@cisco.com> | 2011-11-08 06:38:26 -0500 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2011-12-07 17:04:03 -0500 |
commit | 6457a396bbc20656009eaf950ca165912a943520 (patch) | |
tree | 5a940616d2b1b55f182d4022a39c4d37a9cda1e7 /arch/mips | |
parent | d8d4e3ae0b5c179c0bfd3f0af5b352d13bea9cfa (diff) |
MIPS Kprobes: Support branch instructions probing
This patch provides support for kprobes on branch instructions. The branch
instruction at the probed address is actually emulated and not executed
out-of-line like other normal instructions. Instead the delay-slot instruction
is copied and single stepped out of line.
At the time of probe hit, the original branch instruction is evaluated
and the target cp0_epc is computed similar to compute_retrun_epc(). It
is also checked if the delay slot instruction can be skipped, which is
true if there is a NOP in delay slot or branch is taken in case of
branch likely instructions. Once the delay slot instruction is single
stepped the normal execution resume with the cp0_epc updated the earlier
computed cp0_epc as per the branch instructions.
Signed-off-by: Maneesh Soni <manesoni@cisco.com>
Signed-off-by: Victor Kamensky <kamensky@cisco.com>
Cc: David Daney <david.daney@cavium.com>
Cc: ananth@in.ibm.com
Cc: linux-kernel@vger.kernel.org
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/2914/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips')
-rw-r--r-- | arch/mips/include/asm/kprobes.h | 5 | ||||
-rw-r--r-- | arch/mips/kernel/kprobes.c | 145 |
2 files changed, 117 insertions, 33 deletions
diff --git a/arch/mips/include/asm/kprobes.h b/arch/mips/include/asm/kprobes.h index e6ea4d4d7205..1fbbca01e681 100644 --- a/arch/mips/include/asm/kprobes.h +++ b/arch/mips/include/asm/kprobes.h | |||
@@ -74,6 +74,8 @@ struct prev_kprobe { | |||
74 | : MAX_JPROBES_STACK_SIZE) | 74 | : MAX_JPROBES_STACK_SIZE) |
75 | 75 | ||
76 | 76 | ||
77 | #define SKIP_DELAYSLOT 0x0001 | ||
78 | |||
77 | /* per-cpu kprobe control block */ | 79 | /* per-cpu kprobe control block */ |
78 | struct kprobe_ctlblk { | 80 | struct kprobe_ctlblk { |
79 | unsigned long kprobe_status; | 81 | unsigned long kprobe_status; |
@@ -82,6 +84,9 @@ struct kprobe_ctlblk { | |||
82 | unsigned long kprobe_saved_epc; | 84 | unsigned long kprobe_saved_epc; |
83 | unsigned long jprobe_saved_sp; | 85 | unsigned long jprobe_saved_sp; |
84 | struct pt_regs jprobe_saved_regs; | 86 | struct pt_regs jprobe_saved_regs; |
87 | /* Per-thread fields, used while emulating branches */ | ||
88 | unsigned long flags; | ||
89 | unsigned long target_epc; | ||
85 | u8 jprobes_stack[MAX_JPROBES_STACK_SIZE]; | 90 | u8 jprobes_stack[MAX_JPROBES_STACK_SIZE]; |
86 | struct prev_kprobe prev_kprobe; | 91 | struct prev_kprobe prev_kprobe; |
87 | }; | 92 | }; |
diff --git a/arch/mips/kernel/kprobes.c b/arch/mips/kernel/kprobes.c index 0ab1a5ff1049..158467da9bc1 100644 --- a/arch/mips/kernel/kprobes.c +++ b/arch/mips/kernel/kprobes.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <linux/slab.h> | 30 | #include <linux/slab.h> |
31 | 31 | ||
32 | #include <asm/ptrace.h> | 32 | #include <asm/ptrace.h> |
33 | #include <asm/branch.h> | ||
33 | #include <asm/break.h> | 34 | #include <asm/break.h> |
34 | #include <asm/inst.h> | 35 | #include <asm/inst.h> |
35 | 36 | ||
@@ -152,13 +153,6 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) | |||
152 | goto out; | 153 | goto out; |
153 | } | 154 | } |
154 | 155 | ||
155 | if (insn_has_delayslot(insn)) { | ||
156 | pr_notice("Kprobes for branch and jump instructions are not" | ||
157 | "supported\n"); | ||
158 | ret = -EINVAL; | ||
159 | goto out; | ||
160 | } | ||
161 | |||
162 | if ((probe_kernel_read(&prev_insn, p->addr - 1, | 156 | if ((probe_kernel_read(&prev_insn, p->addr - 1, |
163 | sizeof(mips_instruction)) == 0) && | 157 | sizeof(mips_instruction)) == 0) && |
164 | insn_has_delayslot(prev_insn)) { | 158 | insn_has_delayslot(prev_insn)) { |
@@ -178,9 +172,20 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) | |||
178 | * In the kprobe->ainsn.insn[] array we store the original | 172 | * In the kprobe->ainsn.insn[] array we store the original |
179 | * instruction at index zero and a break trap instruction at | 173 | * instruction at index zero and a break trap instruction at |
180 | * 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. | ||
181 | */ | 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)); | ||
182 | 188 | ||
183 | memcpy(&p->ainsn.insn[0], p->addr, sizeof(kprobe_opcode_t)); | ||
184 | p->ainsn.insn[1] = breakpoint2_insn; | 189 | p->ainsn.insn[1] = breakpoint2_insn; |
185 | p->opcode = *p->addr; | 190 | p->opcode = *p->addr; |
186 | 191 | ||
@@ -231,16 +236,96 @@ static void set_current_kprobe(struct kprobe *p, struct pt_regs *regs, | |||
231 | kcb->kprobe_saved_epc = regs->cp0_epc; | 236 | kcb->kprobe_saved_epc = regs->cp0_epc; |
232 | } | 237 | } |
233 | 238 | ||
234 | 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) | ||
235 | { | 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 | |||
236 | regs->cp0_status &= ~ST0_IE; | 291 | regs->cp0_status &= ~ST0_IE; |
237 | 292 | ||
238 | /* single step inline if the instruction is a break */ | 293 | /* single step inline if the instruction is a break */ |
239 | if (p->opcode.word == breakpoint_insn.word || | 294 | if (p->opcode.word == breakpoint_insn.word || |
240 | p->opcode.word == breakpoint2_insn.word) | 295 | p->opcode.word == breakpoint2_insn.word) |
241 | regs->cp0_epc = (unsigned long)p->addr; | 296 | regs->cp0_epc = (unsigned long)p->addr; |
242 | else | 297 | else if (insn_has_delayslot(p->opcode)) { |
243 | 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 | } | ||
244 | } | 329 | } |
245 | 330 | ||
246 | static int __kprobes kprobe_handler(struct pt_regs *regs) | 331 | static int __kprobes kprobe_handler(struct pt_regs *regs) |
@@ -279,8 +364,13 @@ static int __kprobes kprobe_handler(struct pt_regs *regs) | |||
279 | save_previous_kprobe(kcb); | 364 | save_previous_kprobe(kcb); |
280 | set_current_kprobe(p, regs, kcb); | 365 | set_current_kprobe(p, regs, kcb); |
281 | kprobes_inc_nmissed_count(p); | 366 | kprobes_inc_nmissed_count(p); |
282 | prepare_singlestep(p, regs); | 367 | prepare_singlestep(p, regs, kcb); |
283 | 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 | } | ||
284 | return 1; | 374 | return 1; |
285 | } else { | 375 | } else { |
286 | if (addr->word != breakpoint_insn.word) { | 376 | if (addr->word != breakpoint_insn.word) { |
@@ -324,8 +414,16 @@ static int __kprobes kprobe_handler(struct pt_regs *regs) | |||
324 | } | 414 | } |
325 | 415 | ||
326 | ss_probe: | 416 | ss_probe: |
327 | prepare_singlestep(p, regs); | 417 | prepare_singlestep(p, regs, kcb); |
328 | 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 | |||
329 | return 1; | 427 | return 1; |
330 | 428 | ||
331 | no_kprobe: | 429 | no_kprobe: |
@@ -334,25 +432,6 @@ no_kprobe: | |||
334 | 432 | ||
335 | } | 433 | } |
336 | 434 | ||
337 | /* | ||
338 | * Called after single-stepping. p->addr is the address of the | ||
339 | * instruction whose first byte has been replaced by the "break 0" | ||
340 | * instruction. To avoid the SMP problems that can occur when we | ||
341 | * temporarily put back the original opcode to single-step, we | ||
342 | * single-stepped a copy of the instruction. The address of this | ||
343 | * copy is p->ainsn.insn. | ||
344 | * | ||
345 | * This function prepares to return from the post-single-step | ||
346 | * breakpoint trap. | ||
347 | */ | ||
348 | static void __kprobes resume_execution(struct kprobe *p, | ||
349 | struct pt_regs *regs, | ||
350 | struct kprobe_ctlblk *kcb) | ||
351 | { | ||
352 | unsigned long orig_epc = kcb->kprobe_saved_epc; | ||
353 | regs->cp0_epc = orig_epc + 4; | ||
354 | } | ||
355 | |||
356 | static inline int post_kprobe_handler(struct pt_regs *regs) | 435 | static inline int post_kprobe_handler(struct pt_regs *regs) |
357 | { | 436 | { |
358 | struct kprobe *cur = kprobe_running(); | 437 | struct kprobe *cur = kprobe_running(); |