From 41379ba604d15dd86831c986b49d54a14c340ca4 Mon Sep 17 00:00:00 2001 From: Vyacheslav Cherkashin Date: Wed, 8 Aug 2012 16:26:54 +0400 Subject: [PATCH] mini refactoring kprobes --- driver/probes_manager.c | 11 +- kprobe/arch/asm-arm/dbi_kprobes.c | 261 +++++++++++++++++-------------------- kprobe/arch/asm-mips/dbi_kprobes.c | 2 +- kprobe/dbi_kprobes.c | 213 ++++++++++-------------------- kprobe/dbi_kprobes.h | 21 ++- kprobe/dbi_uprobes.c | 2 +- 6 files changed, 205 insertions(+), 305 deletions(-) diff --git a/driver/probes_manager.c b/driver/probes_manager.c index c4acba3..2809ab8 100644 --- a/driver/probes_manager.c +++ b/driver/probes_manager.c @@ -102,7 +102,7 @@ register_kernel_jprobe (kernel_probe_t * probe) { return 0; // probe is already registered } - result = dbi_register_jprobe (&probe->jprobe, 0); + result = dbi_register_jprobe (&probe->jprobe); if (result) { EPRINTF ("register_kernel_jprobe(0x%lx) failure %d", probe->addr, result); @@ -120,7 +120,7 @@ unregister_kernel_jprobe (kernel_probe_t * probe) ((probe == exec_probe) && (us_proc_probes & US_PROC_EXEC_INSTLD))) { return 0; // probe is necessary for user space instrumentation } - dbi_unregister_jprobe (&probe->jprobe, 0); + dbi_unregister_jprobe (&probe->jprobe); return 0; } @@ -135,7 +135,7 @@ register_kernel_retprobe (kernel_probe_t * probe) return 0; // probe is already registered } - result = dbi_register_kretprobe (&probe->retprobe, 0); + result = dbi_register_kretprobe (&probe->retprobe); if (result) { EPRINTF ("register_kernel_retprobe(0x%lx) failure %d", probe->addr, result); @@ -153,7 +153,7 @@ unregister_kernel_retprobe (kernel_probe_t * probe) ((probe == exec_probe) && (us_proc_probes & US_PROC_EXEC_INSTLD))) { return 0; // probe is necessary for user space instrumentation } - dbi_unregister_kretprobe (&probe->retprobe, 0); + dbi_unregister_kretprobe (&probe->retprobe); return 0; } @@ -363,14 +363,11 @@ remove_probe (unsigned long addr) DEFINE_PER_CPU (kernel_probe_t *, gpKernProbe) = NULL; EXPORT_PER_CPU_SYMBOL_GPL(gpKernProbe); -DEFINE_PER_CPU(struct pt_regs *, gpKernRegs) = NULL; -EXPORT_PER_CPU_SYMBOL_GPL(gpKernRegs); unsigned long def_jprobe_event_pre_handler (kernel_probe_t * probe, struct pt_regs *regs) { __get_cpu_var (gpKernProbe) = probe; - __get_cpu_var (gpKernRegs) = regs; return 0; } diff --git a/kprobe/arch/asm-arm/dbi_kprobes.c b/kprobe/arch/asm-arm/dbi_kprobes.c index 033809f..0ca494f 100644 --- a/kprobe/arch/asm-arm/dbi_kprobes.c +++ b/kprobe/arch/asm-arm/dbi_kprobes.c @@ -22,12 +22,11 @@ * 2008-2009 Alexey Gerenkov User-Space * Probes initial implementation; Support x86. * 2010 Ekaterina Gorelkina : redesign module for separating core and arch parts - * * 2010-2011 Alexander Shirshikov : initial implementation for Thumb - * 2012 Stanislav Andreev : added time debug profiling support; BUG() message fix - * 2012 Stanislav Andreev : redesign of kprobe functionality - - * kprobe_handler() now called via undefined instruction hooks - * 2012 Stanislav Andreev : hash tables search implemented for uprobes + * 2012 Stanislav Andreev : added time debug profiling support; BUG() message fix + * 2012 Stanislav Andreev : redesign of kprobe functionality - + * kprobe_handler() now called via undefined instruction hooks + * 2012 Stanislav Andreev : hash tables search implemented for uprobes */ #include @@ -135,8 +134,6 @@ int prep_pc_dep_insn_execbuf (kprobe_opcode_t * insns, kprobe_opcode_t insn, int { for (i = 0; i < 13; i++) { - // DBPRINTF("prep_pc_dep_insn_execbuf: check R%d/%d, changing regs %x in %x", - // i, ARM_INSN_REG_RN(insn), uregs, insn); if ((uregs & 0x1) && (ARM_INSN_REG_RN (insn) == i)) continue; if ((uregs & 0x2) && (ARM_INSN_REG_RD (insn) == i)) @@ -159,7 +156,7 @@ int prep_pc_dep_insn_execbuf (kprobe_opcode_t * insns, kprobe_opcode_t insn, int ARM_INSN_REG_SET_RD (insns[0], i); // set register to load address to ARM_INSN_REG_SET_RD (insns[1], i); - // set instruction to execute and patch it + // set instruction to execute and patch it if (uregs & 0x10) { ARM_INSN_REG_CLEAR_MR (insn, 15); @@ -198,7 +195,7 @@ int prep_pc_dep_insn_execbuf_thumb (kprobe_opcode_t * insns, kprobe_opcode_t ins { if (((((unsigned char) insn) & 0xff) >> 3) == 15) reg = (insn & 0xffff) & uregs; - else + else return 0; }else{ if (THUMB2_INSN_MATCH (ADR, insn)) @@ -513,124 +510,110 @@ int arch_prepare_kretprobe (struct kretprobe *p) int arch_prepare_kprobe (struct kprobe *p) { kprobe_opcode_t insns[KPROBES_TRAMP_LEN]; - int uregs, pc_dep; - int ret = 0; - - if (!ret) - { - kprobe_opcode_t insn[MAX_INSN_SIZE]; - struct arch_specific_insn ainsn; - /* insn: must be on special executable page on i386. */ - p->ainsn.insn = get_insn_slot (NULL, 0); - if (!p->ainsn.insn) - return -ENOMEM; - memcpy (insn, p->addr, MAX_INSN_SIZE * sizeof (kprobe_opcode_t)); - ainsn.insn_arm = ainsn.insn = insn; - ret = arch_check_insn_arm (&ainsn); - if (!ret) - { - p->opcode = *p->addr; - - p->ainsn.boostable = 1; - uregs = pc_dep = 0; - // Rn, Rm ,Rd - if (ARM_INSN_MATCH (DPIS, insn[0]) || ARM_INSN_MATCH (LRO, insn[0]) || - ARM_INSN_MATCH (SRO, insn[0])) - { - - uregs = 0xb; - if ((ARM_INSN_REG_RN (insn[0]) == 15) || (ARM_INSN_REG_RM (insn[0]) == 15) || - (ARM_INSN_MATCH (SRO, insn[0]) && (ARM_INSN_REG_RD (insn[0]) == 15))) - { - - DBPRINTF ("Unboostable insn %lx, DPIS/LRO/SRO\n", insn[0]); - pc_dep = 1; - } - } - // Rn ,Rd - else if (ARM_INSN_MATCH (DPI, insn[0]) || ARM_INSN_MATCH (LIO, insn[0]) || - ARM_INSN_MATCH (SIO, insn[0])) - { - - uregs = 0x3; - if ((ARM_INSN_REG_RN (insn[0]) == 15) || (ARM_INSN_MATCH (SIO, insn[0]) && - (ARM_INSN_REG_RD (insn[0]) == 15))) - { - - pc_dep = 1; - DBPRINTF ("Unboostable insn %lx/%p/%d, DPI/LIO/SIO\n", insn[0], p, p->ainsn.boostable); - } - } - // Rn, Rm, Rs - else if (ARM_INSN_MATCH (DPRS, insn[0])) - { - - uregs = 0xd; - if ((ARM_INSN_REG_RN (insn[0]) == 15) || (ARM_INSN_REG_RM (insn[0]) == 15) || - (ARM_INSN_REG_RS (insn[0]) == 15)) - { - - pc_dep = 1; - DBPRINTF ("Unboostable insn %lx, DPRS\n", insn[0]); - } - } - // register list - else if (ARM_INSN_MATCH (SM, insn[0])) - { - - uregs = 0x10; - if (ARM_INSN_REG_MR (insn[0], 15)) - { - - DBPRINTF ("Unboostable insn %lx, SM\n", insn[0]); - pc_dep = 1; - } - } - // check instructions that can write result to SP andu uses PC - if (pc_dep && (ARM_INSN_REG_RD (ainsn.insn[0]) == 13)) - { - static int count; - count++; - //printk ("insn writes result to SP and uses PC: %lx/%d\n", ainsn.insn[0], count); - free_insn_slot (&kprobe_insn_pages, NULL, p->ainsn.insn, 0); - ret = -EFAULT; - } - else { - if (uregs && pc_dep) - { - memcpy (insns, pc_dep_insn_execbuf, sizeof (insns)); - if (prep_pc_dep_insn_execbuf (insns, insn[0], uregs) != 0) - { - DBPRINTF ("failed to prepare exec buffer for insn %lx!", insn[0]); - free_insn_slot (&kprobe_insn_pages, NULL, p->ainsn.insn, 0); - return -EINVAL; - } - //insns[KPROBES_TRAMP_SS_BREAK_IDX] = BREAKPOINT_INSTRUCTION; - insns[6] = (kprobe_opcode_t) (p->addr + 2); - } - else - { - memcpy (insns, gen_insn_execbuf, sizeof (insns)); - insns[KPROBES_TRAMP_INSN_IDX] = insn[0]; - } - //insns[KPROBES_TRAMP_RET_BREAK_IDX] = UNDEF_INSTRUCTION; - insns[7] = (kprobe_opcode_t) (p->addr + 1); - DBPRINTF ("arch_prepare_kprobe: insn %lx", insn[0]); - DBPRINTF ("arch_prepare_kprobe: to %p - %lx %lx %lx %lx %lx %lx %lx %lx %lx", - p->ainsn.insn, insns[0], insns[1], insns[2], insns[3], insns[4], - insns[5], insns[6], insns[7], insns[8]); - memcpy (p->ainsn.insn, insns, sizeof(insns)); - flush_icache_range(p->ainsn.insn, p->ainsn.insn + sizeof(insns)); + int uregs, pc_dep, ret = 0; + kprobe_opcode_t insn[MAX_INSN_SIZE]; + struct arch_specific_insn ainsn; + + /* insn: must be on special executable page on i386. */ + p->ainsn.insn = get_insn_slot (NULL, 0); + if (!p->ainsn.insn) + return -ENOMEM; + + memcpy (insn, p->addr, MAX_INSN_SIZE * sizeof (kprobe_opcode_t)); + ainsn.insn_arm = ainsn.insn = insn; + ret = arch_check_insn_arm (&ainsn); + if (!ret) + { + p->opcode = *p->addr; + p->ainsn.boostable = 1; + uregs = pc_dep = 0; + + // Rn, Rm ,Rd + if(ARM_INSN_MATCH (DPIS, insn[0]) || ARM_INSN_MATCH (LRO, insn[0]) || + ARM_INSN_MATCH (SRO, insn[0])) + { + uregs = 0xb; + if( (ARM_INSN_REG_RN (insn[0]) == 15) || (ARM_INSN_REG_RM (insn[0]) == 15) || + (ARM_INSN_MATCH (SRO, insn[0]) && (ARM_INSN_REG_RD (insn[0]) == 15)) ) + { + DBPRINTF ("Unboostable insn %lx, DPIS/LRO/SRO\n", insn[0]); + pc_dep = 1; + } + } + // Rn ,Rd + else if(ARM_INSN_MATCH (DPI, insn[0]) || ARM_INSN_MATCH (LIO, insn[0]) || + ARM_INSN_MATCH (SIO, insn[0])) + { + uregs = 0x3; + if ((ARM_INSN_REG_RN (insn[0]) == 15) || (ARM_INSN_MATCH (SIO, insn[0]) && + (ARM_INSN_REG_RD (insn[0]) == 15))) + { + pc_dep = 1; + DBPRINTF ("Unboostable insn %lx/%p/%d, DPI/LIO/SIO\n", insn[0], p, p->ainsn.boostable); + } + } + // Rn, Rm, Rs + else if(ARM_INSN_MATCH (DPRS, insn[0])) + { + uregs = 0xd; + if ((ARM_INSN_REG_RN (insn[0]) == 15) || (ARM_INSN_REG_RM (insn[0]) == 15) || + (ARM_INSN_REG_RS (insn[0]) == 15)) + { + pc_dep = 1; + DBPRINTF ("Unboostable insn %lx, DPRS\n", insn[0]); + } + } + // register list + else if(ARM_INSN_MATCH (SM, insn[0])) + { + uregs = 0x10; + if (ARM_INSN_REG_MR (insn[0], 15)) + { + DBPRINTF ("Unboostable insn %lx, SM\n", insn[0]); + pc_dep = 1; + } + } + // check instructions that can write result to SP andu uses PC + if (pc_dep && (ARM_INSN_REG_RD (ainsn.insn[0]) == 13)) + { + free_insn_slot (&kprobe_insn_pages, NULL, p->ainsn.insn, 0); + ret = -EFAULT; + } + else + { + if (uregs && pc_dep) + { + memcpy (insns, pc_dep_insn_execbuf, sizeof (insns)); + if (prep_pc_dep_insn_execbuf (insns, insn[0], uregs) != 0) + { + DBPRINTF ("failed to prepare exec buffer for insn %lx!", insn[0]); + free_insn_slot (&kprobe_insn_pages, NULL, p->ainsn.insn, 0); + return -EINVAL; + } + insns[6] = (kprobe_opcode_t) (p->addr + 2); + } + else + { + memcpy (insns, gen_insn_execbuf, sizeof (insns)); + insns[KPROBES_TRAMP_INSN_IDX] = insn[0]; + } + insns[7] = (kprobe_opcode_t) (p->addr + 1); + DBPRINTF ("arch_prepare_kprobe: insn %lx", insn[0]); + DBPRINTF ("arch_prepare_kprobe: to %p - %lx %lx %lx %lx %lx %lx %lx %lx %lx", + p->ainsn.insn, insns[0], insns[1], insns[2], insns[3], insns[4], + insns[5], insns[6], insns[7], insns[8]); + memcpy (p->ainsn.insn, insns, sizeof(insns)); + flush_icache_range(p->ainsn.insn, p->ainsn.insn + sizeof(insns)); #ifdef BOARD_tegra - flush_cache_all(); + flush_cache_all(); #endif - } - } - else - { - free_insn_slot (&kprobe_insn_pages, NULL, p->ainsn.insn, 0); - } - } + } + } + else + { + free_insn_slot (&kprobe_insn_pages, NULL, p->ainsn.insn, 0); + } + return ret; } @@ -823,7 +806,7 @@ int arch_copy_trampoline_arm_uprobe (struct kprobe *p, struct task_struct *task, memcpy (insns, pc_dep_insn_execbuf, sizeof (insns)); if (prep_pc_dep_insn_execbuf (insns, insn[0], uregs) != 0) { - printk("Error in %s at %d: failed to prepare exec buffer for insn %lx!", + printk("Error in %s at %d: failed to prepare exec buffer for insn %lx!", insn[0], __FILE__, __LINE__); p->safe_arm = -1; // TODO: move free to later phase @@ -906,10 +889,10 @@ int arch_copy_trampoline_thumb_uprobe (struct kprobe *p, struct task_struct *tas THUMB2_INSN_MATCH (LDRHW, insn[0]) || THUMB2_INSN_MATCH (LDRHW1, insn[0]) || THUMB2_INSN_MATCH (LDRWL, insn[0])) && THUMB2_INSN_REG_RN(insn[0]) == 15) || THUMB2_INSN_MATCH (LDREX, insn[0]) || - ((THUMB2_INSN_MATCH (STRW, insn[0]) || THUMB2_INSN_MATCH (STRBW, insn[0]) || - THUMB2_INSN_MATCH (STRHW, insn[0]) || THUMB2_INSN_MATCH (STRHW1, insn[0])) && + ((THUMB2_INSN_MATCH (STRW, insn[0]) || THUMB2_INSN_MATCH (STRBW, insn[0]) || + THUMB2_INSN_MATCH (STRHW, insn[0]) || THUMB2_INSN_MATCH (STRHW1, insn[0])) && (THUMB2_INSN_REG_RN(insn[0]) == 15 || THUMB2_INSN_REG_RT(insn[0]) == 15)) || - ((THUMB2_INSN_MATCH (STRT, insn[0]) || THUMB2_INSN_MATCH (STRHT, insn[0])) && + ((THUMB2_INSN_MATCH (STRT, insn[0]) || THUMB2_INSN_MATCH (STRHT, insn[0])) && (THUMB2_INSN_REG_RN(insn[0]) == 15 || THUMB2_INSN_REG_RT(insn[0]) == 15)) ) { uregs = 0xf000; // Rt 12-15 @@ -971,7 +954,7 @@ int arch_copy_trampoline_thumb_uprobe (struct kprobe *p, struct task_struct *tas memcpy (insns, pc_dep_insn_execbuf_thumb, 18 * 2); if (prep_pc_dep_insn_execbuf_thumb (insns, insn[0], uregs) != 0) { - printk("Error in %s at %d: failed to prepare exec buffer for insn %lx!", + printk("Error in %s at %d: failed to prepare exec buffer for insn %lx!", insn[0], __FILE__, __LINE__); p->safe_thumb = -1; //free_insn_slot (&uprobe_insn_pages, task, p->ainsn.insn_thumb, 0); @@ -1137,7 +1120,7 @@ int kprobe_handler (struct pt_regs *regs) #ifdef OVERHEAD_DEBUG do_gettimeofday(&swap_tv2); swap_sum_hit++; - swap_sum_time += ((swap_tv2.tv_sec - swap_tv1.tv_sec) * USEC_IN_SEC_NUM + + swap_sum_time += ((swap_tv2.tv_sec - swap_tv1.tv_sec) * USEC_IN_SEC_NUM + (swap_tv2.tv_usec - swap_tv1.tv_usec)); #endif #ifdef SUPRESS_BUG_MESSAGES @@ -1148,7 +1131,7 @@ int kprobe_handler (struct pt_regs *regs) } else { - if(pid) { //we can reenter probe upon uretprobe exception + if(pid) { //we can reenter probe upon uretprobe exception DBPRINTF ("check for UNDEF_INSTRUCTION %p\n", addr); // UNDEF_INSTRUCTION from user space @@ -1171,7 +1154,7 @@ int kprobe_handler (struct pt_regs *regs) /*if (p->break_handler && p->break_handler(p, regs)) { DBPRINTF("kprobe_running !!! goto ss"); goto ss_probe; - } */ + } */ DBPRINTF ("unknown uprobe at %p cur at %p/%p\n", addr, p->addr, p->ainsn.insn); if(pid) ssaddr = p->ainsn.insn + UPROBES_TRAMP_SS_BREAK_IDX; @@ -1265,7 +1248,7 @@ int kprobe_handler (struct pt_regs *regs) #ifdef OVERHEAD_DEBUG do_gettimeofday(&swap_tv2); swap_sum_hit++; - swap_sum_time += ((swap_tv2.tv_sec - swap_tv1.tv_sec) * USEC_IN_SEC_NUM + + swap_sum_time += ((swap_tv2.tv_sec - swap_tv1.tv_sec) * USEC_IN_SEC_NUM + (swap_tv2.tv_usec - swap_tv1.tv_usec)); #endif #ifdef SUPRESS_BUG_MESSAGES @@ -1280,7 +1263,7 @@ no_kprobe: #ifdef OVERHEAD_DEBUG do_gettimeofday(&swap_tv2); swap_sum_hit++; - swap_sum_time += ((swap_tv2.tv_sec - swap_tv1.tv_sec) * USEC_IN_SEC_NUM + + swap_sum_time += ((swap_tv2.tv_sec - swap_tv1.tv_sec) * USEC_IN_SEC_NUM + (swap_tv2.tv_usec - swap_tv1.tv_usec)); #endif #ifdef SUPRESS_BUG_MESSAGES @@ -1293,7 +1276,7 @@ no_kprobe_live: #ifdef OVERHEAD_DEBUG do_gettimeofday(&swap_tv2); swap_sum_hit++; - swap_sum_time += ((swap_tv2.tv_sec - swap_tv1.tv_sec) * USEC_IN_SEC_NUM + + swap_sum_time += ((swap_tv2.tv_sec - swap_tv1.tv_sec) * USEC_IN_SEC_NUM + (swap_tv2.tv_usec - swap_tv1.tv_usec)); #endif #ifdef SUPRESS_BUG_MESSAGES @@ -1371,7 +1354,7 @@ int setjmp_pre_handler (struct kprobe *p, struct pt_regs *regs) //call handler for all kernel probes and user space ones which belong to current tgid if (!p->tgid || (p->tgid == current->tgid)) - { + { if(!p->tgid && ((unsigned int)p->addr == sched_addr) && sched_rp){ struct task_struct *p, *g; rcu_read_lock(); @@ -1510,7 +1493,7 @@ int trampoline_probe_handler (struct kprobe *p, struct pt_regs *regs) /* * It is possible to have multiple instances associated with a given * task either because an multiple functions in the call path - * have a return probe installed on them, and/or more then one + * have a return probe installed on them, and/or more then one * return probe was registered for a target function. * * We can handle this because: @@ -1751,7 +1734,7 @@ int __init arch_init_kprobes (void) do_kpro(&undef_ho_k); do_kpro(&undef_ho_u); do_kpro(&undef_ho_u_t); - if ((ret = dbi_register_kprobe (&trampoline_p, 0)) != 0) { + if ((ret = dbi_register_kprobe (&trampoline_p)) != 0) { //dbi_unregister_jprobe(&do_exit_p, 0); return ret; } diff --git a/kprobe/arch/asm-mips/dbi_kprobes.c b/kprobe/arch/asm-mips/dbi_kprobes.c index 6358741..b537746 100644 --- a/kprobe/arch/asm-mips/dbi_kprobes.c +++ b/kprobe/arch/asm-mips/dbi_kprobes.c @@ -841,7 +841,7 @@ int __init arch_init_kprobes (void) // Insert new code memcpy ((void *) do_bp_handler, arr_traps_template, code_size); flush_icache_range (do_bp_handler, do_bp_handler + code_size); - if((ret = dbi_register_kprobe (&trampoline_p, 0)) != 0){ + if((ret = dbi_register_kprobe (&trampoline_p)) != 0){ //dbi_unregister_jprobe(&do_exit_p, 0); return ret; } diff --git a/kprobe/dbi_kprobes.c b/kprobe/dbi_kprobes.c index 669c548..8eeae24 100644 --- a/kprobe/dbi_kprobes.c +++ b/kprobe/dbi_kprobes.c @@ -44,9 +44,8 @@ * 2006-2007 Ekaterina Gorelkina : initial implementation for ARM and MIPS * 2008-2009 Alexey Gerenkov User-Space * Probes initial implementation; Support x86/ARM/MIPS for both user and kernel spaces. - * 2010 Ekaterina Gorelkina : redesign module for separating core and arch parts + * 2010 Ekaterina Gorelkina : redesign module for separating core and arch parts * - */ #include "dbi_kprobes.h" @@ -73,7 +72,6 @@ extern unsigned int *sched_addr; extern unsigned int *fork_addr; - extern struct hlist_head kprobe_insn_pages; extern unsigned long (*kallsyms_search) (const char *name); @@ -99,13 +97,13 @@ void kretprobe_assert (struct kretprobe_instance *ri, unsigned long orig_ret_add /* We have preemption disabled.. so it is safe to use __ versions */ -static inline +static inline void set_kprobe_instance (struct kprobe *kp) { __get_cpu_var (kprobe_instance) = kp; } -static inline +static inline void reset_kprobe_instance (void) { __get_cpu_var (kprobe_instance) = NULL; @@ -174,7 +172,7 @@ struct kprobe *get_kprobe (void *addr, int tgid, struct task_struct *ctask) * Aggregate handlers for multiple kprobes support - these handlers * take care of invoking the individual kprobe handlers on p->list */ -static +static int aggr_pre_handler (struct kprobe *p, struct pt_regs *regs) { struct kprobe *kp; @@ -194,7 +192,7 @@ int aggr_pre_handler (struct kprobe *p, struct pt_regs *regs) return 0; } -static +static void aggr_post_handler (struct kprobe *p, struct pt_regs *regs, unsigned long flags) { struct kprobe *kp; @@ -208,10 +206,9 @@ void aggr_post_handler (struct kprobe *p, struct pt_regs *regs, unsigned long fl reset_kprobe_instance (); } } - return; } -static +static int aggr_fault_handler (struct kprobe *p, struct pt_regs *regs, int trapnr) { struct kprobe *cur = __get_cpu_var (kprobe_instance); @@ -228,7 +225,7 @@ int aggr_fault_handler (struct kprobe *p, struct pt_regs *regs, int trapnr) return 0; } -static +static int aggr_break_handler (struct kprobe *p, struct pt_regs *regs) { struct kprobe *cur = __get_cpu_var (kprobe_instance); @@ -359,7 +356,7 @@ void free_rp_inst (struct kretprobe *rp) /* * Keep all fields in the kprobe consistent */ -static inline +static inline void copy_kprobe (struct kprobe *old_p, struct kprobe *p) { memcpy (&p->opcode, &old_p->opcode, sizeof (kprobe_opcode_t)); @@ -419,7 +416,7 @@ inline void dbi_hlist_replace_rcu (struct hlist_node *old, struct hlist_node *ne * Fill in the required fields of the "manager kprobe". Replace the * earlier kprobe in the hlist with the manager kprobe */ -static inline +static inline void add_aggr_kprobe (struct kprobe *ap, struct kprobe *p) { copy_kprobe (p, ap); @@ -477,132 +474,80 @@ int register_aggr_kprobe (struct kprobe *old_p, struct kprobe *p) return ret; } -static -int __dbi_register_kprobe (struct kprobe *p, unsigned long called_from, int atomic) -{ - struct kprobe *old_p; - // struct module *probed_mod; - int ret = 0; - /* - * If we have a symbol_name argument look it up, - * and add it to the address. That way the addr - * field can either be global or relative to a symbol. - */ - if (p->symbol_name) - { - if (p->addr) - return -EINVAL; - p->addr = (unsigned int) kallsyms_search (p->symbol_name); - } - - if (!p->addr) - return -EINVAL; - DBPRINTF ("p->addr = 0x%p\n", p->addr); - p->addr = (kprobe_opcode_t *) (((char *) p->addr) + p->offset); - DBPRINTF ("p->addr = 0x%p p = 0x%p\n", p->addr, p); - - /* if ((!kernel_text_address((unsigned long) p->addr)) || - in_kprobes_functions((unsigned long) p->addr)) - return -EINVAL;*/ +int dbi_register_kprobe (struct kprobe *p) +{ + struct kprobe *old_p; + int ret = 0; + /* + * If we have a symbol_name argument look it up, + * and add it to the address. That way the addr + * field can either be global or relative to a symbol. + */ + if (p->symbol_name) + { + if (p->addr) + return -EINVAL; + p->addr = (unsigned int) kallsyms_search (p->symbol_name); + } + + if (!p->addr) + return -EINVAL; + DBPRINTF ("p->addr = 0x%p\n", p->addr); + p->addr = (kprobe_opcode_t *) (((char *) p->addr) + p->offset); + DBPRINTF ("p->addr = 0x%p p = 0x%p\n", p->addr, p); #ifdef KPROBES_PROFILE - p->start_tm.tv_sec = p->start_tm.tv_usec = 0; - p->hnd_tm_sum.tv_sec = p->hnd_tm_sum.tv_usec = 0; - p->count = 0; + p->start_tm.tv_sec = p->start_tm.tv_usec = 0; + p->hnd_tm_sum.tv_sec = p->hnd_tm_sum.tv_usec = 0; + p->count = 0; #endif - p->mod_refcounted = 0; - //p->proc_prio = 0; - //p->proc_sched = 0; - //p->spid = -1; - //p->irq = 0; - //p->task_flags = 0; - /* - // Check are we probing a module - if ((probed_mod = module_text_address((unsigned long) p->addr))) { - struct module *calling_mod = module_text_address(called_from); - // We must allow modules to probe themself and - // in this case avoid incrementing the module refcount, - // so as to allow unloading of self probing modules. - // - if (calling_mod && (calling_mod != probed_mod)) { - if (unlikely(!try_module_get(probed_mod))) - return -EINVAL; - p->mod_refcounted = 1; - } else - probed_mod = NULL; - } - */ - p->nmissed = 0; - // mutex_lock(&kprobe_mutex); - old_p = get_kprobe (p->addr, 0, NULL); - if (old_p) - { - ret = register_aggr_kprobe (old_p, p); - if (!ret) - atomic_inc (&kprobe_count); - goto out; - } - - if ((ret = arch_prepare_kprobe (p)) != 0) - goto out; - - DBPRINTF ("before out ret = 0x%x\n", ret); - - INIT_HLIST_NODE (&p->hlist); - hlist_add_head_rcu (&p->hlist, &kprobe_table[hash_ptr (p->addr, KPROBE_HASH_BITS)]); - - /* if (atomic_add_return(1, &kprobe_count) == \ - (ARCH_INACTIVE_KPROBE_COUNT + 1)) - register_page_fault_notifier(&kprobe_page_fault_nb);*/ - - arch_arm_kprobe (p); + p->mod_refcounted = 0; + p->nmissed = 0; + + old_p = get_kprobe (p->addr, 0, NULL); + if (old_p) + { + ret = register_aggr_kprobe (old_p, p); + if (!ret) + atomic_inc (&kprobe_count); + goto out; + } + + if ((ret = arch_prepare_kprobe (p)) != 0) + goto out; + + DBPRINTF ("before out ret = 0x%x\n", ret); + INIT_HLIST_NODE (&p->hlist); + hlist_add_head_rcu (&p->hlist, &kprobe_table[hash_ptr (p->addr, KPROBE_HASH_BITS)]); + arch_arm_kprobe (p); out: - // mutex_unlock(&kprobe_mutex); - /* - if (ret && probed_mod) - module_put(probed_mod); - */ - DBPRINTF ("out ret = 0x%x\n", ret); - - return ret; + DBPRINTF ("out ret = 0x%x\n", ret); + return ret; } - -int dbi_register_kprobe (struct kprobe *p, int atomic) +void dbi_unregister_kprobe (struct kprobe *p, struct task_struct *task) { - return __dbi_register_kprobe (p, (unsigned long) __builtin_return_address (0), atomic); -} - -void dbi_unregister_kprobe (struct kprobe *p, struct task_struct *task, int atomic) -{ - // struct module *mod; struct kprobe *old_p, *list_p; - int cleanup_p, pid = 0; - - // mutex_lock(&kprobe_mutex); - - pid = p->tgid; + int cleanup_p, pid = p->tgid; old_p = get_kprobe (p->addr, pid, NULL); DBPRINTF ("dbi_unregister_kprobe p=%p old_p=%p", p, old_p); if (unlikely (!old_p)) - { - // mutex_unlock(&kprobe_mutex); return; - } + if (p != old_p) { - list_for_each_entry_rcu (list_p, &old_p->list, list) + list_for_each_entry_rcu (list_p, &old_p->list, list) if (list_p == p) /* kprobe p is a valid probe */ goto valid_p; - // mutex_unlock(&kprobe_mutex); return; } + valid_p: DBPRINTF ("dbi_unregister_kprobe valid_p"); - if ((old_p == p) || ((old_p->pre_handler == aggr_pre_handler) && + if ((old_p == p) || ((old_p->pre_handler == aggr_pre_handler) && (p->list.next == &old_p->list) && (p->list.prev == &old_p->list))) { /* Only probe on the hash list */ @@ -620,14 +565,7 @@ valid_p: cleanup_p = 0; } DBPRINTF ("dbi_unregister_kprobe cleanup_p=%d", cleanup_p); - // mutex_unlock(&kprobe_mutex); - // synchronize_sched(); - /* - if (p->mod_refcounted && - (mod = module_text_address((unsigned long)p->addr))) - module_put(mod); - */ if (cleanup_p) { if (p != old_p) @@ -639,7 +577,6 @@ valid_p: } else { - /// mutex_lock(&kprobe_mutex); if (p->break_handler) old_p->break_handler = NULL; if (p->post_handler) @@ -655,32 +592,21 @@ valid_p: if (cleanup_p == 0) old_p->post_handler = NULL; } - // mutex_unlock(&kprobe_mutex); } - - /* Call unregister_page_fault_notifier() - * if no probes are active - */ - // mutex_lock(&kprobe_mutex); - /* if (atomic_add_return(-1, &kprobe_count) == \ - ARCH_INACTIVE_KPROBE_COUNT) - unregister_page_fault_notifier(&kprobe_page_fault_nb);*/ - // mutex_unlock(&kprobe_mutex); - return; } -int dbi_register_jprobe (struct jprobe *jp, int atomic) +int dbi_register_jprobe (struct jprobe *jp) { /* Todo: Verify probepoint is a function entry point */ jp->kp.pre_handler = setjmp_pre_handler; jp->kp.break_handler = longjmp_break_handler; - return __dbi_register_kprobe (&jp->kp, (unsigned long) __builtin_return_address (0), atomic); + return dbi_register_kprobe (&jp->kp); } -void dbi_unregister_jprobe (struct jprobe *jp, int atomic) +void dbi_unregister_jprobe (struct jprobe *jp) { - dbi_unregister_kprobe (&jp->kp, 0, atomic); + dbi_unregister_kprobe (&jp->kp, 0); } /* @@ -746,12 +672,11 @@ int alloc_nodes_kretprobe(struct kretprobe *rp) return 0; } -int dbi_register_kretprobe (struct kretprobe *rp, int atomic) +int dbi_register_kretprobe (struct kretprobe *rp) { int ret = 0; struct kretprobe_instance *inst; int i; - int priority = atomic ? GFP_ATOMIC : GFP_KERNEL; DBPRINTF ("START"); rp->kp.pre_handler = pre_handler_kretprobe; @@ -776,7 +701,7 @@ int dbi_register_kretprobe (struct kretprobe *rp, int atomic) INIT_HLIST_HEAD (&rp->free_instances); for (i = 0; i < rp->maxactive; i++) { - inst = kmalloc (sizeof (struct kretprobe_instance), priority); + inst = kmalloc (sizeof (struct kretprobe_instance), GFP_KERNEL); if (inst == NULL) { free_rp_inst (rp); @@ -789,7 +714,7 @@ int dbi_register_kretprobe (struct kretprobe *rp, int atomic) DBPRINTF ("addr=%p, *addr=[%lx %lx %lx]", rp->kp.addr, (unsigned long) (*(rp->kp.addr)), (unsigned long) (*(rp->kp.addr + 1)), (unsigned long) (*(rp->kp.addr + 2))); rp->nmissed = 0; /* Establish function entry probe point */ - if ((ret = __dbi_register_kprobe (&rp->kp, (unsigned long) __builtin_return_address (0), atomic)) != 0) + if ((ret = dbi_register_kprobe (&rp->kp)) != 0) free_rp_inst (rp); DBPRINTF ("addr=%p, *addr=[%lx %lx %lx]", rp->kp.addr, (unsigned long) (*(rp->kp.addr)), (unsigned long) (*(rp->kp.addr + 1)), (unsigned long) (*(rp->kp.addr + 2))); @@ -799,12 +724,12 @@ int dbi_register_kretprobe (struct kretprobe *rp, int atomic) return ret; } -void dbi_unregister_kretprobe (struct kretprobe *rp, int atomic) +void dbi_unregister_kretprobe (struct kretprobe *rp) { unsigned long flags; struct kretprobe_instance *ri; - dbi_unregister_kprobe (&rp->kp, 0, atomic); + dbi_unregister_kprobe (&rp->kp, 0); if((unsigned int)rp->kp.addr == sched_addr) sched_rp = NULL; diff --git a/kprobe/dbi_kprobes.h b/kprobe/dbi_kprobes.h index a0a500b..2e7bbe0 100644 --- a/kprobe/dbi_kprobes.h +++ b/kprobe/dbi_kprobes.h @@ -45,18 +45,13 @@ * 2006-2007 Ekaterina Gorelkina : initial implementation for ARM and MIPS * 2008-2009 Alexey Gerenkov User-Space * Probes initial implementation; Support x86/ARM/MIPS for both user and kernel spaces. - * 2010 Ekaterina Gorelkina : redesign module for separating core and arch parts + * 2010 Ekaterina Gorelkina : redesign module for separating core and arch parts * - */ - #include // LINUX_VERSION_CODE, KERNEL_VERSION() - -//#include #include -//#include #include #include #include @@ -234,8 +229,8 @@ struct kprobe *get_kprobe_by_insn_slot (void *addr, int tgid, struct task_struct struct hlist_head *kretprobe_inst_table_head (void *hash_key); -int dbi_register_kprobe (struct kprobe *p, int atomic); -void dbi_unregister_kprobe (struct kprobe *p, struct task_struct *task, int atomic); +int dbi_register_kprobe (struct kprobe *p); +void dbi_unregister_kprobe (struct kprobe *p, struct task_struct *task); int register_aggr_kprobe (struct kprobe *old_p, struct kprobe *p); int pre_handler_kretprobe (struct kprobe *p, struct pt_regs *regs); @@ -243,8 +238,8 @@ int pre_handler_kretprobe (struct kprobe *p, struct pt_regs *regs); int setjmp_pre_handler (struct kprobe *, struct pt_regs *); int longjmp_break_handler (struct kprobe *, struct pt_regs *); -int dbi_register_jprobe (struct jprobe *p, int atomic); -void dbi_unregister_jprobe (struct jprobe *p, int atomic); +int dbi_register_jprobe (struct jprobe *p); +void dbi_unregister_jprobe (struct jprobe *p); void dbi_jprobe_return (void); void dbi_jprobe_return_end (void); @@ -253,10 +248,10 @@ struct kretprobe_instance * get_used_rp_inst (struct kretprobe *rp); int alloc_nodes_kretprobe(struct kretprobe *rp); -int dbi_register_kretprobe (struct kretprobe *rp, int atomic); -void dbi_unregister_kretprobe (struct kretprobe *rp, int atomic); +int dbi_register_kretprobe (struct kretprobe *rp); +void dbi_unregister_kretprobe (struct kretprobe *rp); -void kretprobe_assert (struct kretprobe_instance *ri, +void kretprobe_assert (struct kretprobe_instance *ri, unsigned long orig_ret_address, unsigned long trampoline_address); diff --git a/kprobe/dbi_uprobes.c b/kprobe/dbi_uprobes.c index d2bf5bf..d69cd8b 100644 --- a/kprobe/dbi_uprobes.c +++ b/kprobe/dbi_uprobes.c @@ -139,7 +139,7 @@ out: void unregister_uprobe (struct kprobe *p, struct task_struct *task, int atomic) { - dbi_unregister_kprobe (p, task, atomic); + dbi_unregister_kprobe (p, task); } -- 2.7.4