aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/kernel/kprobes-thumb.c
diff options
context:
space:
mode:
authorJon Medhurst <tixy@yxit.co.uk>2011-07-02 11:30:43 -0400
committerTixy <tixy@medhuaa1.miniserver.com>2011-07-13 13:32:45 -0400
commit396b41f68d937a0c48ba624186ed06288b35bb4e (patch)
treef9e034023f80db80a7b446ce552432dc637e9455 /arch/arm/kernel/kprobes-thumb.c
parent444956677eccfcdfe05de761e1286f62c423ce88 (diff)
ARM: kprobes: Decode 16-bit Thumb branch instructions
We previously changed the behaviour of probes so that conditional instructions don't fire when the condition isn't met. For ARM branches, and Thumb branches in IT blocks, this means they don't fire if the branch isn't taken. For consistency, we implement the same for Thumb conditional branch instructions. This involves setting up insn_check_cc to point to the relevant condition checking function. As the emulation routine is only called when this condition passes, it doesn't need to check again and can unconditionally update PC. Signed-off-by: Jon Medhurst <tixy@yxit.co.uk> Acked-by: Nicolas Pitre <nicolas.pitre@linaro.org>
Diffstat (limited to 'arch/arm/kernel/kprobes-thumb.c')
-rw-r--r--arch/arm/kernel/kprobes-thumb.c38
1 files changed, 38 insertions, 0 deletions
diff --git a/arch/arm/kernel/kprobes-thumb.c b/arch/arm/kernel/kprobes-thumb.c
index 997fc6d59a40..d3133fd2d4e8 100644
--- a/arch/arm/kernel/kprobes-thumb.c
+++ b/arch/arm/kernel/kprobes-thumb.c
@@ -141,6 +141,35 @@ t16_decode_it(kprobe_opcode_t insn, struct arch_specific_insn *asi)
141 return INSN_GOOD_NO_SLOT; 141 return INSN_GOOD_NO_SLOT;
142} 142}
143 143
144static void __kprobes
145t16_simulate_cond_branch(struct kprobe *p, struct pt_regs *regs)
146{
147 kprobe_opcode_t insn = p->opcode;
148 unsigned long pc = thumb_probe_pc(p);
149 long offset = insn & 0x7f;
150 offset -= insn & 0x80; /* Apply sign bit */
151 regs->ARM_pc = pc + (offset * 2);
152}
153
154static enum kprobe_insn __kprobes
155t16_decode_cond_branch(kprobe_opcode_t insn, struct arch_specific_insn *asi)
156{
157 int cc = (insn >> 8) & 0xf;
158 asi->insn_check_cc = kprobe_condition_checks[cc];
159 asi->insn_handler = t16_simulate_cond_branch;
160 return INSN_GOOD_NO_SLOT;
161}
162
163static void __kprobes
164t16_simulate_branch(struct kprobe *p, struct pt_regs *regs)
165{
166 kprobe_opcode_t insn = p->opcode;
167 unsigned long pc = thumb_probe_pc(p);
168 long offset = insn & 0x3ff;
169 offset -= insn & 0x400; /* Apply sign bit */
170 regs->ARM_pc = pc + (offset * 2);
171}
172
144static unsigned long __kprobes 173static unsigned long __kprobes
145t16_emulate_loregs(struct kprobe *p, struct pt_regs *regs) 174t16_emulate_loregs(struct kprobe *p, struct pt_regs *regs)
146{ 175{
@@ -472,6 +501,15 @@ const union decode_item kprobe_decode_thumb16_table[] = {
472 /* SVC 1101 1111 xxxx xxxx */ 501 /* SVC 1101 1111 xxxx xxxx */
473 DECODE_REJECT (0xfe00, 0xde00), 502 DECODE_REJECT (0xfe00, 0xde00),
474 503
504 /* Conditional branch 1101 xxxx xxxx xxxx */
505 DECODE_CUSTOM (0xf000, 0xd000, t16_decode_cond_branch),
506
507 /*
508 * Unconditional branch
509 * B 1110 0xxx xxxx xxxx
510 */
511 DECODE_SIMULATE (0xf800, 0xe000, t16_simulate_branch),
512
475 DECODE_END 513 DECODE_END
476}; 514};
477 515