// ARM 架构注册kprobe
int __kprobes arch_prepare_kprobe(struct kprobe *p)
{
kprobe_opcode_t insn;
kprobe_opcode_t tmp_insn[MAX_INSN_SIZE];
unsigned long addr = (unsigned long)p->addr;
bool thumb;
kprobe_decode_insn_t *decode_insn;
int is;
// 检测地址是否在异常代码段中
if (in_exception_text(addr))
return -EINVAL;
//地址应该为4的整数倍 ,呵呵我把CONFIG_THUMB2_KERNEL
// 删除掉了,方便阅读,但是不影响原理分析
if (addr & 0x3)
return -EINVAL;
// 取出探测点的汇编指令
insn = *p->addr;
decode_insn = arm_kprobe_decode_insn;
//暂时保存探测指令,发生trap的时候执行
p->opcode = insn;
p->ainsn.insn = tmp_insn;
......
return 0;
}
* INSN_REJECTED If instruction is one not allowed to kprobe,
* INSN_GOOD If instruction is supported and uses instruction slot,
* INSN_GOOD_NO_SLOT If instruction is supported but doesn't use its slot.
// 判断监控的指令是什么类型,不是所有指令都可以监控的
enum kprobe_insn __kprobes
arm_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi)
{
asi->insn_singlestep = arm_singlestep;
asi->insn_check_cc = kprobe_condition_checks[insn>>28];
return kprobe_decode_insn(insn, asi, kprobe_decode_arm_table, false);
}
//单步执行,只是简单PC = PC + 4
static void __kprobes arm_singlestep(struct kprobe *p, struct pt_regs *regs)
{
regs->ARM_pc += 4;
p->ainsn.insn_handler(p, regs);
}
// 把break指令写入到探测的地址中
#define KPROBE_ARM_BREAKPOINT_INSTRUCTION 0x07f001f8
#define KPROBE_THUMB16_BREAKPOINT_INSTRUCTION 0xde18
#define KPROBE_THUMB32_BREAKPOINT_INSTRUCTION 0xf7f0a018
void __kprobes arch_arm_kprobe(struct kprobe *p)
{
unsigned int brkp;
void *addr;
brkp = KPROBE_ARM_BREAKPOINT_INSTRUCTION;
patch_text(addr, brkp);
}
void __kprobes __patch_text(void *addr, unsigned int insn)
{
int size;
insn = __opcode_to_mem_arm(insn);
//往探测地址写入新的指令
*(u32 *)addr = insn;
size = sizeof(u32);
// 把修改从cache真正写到内存中
flush_icache_range((uintptr_t)(addr),
(uintptr_t)(addr) + size);
}