|
|
|
@ -87,8 +87,10 @@ static enum instruction_type bundle_encoding[32][3] = {
|
|
|
|
|
* is IP relative instruction and update the kprobe
|
|
|
|
|
* inst flag accordingly
|
|
|
|
|
*/
|
|
|
|
|
static void update_kprobe_inst_flag(uint template, uint slot, uint major_opcode,
|
|
|
|
|
unsigned long kprobe_inst, struct kprobe *p)
|
|
|
|
|
static void __kprobes update_kprobe_inst_flag(uint template, uint slot,
|
|
|
|
|
uint major_opcode,
|
|
|
|
|
unsigned long kprobe_inst,
|
|
|
|
|
struct kprobe *p)
|
|
|
|
|
{
|
|
|
|
|
p->ainsn.inst_flag = 0;
|
|
|
|
|
p->ainsn.target_br_reg = 0;
|
|
|
|
@ -126,8 +128,10 @@ static void update_kprobe_inst_flag(uint template, uint slot, uint major_opcode
|
|
|
|
|
* Returns 0 if supported
|
|
|
|
|
* Returns -EINVAL if unsupported
|
|
|
|
|
*/
|
|
|
|
|
static int unsupported_inst(uint template, uint slot, uint major_opcode,
|
|
|
|
|
unsigned long kprobe_inst, struct kprobe *p)
|
|
|
|
|
static int __kprobes unsupported_inst(uint template, uint slot,
|
|
|
|
|
uint major_opcode,
|
|
|
|
|
unsigned long kprobe_inst,
|
|
|
|
|
struct kprobe *p)
|
|
|
|
|
{
|
|
|
|
|
unsigned long addr = (unsigned long)p->addr;
|
|
|
|
|
|
|
|
|
@ -168,8 +172,9 @@ static int unsupported_inst(uint template, uint slot, uint major_opcode,
|
|
|
|
|
* on which we are inserting kprobe is cmp instruction
|
|
|
|
|
* with ctype as unc.
|
|
|
|
|
*/
|
|
|
|
|
static uint is_cmp_ctype_unc_inst(uint template, uint slot, uint major_opcode,
|
|
|
|
|
unsigned long kprobe_inst)
|
|
|
|
|
static uint __kprobes is_cmp_ctype_unc_inst(uint template, uint slot,
|
|
|
|
|
uint major_opcode,
|
|
|
|
|
unsigned long kprobe_inst)
|
|
|
|
|
{
|
|
|
|
|
cmp_inst_t cmp_inst;
|
|
|
|
|
uint ctype_unc = 0;
|
|
|
|
@ -201,8 +206,10 @@ unsigned long kprobe_inst)
|
|
|
|
|
* In this function we override the bundle with
|
|
|
|
|
* the break instruction at the given slot.
|
|
|
|
|
*/
|
|
|
|
|
static void prepare_break_inst(uint template, uint slot, uint major_opcode,
|
|
|
|
|
unsigned long kprobe_inst, struct kprobe *p)
|
|
|
|
|
static void __kprobes prepare_break_inst(uint template, uint slot,
|
|
|
|
|
uint major_opcode,
|
|
|
|
|
unsigned long kprobe_inst,
|
|
|
|
|
struct kprobe *p)
|
|
|
|
|
{
|
|
|
|
|
unsigned long break_inst = BREAK_INST;
|
|
|
|
|
bundle_t *bundle = &p->ainsn.insn.bundle;
|
|
|
|
@ -271,7 +278,8 @@ static inline int in_ivt_functions(unsigned long addr)
|
|
|
|
|
&& addr < (unsigned long)__end_ivt_text);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int valid_kprobe_addr(int template, int slot, unsigned long addr)
|
|
|
|
|
static int __kprobes valid_kprobe_addr(int template, int slot,
|
|
|
|
|
unsigned long addr)
|
|
|
|
|
{
|
|
|
|
|
if ((slot > 2) || ((bundle_encoding[template][1] == L) && slot > 1)) {
|
|
|
|
|
printk(KERN_WARNING "Attempting to insert unaligned kprobe "
|
|
|
|
@ -323,7 +331,7 @@ static void kretprobe_trampoline(void)
|
|
|
|
|
* - cleanup by marking the instance as unused
|
|
|
|
|
* - long jump back to the original return address
|
|
|
|
|
*/
|
|
|
|
|
int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
|
|
|
|
|
int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
|
|
|
|
|
{
|
|
|
|
|
struct kretprobe_instance *ri = NULL;
|
|
|
|
|
struct hlist_head *head;
|
|
|
|
@ -381,7 +389,8 @@ int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs)
|
|
|
|
|
void __kprobes arch_prepare_kretprobe(struct kretprobe *rp,
|
|
|
|
|
struct pt_regs *regs)
|
|
|
|
|
{
|
|
|
|
|
struct kretprobe_instance *ri;
|
|
|
|
|
|
|
|
|
@ -399,7 +408,7 @@ void arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int arch_prepare_kprobe(struct kprobe *p)
|
|
|
|
|
int __kprobes arch_prepare_kprobe(struct kprobe *p)
|
|
|
|
|
{
|
|
|
|
|
unsigned long addr = (unsigned long) p->addr;
|
|
|
|
|
unsigned long *kprobe_addr = (unsigned long *)(addr & ~0xFULL);
|
|
|
|
@ -430,7 +439,7 @@ int arch_prepare_kprobe(struct kprobe *p)
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void arch_arm_kprobe(struct kprobe *p)
|
|
|
|
|
void __kprobes arch_arm_kprobe(struct kprobe *p)
|
|
|
|
|
{
|
|
|
|
|
unsigned long addr = (unsigned long)p->addr;
|
|
|
|
|
unsigned long arm_addr = addr & ~0xFULL;
|
|
|
|
@ -439,7 +448,7 @@ void arch_arm_kprobe(struct kprobe *p)
|
|
|
|
|
flush_icache_range(arm_addr, arm_addr + sizeof(bundle_t));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void arch_disarm_kprobe(struct kprobe *p)
|
|
|
|
|
void __kprobes arch_disarm_kprobe(struct kprobe *p)
|
|
|
|
|
{
|
|
|
|
|
unsigned long addr = (unsigned long)p->addr;
|
|
|
|
|
unsigned long arm_addr = addr & ~0xFULL;
|
|
|
|
@ -449,7 +458,7 @@ void arch_disarm_kprobe(struct kprobe *p)
|
|
|
|
|
flush_icache_range(arm_addr, arm_addr + sizeof(bundle_t));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void arch_remove_kprobe(struct kprobe *p)
|
|
|
|
|
void __kprobes arch_remove_kprobe(struct kprobe *p)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -461,7 +470,7 @@ void arch_remove_kprobe(struct kprobe *p)
|
|
|
|
|
* to original stack address, handle the case where we need to fixup the
|
|
|
|
|
* relative IP address and/or fixup branch register.
|
|
|
|
|
*/
|
|
|
|
|
static void resume_execution(struct kprobe *p, struct pt_regs *regs)
|
|
|
|
|
static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs)
|
|
|
|
|
{
|
|
|
|
|
unsigned long bundle_addr = ((unsigned long) (&p->opcode.bundle)) & ~0xFULL;
|
|
|
|
|
unsigned long resume_addr = (unsigned long)p->addr & ~0xFULL;
|
|
|
|
@ -528,7 +537,7 @@ static void resume_execution(struct kprobe *p, struct pt_regs *regs)
|
|
|
|
|
ia64_psr(regs)->ss = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void prepare_ss(struct kprobe *p, struct pt_regs *regs)
|
|
|
|
|
static void __kprobes prepare_ss(struct kprobe *p, struct pt_regs *regs)
|
|
|
|
|
{
|
|
|
|
|
unsigned long bundle_addr = (unsigned long) &p->opcode.bundle;
|
|
|
|
|
unsigned long slot = (unsigned long)p->addr & 0xf;
|
|
|
|
@ -545,7 +554,7 @@ static void prepare_ss(struct kprobe *p, struct pt_regs *regs)
|
|
|
|
|
ia64_psr(regs)->ss = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int pre_kprobes_handler(struct die_args *args)
|
|
|
|
|
static int __kprobes pre_kprobes_handler(struct die_args *args)
|
|
|
|
|
{
|
|
|
|
|
struct kprobe *p;
|
|
|
|
|
int ret = 0;
|
|
|
|
@ -616,7 +625,7 @@ static int pre_kprobes_handler(struct die_args *args)
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int post_kprobes_handler(struct pt_regs *regs)
|
|
|
|
|
static int __kprobes post_kprobes_handler(struct pt_regs *regs)
|
|
|
|
|
{
|
|
|
|
|
if (!kprobe_running())
|
|
|
|
|
return 0;
|
|
|
|
@ -641,7 +650,7 @@ static int post_kprobes_handler(struct pt_regs *regs)
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int kprobes_fault_handler(struct pt_regs *regs, int trapnr)
|
|
|
|
|
static int __kprobes kprobes_fault_handler(struct pt_regs *regs, int trapnr)
|
|
|
|
|
{
|
|
|
|
|
if (!kprobe_running())
|
|
|
|
|
return 0;
|
|
|
|
@ -659,8 +668,8 @@ static int kprobes_fault_handler(struct pt_regs *regs, int trapnr)
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int kprobe_exceptions_notify(struct notifier_block *self, unsigned long val,
|
|
|
|
|
void *data)
|
|
|
|
|
int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
|
|
|
|
|
unsigned long val, void *data)
|
|
|
|
|
{
|
|
|
|
|
struct die_args *args = (struct die_args *)data;
|
|
|
|
|
switch(val) {
|
|
|
|
@ -681,7 +690,7 @@ int kprobe_exceptions_notify(struct notifier_block *self, unsigned long val,
|
|
|
|
|
return NOTIFY_DONE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
|
|
|
|
|
int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
|
|
|
|
|
{
|
|
|
|
|
struct jprobe *jp = container_of(p, struct jprobe, kp);
|
|
|
|
|
unsigned long addr = ((struct fnptr *)(jp->entry))->ip;
|
|
|
|
@ -703,7 +712,7 @@ int setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
|
|
|
|
|
int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
|
|
|
|
|
{
|
|
|
|
|
*regs = jprobe_saved_regs;
|
|
|
|
|
return 1;
|
|
|
|
|