18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Kernel Probes Jump Optimization (Optprobes) 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) IBM Corporation, 2002, 2004 68c2ecf20Sopenharmony_ci * Copyright (C) Hitachi Ltd., 2012 78c2ecf20Sopenharmony_ci * Copyright (C) Huawei Inc., 2014 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/kprobes.h> 118c2ecf20Sopenharmony_ci#include <linux/jump_label.h> 128c2ecf20Sopenharmony_ci#include <asm/kprobes.h> 138c2ecf20Sopenharmony_ci#include <asm/cacheflush.h> 148c2ecf20Sopenharmony_ci/* for arm_gen_branch */ 158c2ecf20Sopenharmony_ci#include <asm/insn.h> 168c2ecf20Sopenharmony_ci/* for patch_text */ 178c2ecf20Sopenharmony_ci#include <asm/patch.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include "core.h" 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci/* 228c2ecf20Sopenharmony_ci * See register_usage_flags. If the probed instruction doesn't use PC, 238c2ecf20Sopenharmony_ci * we can copy it into template and have it executed directly without 248c2ecf20Sopenharmony_ci * simulation or emulation. 258c2ecf20Sopenharmony_ci */ 268c2ecf20Sopenharmony_ci#define ARM_REG_PC 15 278c2ecf20Sopenharmony_ci#define can_kprobe_direct_exec(m) (!test_bit(ARM_REG_PC, &(m))) 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci/* 308c2ecf20Sopenharmony_ci * NOTE: the first sub and add instruction will be modified according 318c2ecf20Sopenharmony_ci * to the stack cost of the instruction. 328c2ecf20Sopenharmony_ci */ 338c2ecf20Sopenharmony_ciasm ( 348c2ecf20Sopenharmony_ci ".global optprobe_template_entry\n" 358c2ecf20Sopenharmony_ci "optprobe_template_entry:\n" 368c2ecf20Sopenharmony_ci ".global optprobe_template_sub_sp\n" 378c2ecf20Sopenharmony_ci "optprobe_template_sub_sp:" 388c2ecf20Sopenharmony_ci " sub sp, sp, #0xff\n" 398c2ecf20Sopenharmony_ci " stmia sp, {r0 - r14} \n" 408c2ecf20Sopenharmony_ci ".global optprobe_template_add_sp\n" 418c2ecf20Sopenharmony_ci "optprobe_template_add_sp:" 428c2ecf20Sopenharmony_ci " add r3, sp, #0xff\n" 438c2ecf20Sopenharmony_ci " str r3, [sp, #52]\n" 448c2ecf20Sopenharmony_ci " mrs r4, cpsr\n" 458c2ecf20Sopenharmony_ci " str r4, [sp, #64]\n" 468c2ecf20Sopenharmony_ci " mov r1, sp\n" 478c2ecf20Sopenharmony_ci " ldr r0, 1f\n" 488c2ecf20Sopenharmony_ci " ldr r2, 2f\n" 498c2ecf20Sopenharmony_ci /* 508c2ecf20Sopenharmony_ci * AEABI requires an 8-bytes alignment stack. If 518c2ecf20Sopenharmony_ci * SP % 8 != 0 (SP % 4 == 0 should be ensured), 528c2ecf20Sopenharmony_ci * alloc more bytes here. 538c2ecf20Sopenharmony_ci */ 548c2ecf20Sopenharmony_ci " and r4, sp, #4\n" 558c2ecf20Sopenharmony_ci " sub sp, sp, r4\n" 568c2ecf20Sopenharmony_ci#if __LINUX_ARM_ARCH__ >= 5 578c2ecf20Sopenharmony_ci " blx r2\n" 588c2ecf20Sopenharmony_ci#else 598c2ecf20Sopenharmony_ci " mov lr, pc\n" 608c2ecf20Sopenharmony_ci " mov pc, r2\n" 618c2ecf20Sopenharmony_ci#endif 628c2ecf20Sopenharmony_ci " add sp, sp, r4\n" 638c2ecf20Sopenharmony_ci " ldr r1, [sp, #64]\n" 648c2ecf20Sopenharmony_ci " tst r1, #"__stringify(PSR_T_BIT)"\n" 658c2ecf20Sopenharmony_ci " ldrne r2, [sp, #60]\n" 668c2ecf20Sopenharmony_ci " orrne r2, #1\n" 678c2ecf20Sopenharmony_ci " strne r2, [sp, #60] @ set bit0 of PC for thumb\n" 688c2ecf20Sopenharmony_ci " msr cpsr_cxsf, r1\n" 698c2ecf20Sopenharmony_ci ".global optprobe_template_restore_begin\n" 708c2ecf20Sopenharmony_ci "optprobe_template_restore_begin:\n" 718c2ecf20Sopenharmony_ci " ldmia sp, {r0 - r15}\n" 728c2ecf20Sopenharmony_ci ".global optprobe_template_restore_orig_insn\n" 738c2ecf20Sopenharmony_ci "optprobe_template_restore_orig_insn:\n" 748c2ecf20Sopenharmony_ci " nop\n" 758c2ecf20Sopenharmony_ci ".global optprobe_template_restore_end\n" 768c2ecf20Sopenharmony_ci "optprobe_template_restore_end:\n" 778c2ecf20Sopenharmony_ci " nop\n" 788c2ecf20Sopenharmony_ci ".global optprobe_template_val\n" 798c2ecf20Sopenharmony_ci "optprobe_template_val:\n" 808c2ecf20Sopenharmony_ci "1: .long 0\n" 818c2ecf20Sopenharmony_ci ".global optprobe_template_call\n" 828c2ecf20Sopenharmony_ci "optprobe_template_call:\n" 838c2ecf20Sopenharmony_ci "2: .long 0\n" 848c2ecf20Sopenharmony_ci ".global optprobe_template_end\n" 858c2ecf20Sopenharmony_ci "optprobe_template_end:\n"); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci#define TMPL_VAL_IDX \ 888c2ecf20Sopenharmony_ci ((unsigned long *)optprobe_template_val - (unsigned long *)optprobe_template_entry) 898c2ecf20Sopenharmony_ci#define TMPL_CALL_IDX \ 908c2ecf20Sopenharmony_ci ((unsigned long *)optprobe_template_call - (unsigned long *)optprobe_template_entry) 918c2ecf20Sopenharmony_ci#define TMPL_END_IDX \ 928c2ecf20Sopenharmony_ci ((unsigned long *)optprobe_template_end - (unsigned long *)optprobe_template_entry) 938c2ecf20Sopenharmony_ci#define TMPL_ADD_SP \ 948c2ecf20Sopenharmony_ci ((unsigned long *)optprobe_template_add_sp - (unsigned long *)optprobe_template_entry) 958c2ecf20Sopenharmony_ci#define TMPL_SUB_SP \ 968c2ecf20Sopenharmony_ci ((unsigned long *)optprobe_template_sub_sp - (unsigned long *)optprobe_template_entry) 978c2ecf20Sopenharmony_ci#define TMPL_RESTORE_BEGIN \ 988c2ecf20Sopenharmony_ci ((unsigned long *)optprobe_template_restore_begin - (unsigned long *)optprobe_template_entry) 998c2ecf20Sopenharmony_ci#define TMPL_RESTORE_ORIGN_INSN \ 1008c2ecf20Sopenharmony_ci ((unsigned long *)optprobe_template_restore_orig_insn - (unsigned long *)optprobe_template_entry) 1018c2ecf20Sopenharmony_ci#define TMPL_RESTORE_END \ 1028c2ecf20Sopenharmony_ci ((unsigned long *)optprobe_template_restore_end - (unsigned long *)optprobe_template_entry) 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci/* 1058c2ecf20Sopenharmony_ci * ARM can always optimize an instruction when using ARM ISA, except 1068c2ecf20Sopenharmony_ci * instructions like 'str r0, [sp, r1]' which store to stack and unable 1078c2ecf20Sopenharmony_ci * to determine stack space consumption statically. 1088c2ecf20Sopenharmony_ci */ 1098c2ecf20Sopenharmony_ciint arch_prepared_optinsn(struct arch_optimized_insn *optinsn) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci return optinsn->insn != NULL; 1128c2ecf20Sopenharmony_ci} 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci/* 1158c2ecf20Sopenharmony_ci * In ARM ISA, kprobe opt always replace one instruction (4 bytes 1168c2ecf20Sopenharmony_ci * aligned and 4 bytes long). It is impossible to encounter another 1178c2ecf20Sopenharmony_ci * kprobe in the address range. So always return 0. 1188c2ecf20Sopenharmony_ci */ 1198c2ecf20Sopenharmony_ciint arch_check_optimized_kprobe(struct optimized_kprobe *op) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci return 0; 1228c2ecf20Sopenharmony_ci} 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci/* Caller must ensure addr & 3 == 0 */ 1258c2ecf20Sopenharmony_cistatic int can_optimize(struct kprobe *kp) 1268c2ecf20Sopenharmony_ci{ 1278c2ecf20Sopenharmony_ci if (kp->ainsn.stack_space < 0) 1288c2ecf20Sopenharmony_ci return 0; 1298c2ecf20Sopenharmony_ci /* 1308c2ecf20Sopenharmony_ci * 255 is the biggest imm can be used in 'sub r0, r0, #<imm>'. 1318c2ecf20Sopenharmony_ci * Number larger than 255 needs special encoding. 1328c2ecf20Sopenharmony_ci */ 1338c2ecf20Sopenharmony_ci if (kp->ainsn.stack_space > 255 - sizeof(struct pt_regs)) 1348c2ecf20Sopenharmony_ci return 0; 1358c2ecf20Sopenharmony_ci return 1; 1368c2ecf20Sopenharmony_ci} 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci/* Free optimized instruction slot */ 1398c2ecf20Sopenharmony_cistatic void 1408c2ecf20Sopenharmony_ci__arch_remove_optimized_kprobe(struct optimized_kprobe *op, int dirty) 1418c2ecf20Sopenharmony_ci{ 1428c2ecf20Sopenharmony_ci if (op->optinsn.insn) { 1438c2ecf20Sopenharmony_ci free_optinsn_slot(op->optinsn.insn, dirty); 1448c2ecf20Sopenharmony_ci op->optinsn.insn = NULL; 1458c2ecf20Sopenharmony_ci } 1468c2ecf20Sopenharmony_ci} 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_cistatic void 1498c2ecf20Sopenharmony_cioptimized_callback(struct optimized_kprobe *op, struct pt_regs *regs) 1508c2ecf20Sopenharmony_ci{ 1518c2ecf20Sopenharmony_ci unsigned long flags; 1528c2ecf20Sopenharmony_ci struct kprobe *p = &op->kp; 1538c2ecf20Sopenharmony_ci struct kprobe_ctlblk *kcb; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci /* Save skipped registers */ 1568c2ecf20Sopenharmony_ci regs->ARM_pc = (unsigned long)op->kp.addr; 1578c2ecf20Sopenharmony_ci regs->ARM_ORIG_r0 = ~0UL; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci local_irq_save(flags); 1608c2ecf20Sopenharmony_ci kcb = get_kprobe_ctlblk(); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci if (kprobe_running()) { 1638c2ecf20Sopenharmony_ci kprobes_inc_nmissed_count(&op->kp); 1648c2ecf20Sopenharmony_ci } else { 1658c2ecf20Sopenharmony_ci __this_cpu_write(current_kprobe, &op->kp); 1668c2ecf20Sopenharmony_ci kcb->kprobe_status = KPROBE_HIT_ACTIVE; 1678c2ecf20Sopenharmony_ci opt_pre_handler(&op->kp, regs); 1688c2ecf20Sopenharmony_ci __this_cpu_write(current_kprobe, NULL); 1698c2ecf20Sopenharmony_ci } 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci /* 1728c2ecf20Sopenharmony_ci * We singlestep the replaced instruction only when it can't be 1738c2ecf20Sopenharmony_ci * executed directly during restore. 1748c2ecf20Sopenharmony_ci */ 1758c2ecf20Sopenharmony_ci if (!p->ainsn.kprobe_direct_exec) 1768c2ecf20Sopenharmony_ci op->kp.ainsn.insn_singlestep(p->opcode, &p->ainsn, regs); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci local_irq_restore(flags); 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ciNOKPROBE_SYMBOL(optimized_callback) 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ciint arch_prepare_optimized_kprobe(struct optimized_kprobe *op, struct kprobe *orig) 1838c2ecf20Sopenharmony_ci{ 1848c2ecf20Sopenharmony_ci kprobe_opcode_t *code; 1858c2ecf20Sopenharmony_ci unsigned long rel_chk; 1868c2ecf20Sopenharmony_ci unsigned long val; 1878c2ecf20Sopenharmony_ci unsigned long stack_protect = sizeof(struct pt_regs); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci if (!can_optimize(orig)) 1908c2ecf20Sopenharmony_ci return -EILSEQ; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci code = get_optinsn_slot(); 1938c2ecf20Sopenharmony_ci if (!code) 1948c2ecf20Sopenharmony_ci return -ENOMEM; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci /* 1978c2ecf20Sopenharmony_ci * Verify if the address gap is in 32MiB range, because this uses 1988c2ecf20Sopenharmony_ci * a relative jump. 1998c2ecf20Sopenharmony_ci * 2008c2ecf20Sopenharmony_ci * kprobe opt use a 'b' instruction to branch to optinsn.insn. 2018c2ecf20Sopenharmony_ci * According to ARM manual, branch instruction is: 2028c2ecf20Sopenharmony_ci * 2038c2ecf20Sopenharmony_ci * 31 28 27 24 23 0 2048c2ecf20Sopenharmony_ci * +------+---+---+---+---+----------------+ 2058c2ecf20Sopenharmony_ci * | cond | 1 | 0 | 1 | 0 | imm24 | 2068c2ecf20Sopenharmony_ci * +------+---+---+---+---+----------------+ 2078c2ecf20Sopenharmony_ci * 2088c2ecf20Sopenharmony_ci * imm24 is a signed 24 bits integer. The real branch offset is computed 2098c2ecf20Sopenharmony_ci * by: imm32 = SignExtend(imm24:'00', 32); 2108c2ecf20Sopenharmony_ci * 2118c2ecf20Sopenharmony_ci * So the maximum forward branch should be: 2128c2ecf20Sopenharmony_ci * (0x007fffff << 2) = 0x01fffffc = 0x1fffffc 2138c2ecf20Sopenharmony_ci * The maximum backword branch should be: 2148c2ecf20Sopenharmony_ci * (0xff800000 << 2) = 0xfe000000 = -0x2000000 2158c2ecf20Sopenharmony_ci * 2168c2ecf20Sopenharmony_ci * We can simply check (rel & 0xfe000003): 2178c2ecf20Sopenharmony_ci * if rel is positive, (rel & 0xfe000000) shoule be 0 2188c2ecf20Sopenharmony_ci * if rel is negitive, (rel & 0xfe000000) should be 0xfe000000 2198c2ecf20Sopenharmony_ci * the last '3' is used for alignment checking. 2208c2ecf20Sopenharmony_ci */ 2218c2ecf20Sopenharmony_ci rel_chk = (unsigned long)((long)code - 2228c2ecf20Sopenharmony_ci (long)orig->addr + 8) & 0xfe000003; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci if ((rel_chk != 0) && (rel_chk != 0xfe000000)) { 2258c2ecf20Sopenharmony_ci /* 2268c2ecf20Sopenharmony_ci * Different from x86, we free code buf directly instead of 2278c2ecf20Sopenharmony_ci * calling __arch_remove_optimized_kprobe() because 2288c2ecf20Sopenharmony_ci * we have not fill any field in op. 2298c2ecf20Sopenharmony_ci */ 2308c2ecf20Sopenharmony_ci free_optinsn_slot(code, 0); 2318c2ecf20Sopenharmony_ci return -ERANGE; 2328c2ecf20Sopenharmony_ci } 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci /* Copy arch-dep-instance from template. */ 2358c2ecf20Sopenharmony_ci memcpy(code, (unsigned long *)optprobe_template_entry, 2368c2ecf20Sopenharmony_ci TMPL_END_IDX * sizeof(kprobe_opcode_t)); 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci /* Adjust buffer according to instruction. */ 2398c2ecf20Sopenharmony_ci BUG_ON(orig->ainsn.stack_space < 0); 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci stack_protect += orig->ainsn.stack_space; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci /* Should have been filtered by can_optimize(). */ 2448c2ecf20Sopenharmony_ci BUG_ON(stack_protect > 255); 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci /* Create a 'sub sp, sp, #<stack_protect>' */ 2478c2ecf20Sopenharmony_ci code[TMPL_SUB_SP] = __opcode_to_mem_arm(0xe24dd000 | stack_protect); 2488c2ecf20Sopenharmony_ci /* Create a 'add r3, sp, #<stack_protect>' */ 2498c2ecf20Sopenharmony_ci code[TMPL_ADD_SP] = __opcode_to_mem_arm(0xe28d3000 | stack_protect); 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci /* Set probe information */ 2528c2ecf20Sopenharmony_ci val = (unsigned long)op; 2538c2ecf20Sopenharmony_ci code[TMPL_VAL_IDX] = val; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci /* Set probe function call */ 2568c2ecf20Sopenharmony_ci val = (unsigned long)optimized_callback; 2578c2ecf20Sopenharmony_ci code[TMPL_CALL_IDX] = val; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci /* If possible, copy insn and have it executed during restore */ 2608c2ecf20Sopenharmony_ci orig->ainsn.kprobe_direct_exec = false; 2618c2ecf20Sopenharmony_ci if (can_kprobe_direct_exec(orig->ainsn.register_usage_flags)) { 2628c2ecf20Sopenharmony_ci kprobe_opcode_t final_branch = arm_gen_branch( 2638c2ecf20Sopenharmony_ci (unsigned long)(&code[TMPL_RESTORE_END]), 2648c2ecf20Sopenharmony_ci (unsigned long)(op->kp.addr) + 4); 2658c2ecf20Sopenharmony_ci if (final_branch != 0) { 2668c2ecf20Sopenharmony_ci /* 2678c2ecf20Sopenharmony_ci * Replace original 'ldmia sp, {r0 - r15}' with 2688c2ecf20Sopenharmony_ci * 'ldmia {r0 - r14}', restore all registers except pc. 2698c2ecf20Sopenharmony_ci */ 2708c2ecf20Sopenharmony_ci code[TMPL_RESTORE_BEGIN] = __opcode_to_mem_arm(0xe89d7fff); 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci /* The original probed instruction */ 2738c2ecf20Sopenharmony_ci code[TMPL_RESTORE_ORIGN_INSN] = __opcode_to_mem_arm(orig->opcode); 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci /* Jump back to next instruction */ 2768c2ecf20Sopenharmony_ci code[TMPL_RESTORE_END] = __opcode_to_mem_arm(final_branch); 2778c2ecf20Sopenharmony_ci orig->ainsn.kprobe_direct_exec = true; 2788c2ecf20Sopenharmony_ci } 2798c2ecf20Sopenharmony_ci } 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci flush_icache_range((unsigned long)code, 2828c2ecf20Sopenharmony_ci (unsigned long)(&code[TMPL_END_IDX])); 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci /* Set op->optinsn.insn means prepared. */ 2858c2ecf20Sopenharmony_ci op->optinsn.insn = code; 2868c2ecf20Sopenharmony_ci return 0; 2878c2ecf20Sopenharmony_ci} 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_civoid __kprobes arch_optimize_kprobes(struct list_head *oplist) 2908c2ecf20Sopenharmony_ci{ 2918c2ecf20Sopenharmony_ci struct optimized_kprobe *op, *tmp; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci list_for_each_entry_safe(op, tmp, oplist, list) { 2948c2ecf20Sopenharmony_ci unsigned long insn; 2958c2ecf20Sopenharmony_ci WARN_ON(kprobe_disabled(&op->kp)); 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci /* 2988c2ecf20Sopenharmony_ci * Backup instructions which will be replaced 2998c2ecf20Sopenharmony_ci * by jump address 3008c2ecf20Sopenharmony_ci */ 3018c2ecf20Sopenharmony_ci memcpy(op->optinsn.copied_insn, op->kp.addr, 3028c2ecf20Sopenharmony_ci RELATIVEJUMP_SIZE); 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci insn = arm_gen_branch((unsigned long)op->kp.addr, 3058c2ecf20Sopenharmony_ci (unsigned long)op->optinsn.insn); 3068c2ecf20Sopenharmony_ci BUG_ON(insn == 0); 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci /* 3098c2ecf20Sopenharmony_ci * Make it a conditional branch if replaced insn 3108c2ecf20Sopenharmony_ci * is consitional 3118c2ecf20Sopenharmony_ci */ 3128c2ecf20Sopenharmony_ci insn = (__mem_to_opcode_arm( 3138c2ecf20Sopenharmony_ci op->optinsn.copied_insn[0]) & 0xf0000000) | 3148c2ecf20Sopenharmony_ci (insn & 0x0fffffff); 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci /* 3178c2ecf20Sopenharmony_ci * Similar to __arch_disarm_kprobe, operations which 3188c2ecf20Sopenharmony_ci * removing breakpoints must be wrapped by stop_machine 3198c2ecf20Sopenharmony_ci * to avoid racing. 3208c2ecf20Sopenharmony_ci */ 3218c2ecf20Sopenharmony_ci kprobes_remove_breakpoint(op->kp.addr, insn); 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci list_del_init(&op->list); 3248c2ecf20Sopenharmony_ci } 3258c2ecf20Sopenharmony_ci} 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_civoid arch_unoptimize_kprobe(struct optimized_kprobe *op) 3288c2ecf20Sopenharmony_ci{ 3298c2ecf20Sopenharmony_ci arch_arm_kprobe(&op->kp); 3308c2ecf20Sopenharmony_ci} 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci/* 3338c2ecf20Sopenharmony_ci * Recover original instructions and breakpoints from relative jumps. 3348c2ecf20Sopenharmony_ci * Caller must call with locking kprobe_mutex. 3358c2ecf20Sopenharmony_ci */ 3368c2ecf20Sopenharmony_civoid arch_unoptimize_kprobes(struct list_head *oplist, 3378c2ecf20Sopenharmony_ci struct list_head *done_list) 3388c2ecf20Sopenharmony_ci{ 3398c2ecf20Sopenharmony_ci struct optimized_kprobe *op, *tmp; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci list_for_each_entry_safe(op, tmp, oplist, list) { 3428c2ecf20Sopenharmony_ci arch_unoptimize_kprobe(op); 3438c2ecf20Sopenharmony_ci list_move(&op->list, done_list); 3448c2ecf20Sopenharmony_ci } 3458c2ecf20Sopenharmony_ci} 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ciint arch_within_optimized_kprobe(struct optimized_kprobe *op, 3488c2ecf20Sopenharmony_ci unsigned long addr) 3498c2ecf20Sopenharmony_ci{ 3508c2ecf20Sopenharmony_ci return ((unsigned long)op->kp.addr <= addr && 3518c2ecf20Sopenharmony_ci (unsigned long)op->kp.addr + RELATIVEJUMP_SIZE > addr); 3528c2ecf20Sopenharmony_ci} 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_civoid arch_remove_optimized_kprobe(struct optimized_kprobe *op) 3558c2ecf20Sopenharmony_ci{ 3568c2ecf20Sopenharmony_ci __arch_remove_optimized_kprobe(op, 1); 3578c2ecf20Sopenharmony_ci} 358