From: Dmitry Kovalenko Date: Tue, 31 Jan 2012 12:01:42 +0000 (+0400) Subject: "On the go" probes implementation. X-Git-Tag: Tizen_SDK_2.3~815 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=663783a0238c7e6326d9e69c56b5a7f1e0f7ec00;p=kernel%2Fswap-modules.git "On the go" probes implementation. OTG probes can be installed from handlers of other probes. Currently implemented only user space instrumentation. Probe installing is produced by call of "install_otg_ip" function. install_otg_ip(function_addr, pre_handler, jp_handler, rp_handler) pre_handler, jp_handler, rp_handler can be NULL that means deffault handlers. --- diff --git a/driver/storage.c b/driver/storage.c index 6a55493..8a39843 100644 --- a/driver/storage.c +++ b/driver/storage.c @@ -28,6 +28,7 @@ char *p_buffer = NULL; inst_us_proc_t us_proc_info; +struct list_head otg_us_proc_info; inst_dex_proc_t dex_proc_info; char *deps; char *bundle; @@ -750,6 +751,7 @@ void unlink_bundle(void) us_proc_lib_t *d_lib; char *path; struct list_head *pos; //, *tmp; + us_proc_otg_ip_t *p; path = us_proc_info.path; us_proc_info.path = 0; @@ -803,6 +805,11 @@ void unlink_bundle(void) /* } */ us_proc_info.tgid = 0; + + /* OTG probes list cleaning */ + list_for_each_entry_rcu (p, &otg_us_proc_info, list) { + list_del_rcu(&p->list); + } } int link_bundle() @@ -1325,6 +1332,7 @@ int storage_init (void) } INIT_HLIST_HEAD (&kernel_probes); + INIT_LIST_HEAD(&otg_us_proc_info); return 0; } diff --git a/driver/storage.h b/driver/storage.h index c3250e5..8ae7ecd 100644 --- a/driver/storage.h +++ b/driver/storage.h @@ -119,6 +119,8 @@ extern char *p_buffer; // list of selected non-predefined kernel probes extern struct hlist_head kernel_probes; +extern struct list_head otg_us_proc_info; + // event mask extern int event_mask; @@ -136,6 +138,13 @@ typedef struct typedef struct { + us_proc_ip_t ip; + pid_t tgid; + struct list_head list; +} us_proc_otg_ip_t; + +typedef struct +{ int installed; struct jprobe jprobe; unsigned long addr; diff --git a/driver/us_proc_inst.c b/driver/us_proc_inst.c index d65ee9c..7ba0f2c 100644 --- a/driver/us_proc_inst.c +++ b/driver/us_proc_inst.c @@ -33,6 +33,16 @@ DEFINE_PER_CPU (struct pt_regs *, gpCurVtpRegs) = NULL; # warning ARCH_REG_VAL is not implemented for this architecture. FBI will work improperly or even crash!!! #endif // ARCH +unsigned long (*dbi_ujprobe_event_pre_handler_custom_p) +(us_proc_ip_t *, struct pt_regs *) = NULL; +EXPORT_SYMBOL(dbi_ujprobe_event_pre_handler_custom_p); +void (*dbi_ujprobe_event_handler_custom_p)(void) = NULL; +EXPORT_SYMBOL(dbi_ujprobe_event_handler_custom_p); +int (*dbi_uretprobe_event_handler_custom_p) +(struct kretprobe_instance *, struct pt_regs *, us_proc_ip_t *) = NULL; +EXPORT_SYMBOL(dbi_uretprobe_event_handler_custom_p); + + static int register_usprobe (struct task_struct *task, struct mm_struct *mm, us_proc_ip_t * ip, int atomic, kprobe_opcode_t * islot); static int unregister_usprobe (struct task_struct *task, us_proc_ip_t * ip, int atomic); @@ -58,6 +68,76 @@ unsigned long android_app_vma_end = 0; struct dentry *app_process_dentry = NULL; #endif /* ANDROID_APP */ +us_proc_otg_ip_t *find_otg_probe(unsigned long addr) +{ + us_proc_otg_ip_t *p; + struct hlist_node *node; + + //check if such probe does exist + + list_for_each_entry_rcu (p, &otg_us_proc_info, list) + if (p->ip.offset == addr) + break; + + return node ? p : NULL; +} + +int add_otg_probe_to_list(unsigned long addr, us_proc_otg_ip_t **pprobe) +{ + us_proc_otg_ip_t *new_probe; + unsigned long jp_handler_addr, rp_handler_addr, pre_handler_addr; + + us_proc_otg_ip_t *probe; + + if (pprobe) { + *pprobe = NULL; + } + /* check if such probe does already exist */ + probe = find_otg_probe(addr); + if (probe) { + return 1; + } + + new_probe = kmalloc(sizeof(us_proc_otg_ip_t), GFP_KERNEL); + if (!new_probe) { + EPRINTF ("no memory for new probe!"); + return -ENOMEM; + } + memset(new_probe,0, sizeof(us_proc_otg_ip_t)); + + new_probe->ip.offset = addr; + new_probe->ip.jprobe.kp.addr = + new_probe->ip.retprobe.kp.addr = (kprobe_opcode_t *)addr; + new_probe->ip.jprobe.priv_arg = + new_probe->ip.retprobe.priv_arg = new_probe; + + INIT_LIST_HEAD(&new_probe->list); + list_add_rcu(&new_probe->list, &otg_us_proc_info); + + if (pprobe) { + *pprobe = new_probe; + } + return 0; +} + +int remove_otg_probe_from_list(unsigned long addr) +{ + us_proc_otg_ip_t *p; + + //check if such probe does exist + p = find_probe(addr); + if (!p) { + /* We do not care about it. Nothing bad. */ + return 0; + } + + list_del_rcu(&p->list); + + kfree (p); + + return 0; +} + /** * Prepare copy of instrumentation data for task * in case of library only instrumentation @@ -407,6 +487,9 @@ static int install_mapped_ips (struct task_struct *task, inst_us_proc_t* task_in int i, k, err; unsigned long addr; unsigned int old_ips_count, old_vtps_count; + us_proc_otg_ip_t *p; + struct hlist_node *node; + struct task_struct *t; struct mm_struct *mm; char path_buffer[256]; @@ -522,7 +605,7 @@ static int install_mapped_ips (struct task_struct *task, inst_us_proc_t* task_in err = register_usprobe (task, mm, &task_inst_info->p_libs[i].p_ips[k], atomic, 0); if (err != 0) { DPRINTF ("failed to install IP at %lx/%p. Error %d!", task_inst_info->p_libs[i].p_ips[k].offset, - task_inst_info->p_libs[i].p_ips[k].jprobe.kp.addr); + task_inst_info->p_libs[i].p_ips[k].jprobe.kp.addr, err); } } } @@ -560,16 +643,126 @@ static int install_mapped_ips (struct task_struct *task, inst_us_proc_t* task_in } vma = vma->vm_next; } - if(!atomic){ + + list_for_each_entry_rcu (p, &otg_us_proc_info, list) { + if (p->ip.installed) { + continue; + } + rcu_read_lock(); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26) + t = find_task_by_pid(p->tgid); +#else + t = pid_task(find_pid_ns(p->tgid, &init_pid_ns), + PIDTYPE_PID); +#endif + if (t){ + get_task_struct(t); + } + rcu_read_unlock(); + if (!t) { + DPRINTF("task for pid %d not found! Dead probe?", + p->tgid); + continue; + } + if (!t->active_mm) { + continue; + } + if (!page_present(t->active_mm, p->ip.offset)) { + DPRINTF("Page isn't present for %p.", + p->ip.offset); + continue; + } + p->ip.installed = 1; + err = register_usprobe(current, t->active_mm, + &p->ip, atomic, 0); + + if (err != 0) { + DPRINTF("failed to install IP at %lx/%p. Error %d!", + p->ip.offset, + p->ip.jprobe.kp.addr, err); + return err; + } + } + + if (!atomic) { up_read (&mm->mmap_sem); mmput (mm); } return task_inst_info->unres_ips_count + task_inst_info->unres_vtps_count; } +static int install_otg_ip(unsigned long addr, + unsigned long pre_handler, + unsigned long jp_handler, + unsigned long rp_handler) +{ + int err; + us_proc_otg_ip_t *pprobe; + struct mm_struct *mm; + + /* Probe preparing */ + err = add_otg_probe_to_list(addr, &pprobe); + if (err) { + if (err == 1) { + DPRINTF("OTG probe %p already installed.", addr); + return 0; + } else { + DPRINTF("Failed to add new OTG probe, err=%d",err); + return err; + } + } + if (pre_handler) { + pprobe->ip.jprobe.pre_entry = + (kprobe_pre_entry_handler_t)pre_handler; + } else { + pprobe->ip.jprobe.pre_entry = + (kprobe_pre_entry_handler_t) + dbi_ujprobe_event_pre_handler_custom_p; + + } + if (jp_handler) { + pprobe->ip.jprobe.entry = + (kprobe_pre_entry_handler_t)jp_handler; + } else { + pprobe->ip.jprobe.entry = + (kprobe_pre_entry_handler_t) + dbi_ujprobe_event_handler_custom_p; + } + if (rp_handler) { + pprobe->ip.retprobe.handler = + (kprobe_pre_entry_handler_t)rp_handler; + } else { + pprobe->ip.retprobe.handler = + (kprobe_pre_entry_handler_t) + dbi_uretprobe_event_handler_custom_p; + } + + mm = get_task_mm(current); + if (!page_present(mm, addr)) { + DPRINTF("Page isn't present for %p.", addr); + /* Probe will be installed in do_page_fault handler */ + return 0; + } + DPRINTF("Page present for %p.", addr); + + /* Probe installing */ + pprobe->tgid = current->tgid; + pprobe->ip.installed = 1; + err = register_usprobe(current, mm, &pprobe->ip, 1, 0); + if (err != 0) { + DPRINTF("failed to install IP at %lx/%p. Error %d!", + addr, pprobe->ip.jprobe.kp.addr, err); + return err; + } + return 0; +} +EXPORT_SYMBOL_GPL(install_otg_ip); + + static int uninstall_mapped_ips (struct task_struct *task, inst_us_proc_t* task_inst_info, int atomic) { int i, k, err; + us_proc_otg_ip_t *p; for (i = 0; i < task_inst_info->libs_count; i++) { @@ -600,6 +793,20 @@ static int uninstall_mapped_ips (struct task_struct *task, inst_us_proc_t* task } task_inst_info->p_libs[i].loaded = 0; } + list_for_each_entry_rcu (p, &otg_us_proc_info, list) { + if (!p->ip.installed) { + continue; + } + DPRINTF("remove OTG IP at %p.", p->ip.offset); + err = unregister_usprobe(task, &p->ip, atomic); + if (err != 0) { + EPRINTF("failed to uninstall IP at %p. Error %d!", + p->ip.jprobe.kp.addr, err); + continue; + } + p->ip.installed = 0; + } + DPRINTF ("Ures IPs %d.", task_inst_info->unres_ips_count); DPRINTF ("Ures VTPs %d.", task_inst_info->unres_vtps_count); return 0; @@ -1075,13 +1282,6 @@ EXPORT_PER_CPU_SYMBOL_GPL(gpCurIp); DEFINE_PER_CPU(struct pt_regs *, gpUserRegs) = NULL; EXPORT_PER_CPU_SYMBOL_GPL(gpUserRegs); -// XXX MCPP: introduced custom default handlers defined in (exported from) another kernel module(s) -unsigned long (* dbi_ujprobe_event_pre_handler_custom_p)(us_proc_ip_t *, struct pt_regs *) = NULL; -EXPORT_SYMBOL(dbi_ujprobe_event_pre_handler_custom_p); -void (* dbi_ujprobe_event_handler_custom_p)(void) = NULL; -EXPORT_SYMBOL(dbi_ujprobe_event_handler_custom_p); -int (* dbi_uretprobe_event_handler_custom_p)(struct kretprobe_instance *, struct pt_regs *, us_proc_ip_t *) = NULL; -EXPORT_SYMBOL(dbi_uretprobe_event_handler_custom_p); unsigned long ujprobe_event_pre_handler (us_proc_ip_t * ip, struct pt_regs *regs) {