Skip to content

Commit bfc9657

Browse files
WangNan0tixy
authored andcommitted
ARM: optprobes: execute instruction during restoring if possible.
This patch removes software emulation or simulation for most of probed instructions. If the instruction doesn't use PC relative addressing, it will be translated into following instructions in the restore code in code template: ldmia {r0 - r14} // restore all instruction except PC <instruction> // direct execute the probed instruction b next_insn // branch to next instruction. Signed-off-by: Wang Nan <[email protected]> Reviewed-by: Masami Hiramatsu <[email protected]> Signed-off-by: Jon Medhurst <[email protected]>
1 parent 28a1899 commit bfc9657

File tree

3 files changed

+54
-2
lines changed

3 files changed

+54
-2
lines changed

arch/arm/include/asm/kprobes.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@ extern __visible kprobe_opcode_t optprobe_template_call;
5757
extern __visible kprobe_opcode_t optprobe_template_end;
5858
extern __visible kprobe_opcode_t optprobe_template_sub_sp;
5959
extern __visible kprobe_opcode_t optprobe_template_add_sp;
60+
extern __visible kprobe_opcode_t optprobe_template_restore_begin;
61+
extern __visible kprobe_opcode_t optprobe_template_restore_orig_insn;
62+
extern __visible kprobe_opcode_t optprobe_template_restore_end;
6063

6164
#define MAX_OPTIMIZED_LENGTH 4
6265
#define MAX_OPTINSN_SIZE \

arch/arm/include/asm/probes.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ struct arch_probes_insn {
4242
probes_insn_fn_t *insn_fn;
4343
int stack_space;
4444
unsigned long register_usage_flags;
45+
bool kprobe_direct_exec;
4546
};
4647

4748
#endif /* __ASSEMBLY__ */

arch/arm/probes/kprobes/opt-arm.c

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,14 @@
3131

3232
#include "core.h"
3333

34+
/*
35+
* See register_usage_flags. If the probed instruction doesn't use PC,
36+
* we can copy it into template and have it executed directly without
37+
* simulation or emulation.
38+
*/
39+
#define ARM_REG_PC 15
40+
#define can_kprobe_direct_exec(m) (!test_bit(ARM_REG_PC, &(m)))
41+
3442
/*
3543
* NOTE: the first sub and add instruction will be modified according
3644
* to the stack cost of the instruction.
@@ -71,7 +79,15 @@ asm (
7179
" orrne r2, #1\n"
7280
" strne r2, [sp, #60] @ set bit0 of PC for thumb\n"
7381
" msr cpsr_cxsf, r1\n"
82+
".global optprobe_template_restore_begin\n"
83+
"optprobe_template_restore_begin:\n"
7484
" ldmia sp, {r0 - r15}\n"
85+
".global optprobe_template_restore_orig_insn\n"
86+
"optprobe_template_restore_orig_insn:\n"
87+
" nop\n"
88+
".global optprobe_template_restore_end\n"
89+
"optprobe_template_restore_end:\n"
90+
" nop\n"
7591
".global optprobe_template_val\n"
7692
"optprobe_template_val:\n"
7793
"1: .long 0\n"
@@ -91,6 +107,12 @@ asm (
91107
((unsigned long *)&optprobe_template_add_sp - (unsigned long *)&optprobe_template_entry)
92108
#define TMPL_SUB_SP \
93109
((unsigned long *)&optprobe_template_sub_sp - (unsigned long *)&optprobe_template_entry)
110+
#define TMPL_RESTORE_BEGIN \
111+
((unsigned long *)&optprobe_template_restore_begin - (unsigned long *)&optprobe_template_entry)
112+
#define TMPL_RESTORE_ORIGN_INSN \
113+
((unsigned long *)&optprobe_template_restore_orig_insn - (unsigned long *)&optprobe_template_entry)
114+
#define TMPL_RESTORE_END \
115+
((unsigned long *)&optprobe_template_restore_end - (unsigned long *)&optprobe_template_entry)
94116

95117
/*
96118
* ARM can always optimize an instruction when using ARM ISA, except
@@ -160,8 +182,12 @@ optimized_callback(struct optimized_kprobe *op, struct pt_regs *regs)
160182
__this_cpu_write(current_kprobe, NULL);
161183
}
162184

163-
/* In each case, we must singlestep the replaced instruction. */
164-
op->kp.ainsn.insn_singlestep(p->opcode, &p->ainsn, regs);
185+
/*
186+
* We singlestep the replaced instruction only when it can't be
187+
* executed directly during restore.
188+
*/
189+
if (!p->ainsn.kprobe_direct_exec)
190+
op->kp.ainsn.insn_singlestep(p->opcode, &p->ainsn, regs);
165191

166192
local_irq_restore(flags);
167193
}
@@ -243,6 +269,28 @@ int arch_prepare_optimized_kprobe(struct optimized_kprobe *op, struct kprobe *or
243269
val = (unsigned long)optimized_callback;
244270
code[TMPL_CALL_IDX] = val;
245271

272+
/* If possible, copy insn and have it executed during restore */
273+
orig->ainsn.kprobe_direct_exec = false;
274+
if (can_kprobe_direct_exec(orig->ainsn.register_usage_flags)) {
275+
kprobe_opcode_t final_branch = arm_gen_branch(
276+
(unsigned long)(&code[TMPL_RESTORE_END]),
277+
(unsigned long)(op->kp.addr) + 4);
278+
if (final_branch != 0) {
279+
/*
280+
* Replace original 'ldmia sp, {r0 - r15}' with
281+
* 'ldmia {r0 - r14}', restore all registers except pc.
282+
*/
283+
code[TMPL_RESTORE_BEGIN] = __opcode_to_mem_arm(0xe89d7fff);
284+
285+
/* The original probed instruction */
286+
code[TMPL_RESTORE_ORIGN_INSN] = __opcode_to_mem_arm(orig->opcode);
287+
288+
/* Jump back to next instruction */
289+
code[TMPL_RESTORE_END] = __opcode_to_mem_arm(final_branch);
290+
orig->ainsn.kprobe_direct_exec = true;
291+
}
292+
}
293+
246294
flush_icache_range((unsigned long)code,
247295
(unsigned long)(&code[TMPL_END_IDX]));
248296

0 commit comments

Comments
 (0)