diff options
-rw-r--r-- | arch/arm/include/asm/kprobes.h | 9 | ||||
-rw-r--r-- | arch/arm/kernel/kprobes-arm.c | 7 | ||||
-rw-r--r-- | arch/arm/kernel/kprobes-thumb.c | 16 | ||||
-rw-r--r-- | arch/arm/kernel/kprobes.c | 8 |
4 files changed, 31 insertions, 9 deletions
diff --git a/arch/arm/include/asm/kprobes.h b/arch/arm/include/asm/kprobes.h index 57d37d52d71e..1e9ff56d40c7 100644 --- a/arch/arm/include/asm/kprobes.h +++ b/arch/arm/include/asm/kprobes.h | |||
@@ -32,14 +32,15 @@ typedef u32 kprobe_opcode_t; | |||
32 | 32 | ||
33 | struct kprobe; | 33 | struct kprobe; |
34 | typedef void (kprobe_insn_handler_t)(struct kprobe *, struct pt_regs *); | 34 | typedef void (kprobe_insn_handler_t)(struct kprobe *, struct pt_regs *); |
35 | |||
36 | typedef unsigned long (kprobe_check_cc)(unsigned long); | 35 | typedef unsigned long (kprobe_check_cc)(unsigned long); |
36 | typedef void (kprobe_insn_singlestep_t)(struct kprobe *, struct pt_regs *); | ||
37 | 37 | ||
38 | /* Architecture specific copy of original instruction. */ | 38 | /* Architecture specific copy of original instruction. */ |
39 | struct arch_specific_insn { | 39 | struct arch_specific_insn { |
40 | kprobe_opcode_t *insn; | 40 | kprobe_opcode_t *insn; |
41 | kprobe_insn_handler_t *insn_handler; | 41 | kprobe_insn_handler_t *insn_handler; |
42 | kprobe_check_cc *insn_check_cc; | 42 | kprobe_check_cc *insn_check_cc; |
43 | kprobe_insn_singlestep_t *insn_singlestep; | ||
43 | }; | 44 | }; |
44 | 45 | ||
45 | struct prev_kprobe { | 46 | struct prev_kprobe { |
diff --git a/arch/arm/kernel/kprobes-arm.c b/arch/arm/kernel/kprobes-arm.c index 0262b29163d1..a1143e86a09a 100644 --- a/arch/arm/kernel/kprobes-arm.c +++ b/arch/arm/kernel/kprobes-arm.c | |||
@@ -1494,6 +1494,12 @@ space_cccc_11xx(kprobe_opcode_t insn, struct arch_specific_insn *asi) | |||
1494 | return INSN_REJECTED; | 1494 | return INSN_REJECTED; |
1495 | } | 1495 | } |
1496 | 1496 | ||
1497 | static void __kprobes arm_singlestep(struct kprobe *p, struct pt_regs *regs) | ||
1498 | { | ||
1499 | regs->ARM_pc += 4; | ||
1500 | p->ainsn.insn_handler(p, regs); | ||
1501 | } | ||
1502 | |||
1497 | /* Return: | 1503 | /* Return: |
1498 | * INSN_REJECTED If instruction is one not allowed to kprobe, | 1504 | * INSN_REJECTED If instruction is one not allowed to kprobe, |
1499 | * INSN_GOOD If instruction is supported and uses instruction slot, | 1505 | * INSN_GOOD If instruction is supported and uses instruction slot, |
@@ -1509,6 +1515,7 @@ space_cccc_11xx(kprobe_opcode_t insn, struct arch_specific_insn *asi) | |||
1509 | enum kprobe_insn __kprobes | 1515 | enum kprobe_insn __kprobes |
1510 | arm_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi) | 1516 | arm_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi) |
1511 | { | 1517 | { |
1518 | asi->insn_singlestep = arm_singlestep; | ||
1512 | asi->insn_check_cc = kprobe_condition_checks[insn>>28]; | 1519 | asi->insn_check_cc = kprobe_condition_checks[insn>>28]; |
1513 | asi->insn[1] = KPROBE_RETURN_INSTRUCTION; | 1520 | asi->insn[1] = KPROBE_RETURN_INSTRUCTION; |
1514 | 1521 | ||
diff --git a/arch/arm/kernel/kprobes-thumb.c b/arch/arm/kernel/kprobes-thumb.c index 24a188b1601a..973c3eb1243a 100644 --- a/arch/arm/kernel/kprobes-thumb.c +++ b/arch/arm/kernel/kprobes-thumb.c | |||
@@ -33,9 +33,24 @@ static unsigned long __kprobes thumb_check_cc(unsigned long cpsr) | |||
33 | return true; | 33 | return true; |
34 | } | 34 | } |
35 | 35 | ||
36 | static void __kprobes thumb16_singlestep(struct kprobe *p, struct pt_regs *regs) | ||
37 | { | ||
38 | regs->ARM_pc += 2; | ||
39 | p->ainsn.insn_handler(p, regs); | ||
40 | regs->ARM_cpsr = it_advance(regs->ARM_cpsr); | ||
41 | } | ||
42 | |||
43 | static void __kprobes thumb32_singlestep(struct kprobe *p, struct pt_regs *regs) | ||
44 | { | ||
45 | regs->ARM_pc += 4; | ||
46 | p->ainsn.insn_handler(p, regs); | ||
47 | regs->ARM_cpsr = it_advance(regs->ARM_cpsr); | ||
48 | } | ||
49 | |||
36 | enum kprobe_insn __kprobes | 50 | enum kprobe_insn __kprobes |
37 | thumb16_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi) | 51 | thumb16_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi) |
38 | { | 52 | { |
53 | asi->insn_singlestep = thumb16_singlestep; | ||
39 | asi->insn_check_cc = thumb_check_cc; | 54 | asi->insn_check_cc = thumb_check_cc; |
40 | return INSN_REJECTED; | 55 | return INSN_REJECTED; |
41 | } | 56 | } |
@@ -43,6 +58,7 @@ thumb16_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi) | |||
43 | enum kprobe_insn __kprobes | 58 | enum kprobe_insn __kprobes |
44 | thumb32_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi) | 59 | thumb32_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi) |
45 | { | 60 | { |
61 | asi->insn_singlestep = thumb32_singlestep; | ||
46 | asi->insn_check_cc = thumb_check_cc; | 62 | asi->insn_check_cc = thumb_check_cc; |
47 | return INSN_REJECTED; | 63 | return INSN_REJECTED; |
48 | } | 64 | } |
diff --git a/arch/arm/kernel/kprobes.c b/arch/arm/kernel/kprobes.c index 0003dfd3b854..77b7c6974802 100644 --- a/arch/arm/kernel/kprobes.c +++ b/arch/arm/kernel/kprobes.c | |||
@@ -227,12 +227,10 @@ singlestep_skip(struct kprobe *p, struct pt_regs *regs) | |||
227 | #endif | 227 | #endif |
228 | } | 228 | } |
229 | 229 | ||
230 | static void __kprobes singlestep(struct kprobe *p, struct pt_regs *regs, | 230 | static inline void __kprobes |
231 | struct kprobe_ctlblk *kcb) | 231 | singlestep(struct kprobe *p, struct pt_regs *regs, struct kprobe_ctlblk *kcb) |
232 | { | 232 | { |
233 | regs->ARM_pc += 4; | 233 | p->ainsn.insn_singlestep(p, regs); |
234 | if (p->ainsn.insn_check_cc(regs->ARM_cpsr)) | ||
235 | p->ainsn.insn_handler(p, regs); | ||
236 | } | 234 | } |
237 | 235 | ||
238 | /* | 236 | /* |