aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/kernel/kprobes.c
diff options
context:
space:
mode:
authorJon Medhurst <tixy@yxit.co.uk>2011-06-16 10:54:00 -0400
committerTixy <tixy@medhuaa1.miniserver.com>2011-07-13 13:32:42 -0400
commit3cca6c243568d355c1ccecaaa71bf490f014d729 (patch)
tree8d9a78c0090c59316401c173895dc58b458e9f09 /arch/arm/kernel/kprobes.c
parent6aaa8b5570c7b5b9eb8913ec80263a1012b1dd66 (diff)
ARM: kprobes: Don't trigger probes on conditional instructions when condition is false
This patch changes the behavior of kprobes on ARM so that: Kprobes on conditional instructions don't trigger when the condition is false. For conditional branches, this means that they don't trigger in the branch not taken case. Rationale: When probes are placed onto conditionally executed instructions in a Thumb IT block, they may not fire if the condition is not met. This is because we use invalid instructions for breakpoints and "it is IMPLEMENTATION DEFINED whether the instruction executes as a NOP or causes an Undefined Instruction exception". Therefore, for consistency, we will ignore all probes on any conditional instructions when the condition is false. Alternative solutions seem to be too complex to implement or inconsistent. This issue was discussed on linux.arm.kernel in the thread titled "[RFC] kprobes with thumb2 conditional code" See http://comments.gmane.org/gmane.linux.linaro.devel/2985 Signed-off-by: Jon Medhurst <tixy@yxit.co.uk> Acked-by: Nicolas Pitre <nicolas.pitre@linaro.org>
Diffstat (limited to 'arch/arm/kernel/kprobes.c')
-rw-r--r--arch/arm/kernel/kprobes.c24
1 files changed, 23 insertions, 1 deletions
diff --git a/arch/arm/kernel/kprobes.c b/arch/arm/kernel/kprobes.c
index a9050bad4434..b6e9a1cc1c55 100644
--- a/arch/arm/kernel/kprobes.c
+++ b/arch/arm/kernel/kprobes.c
@@ -207,6 +207,20 @@ static void __kprobes set_current_kprobe(struct kprobe *p)
207 __get_cpu_var(current_kprobe) = p; 207 __get_cpu_var(current_kprobe) = p;
208} 208}
209 209
210static void __kprobes
211singlestep_skip(struct kprobe *p, struct pt_regs *regs)
212{
213#ifdef CONFIG_THUMB2_KERNEL
214 regs->ARM_cpsr = it_advance(regs->ARM_cpsr);
215 if (is_wide_instruction(p->opcode))
216 regs->ARM_pc += 4;
217 else
218 regs->ARM_pc += 2;
219#else
220 regs->ARM_pc += 4;
221#endif
222}
223
210static void __kprobes singlestep(struct kprobe *p, struct pt_regs *regs, 224static void __kprobes singlestep(struct kprobe *p, struct pt_regs *regs,
211 struct kprobe_ctlblk *kcb) 225 struct kprobe_ctlblk *kcb)
212{ 226{
@@ -262,7 +276,8 @@ void __kprobes kprobe_handler(struct pt_regs *regs)
262 /* impossible cases */ 276 /* impossible cases */
263 BUG(); 277 BUG();
264 } 278 }
265 } else { 279 } else if (p->ainsn.insn_check_cc(regs->ARM_cpsr)) {
280 /* Probe hit and conditional execution check ok. */
266 set_current_kprobe(p); 281 set_current_kprobe(p);
267 kcb->kprobe_status = KPROBE_HIT_ACTIVE; 282 kcb->kprobe_status = KPROBE_HIT_ACTIVE;
268 283
@@ -282,6 +297,13 @@ void __kprobes kprobe_handler(struct pt_regs *regs)
282 } 297 }
283 reset_current_kprobe(); 298 reset_current_kprobe();
284 } 299 }
300 } else {
301 /*
302 * Probe hit but conditional execution check failed,
303 * so just skip the instruction and continue as if
304 * nothing had happened.
305 */
306 singlestep_skip(p, regs);
285 } 307 }
286 } else if (cur) { 308 } else if (cur) {
287 /* We probably hit a jprobe. Call its break handler. */ 309 /* We probably hit a jprobe. Call its break handler. */