From: Alexander Aksenov Date: Tue, 9 Sep 2014 07:59:57 +0000 (+0400) Subject: [FEATURE] New probes interface X-Git-Tag: submit/tizen/20151123.110932~118 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=f71aa99c316e5aebdee03adc74e6b87b14bfd502;p=kernel%2Fswap-modules.git [FEATURE] New probes interface Separates probes from us_manager. Now all new probe types should register their methods using special interface declared in us_manager/probes/register_probes.h To use probes methods, include us_manager/probes/use_probes.h. Change-Id: I07c7452789b8eec42cd5372ad2b69a5b8d56804b Signed-off-by: Alexander Aksenov --- diff --git a/Kbuild b/Kbuild index e334a39..40b8f27 100644 --- a/Kbuild +++ b/Kbuild @@ -11,4 +11,5 @@ obj-m := buffer/ \ ks_features/ \ sampler/ \ energy/ \ - parser/ + parser/ \ + retprobe/ diff --git a/build.sh b/build.sh index b13e5dd..e824400 100755 --- a/build.sh +++ b/build.sh @@ -34,6 +34,7 @@ ks_features_dir=${modules_dir}/ks_features sampler_dir=${modules_dir}/sampler energy_dir=${modules_dir}/energy parser_dir=${modules_dir}/parser +retprobe_dir=${modules_dir}/retprobe buffer_module_name=swap_buffer.ko driver_module_name=swap_driver.ko @@ -47,6 +48,7 @@ sampler_module_name=swap_sampler.ko energy_module_name=swap_energy.ko parser_module_name=swap_message_parser.ko ksyms_module_name=swap_ksyms.ko +retprobe_module_name=swap_retprobe.ko install_dir="/opt/swap/sdk" @@ -69,7 +71,8 @@ ${ks_features_dir}/${ks_features_module_name} \ ${sampler_dir}/${sampler_module_name} \ ${energy_dir}/${energy_module_name} \ ${parser_dir}/${parser_module_name} \ -${ksyms_dir}/${ksyms_module_name}" +${ksyms_dir}/${ksyms_module_name} \ +${retprobe_dir}/${retprobe_module_name}" for m in ${modules} ; do ${cross_compile}strip -x -g $m diff --git a/parser/us_inst.c b/parser/us_inst.c index 4baf1a6..b36edba 100644 --- a/parser/us_inst.c +++ b/parser/us_inst.c @@ -33,6 +33,8 @@ #include #include #include +#include + #include "msg_parser.h" #include "us_inst.h" @@ -72,9 +74,17 @@ static int mod_func_inst(struct func_inst_data *func, struct pf_group *pfg, switch (mt) { case MT_ADD: - ret = pf_register_probe(pfg, dentry, func->addr, func->args, - func->ret_type); + { + struct probe_info probe_i; + + /* ARM toolchain hates good style initialization of struct with union */ + probe_i.probe_type = SWAP_RETPROBE; + probe_i.rp_i.args = func->args; + probe_i.rp_i.ret_type = func->ret_type; + probe_i.rp_i.size = 0; + ret = pf_register_probe(pfg, dentry, func->addr, &probe_i); break; + } case MT_DEL: ret = pf_unregister_probe(pfg, dentry, func->addr); break; diff --git a/retprobe/Kbuild b/retprobe/Kbuild new file mode 100644 index 0000000..0c9fefb --- /dev/null +++ b/retprobe/Kbuild @@ -0,0 +1,4 @@ +EXTRA_CFLAGS := $(extra_cflags) + +obj-m := swap_retprobe.o +swap_retprobe-y := retprobe.o diff --git a/retprobe/retprobe.c b/retprobe/retprobe.c new file mode 100644 index 0000000..96ba8c4 --- /dev/null +++ b/retprobe/retprobe.c @@ -0,0 +1,143 @@ +/* + * SWAP uprobe manager + * modules/retprobe/retprobe.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) Samsung Electronics, 2014 + * + * 2014 Alexander Aksenov: Probes interface implement + * + */ + +#include "retprobe.h" +#include +#include +#include +#include +#include +#include +#include + +static int retprobe_copy(struct probe_info *dest, + const struct probe_info *source) +{ + size_t len; + + memcpy(dest, source, sizeof(*source)); + + len = strlen(source->rp_i.args) + 1; + dest->rp_i.args = kmalloc(len, GFP_KERNEL); + if (dest->rp_i.args == NULL) + return -ENOMEM; + memcpy(dest->rp_i.args, source->rp_i.args, len); + + return 0; +} + + +static void retprobe_cleanup(struct probe_info *probe_i) +{ + kfree(probe_i->rp_i.args); +} + + + +static struct uprobe *retprobe_get_uprobe(struct us_ip *ip) +{ + return &ip->retprobe.up; +} + +static int retprobe_register_probe(struct us_ip *ip) +{ + return swap_register_uretprobe(&ip->retprobe); +} + +static void retprobe_unregister_probe(struct us_ip *ip, int disarm) +{ + __swap_unregister_uretprobe(&ip->retprobe, disarm); +} + + +static int retprobe_entry_handler(struct uretprobe_instance *ri, struct pt_regs *regs) +{ + struct uretprobe *rp = ri->rp; + + if (rp && get_quiet() == QT_OFF) { + struct us_ip *ip = container_of(rp, struct us_ip, retprobe); + const char *fmt = ip->probe_i.rp_i.args; + unsigned long addr = (unsigned long)ip->orig_addr; + + entry_event(fmt, addr, regs, PT_US, PST_NONE); + } + + return 0; +} + +static int retprobe_ret_handler(struct uretprobe_instance *ri, struct pt_regs *regs) +{ + struct uretprobe *rp = ri->rp; + + if (rp && get_quiet() == QT_OFF) { + struct us_ip *ip = container_of(rp, struct us_ip, retprobe); + unsigned long addr = (unsigned long)ip->orig_addr; + unsigned long ret_addr = (unsigned long)ri->ret_addr; + + exit_event(ip->probe_i.rp_i.ret_type, regs, PT_US, PST_NONE, addr, + ret_addr); + } + + return 0; +} + +static void retprobe_init(struct us_ip *ip) +{ + ip->retprobe.entry_handler = retprobe_entry_handler; + ip->retprobe.handler = retprobe_ret_handler; + ip->retprobe.maxactive = 0; +} + +static void retprobe_uninit(struct us_ip *ip) +{ + retprobe_cleanup(&ip->probe_i); +} + + +static struct probe_iface retprobe_iface = { + .init = retprobe_init, + .uninit = retprobe_uninit, + .reg = retprobe_register_probe, + .unreg = retprobe_unregister_probe, + .get_uprobe = retprobe_get_uprobe, + .copy = retprobe_copy, + .cleanup = retprobe_cleanup +}; + +static int __init retprobe_module_init(void) +{ + return swap_register_probe_type(SWAP_RETPROBE, &retprobe_iface); +} + +static void __exit retprobe_module_exit(void) +{ + swap_unregister_probe_type(SWAP_RETPROBE); +} + +module_init(retprobe_module_init); +module_exit(retprobe_module_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("SWAP retprobe"); +MODULE_AUTHOR("Alexander Aksenov "); diff --git a/retprobe/retprobe.h b/retprobe/retprobe.h new file mode 100644 index 0000000..7a82781 --- /dev/null +++ b/retprobe/retprobe.h @@ -0,0 +1,34 @@ +/* + * SWAP uprobe manager + * modules/us_manager/probes/uretprobe.h + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) Samsung Electronics, 2014 + * + * 2014 Alexander Aksenov: Probes interface implement + * + */ + +#ifndef __URETPROBE_H__ +#define __URETPROBE_H__ + +/* Common retprobe info */ +struct retprobe_info { + char *args; + char ret_type; +}; + +#endif /* __URETPROBE_H__ */ diff --git a/us_manager/Kbuild b/us_manager/Kbuild index 5e2cc16..c6db3e9 100644 --- a/us_manager/Kbuild +++ b/us_manager/Kbuild @@ -8,4 +8,5 @@ swap_us_manager-y := us_manager.o us_slot_manager.o helper.o debugfs_us_manager. sspt/ip.o sspt/sspt_page.o sspt/sspt_file.o sspt/sspt_proc.o \ sspt/sspt_feature.o sspt/sspt_filter.o \ pf/proc_filters.o pf/pf_group.o \ - img/img_proc.o img/img_file.o img/img_ip.o + img/img_proc.o img/img_file.o img/img_ip.o \ + probes/probes.o diff --git a/us_manager/img/img_file.c b/us_manager/img/img_file.c index 6a2d405..d87a2c0 100644 --- a/us_manager/img/img_file.c +++ b/us_manager/img/img_file.c @@ -94,12 +94,12 @@ static struct img_ip *find_img_ip(struct img_file *file, unsigned long addr) * * @param file Pointer to the img_file struct * @param addr Function address - * @param args Function arguments - * @param ret_type Return type + * @param probe_Pointer to a probe_info structure with an information about + * the probe. * @return Error code */ int img_file_add_ip(struct img_file *file, unsigned long addr, - const char *args, char ret_type) + struct probe_info *probe_i) { struct img_ip *ip; @@ -109,7 +109,7 @@ int img_file_add_ip(struct img_file *file, unsigned long addr, return 0; } - ip = create_img_ip(addr, args, ret_type); + ip = create_img_ip(addr, probe_i); img_add_ip_by_list(file, ip); return 0; diff --git a/us_manager/img/img_file.h b/us_manager/img/img_file.h index 312313d..5e7977b 100644 --- a/us_manager/img/img_file.h +++ b/us_manager/img/img_file.h @@ -28,6 +28,8 @@ #include +struct probe_info; + /** * @struct img_file * @breaf Image of file @@ -42,7 +44,7 @@ struct img_file *create_img_file(struct dentry *dentry); void free_img_file(struct img_file *ip); int img_file_add_ip(struct img_file *file, unsigned long addr, - const char *args, char ret_type); + struct probe_info *probe_i); int img_file_del_ip(struct img_file *file, unsigned long addr); int img_file_empty(struct img_file *file); diff --git a/us_manager/img/img_ip.c b/us_manager/img/img_ip.c index 102d9f0..7b6395a 100644 --- a/us_manager/img/img_ip.c +++ b/us_manager/img/img_ip.c @@ -24,32 +24,25 @@ #include "img_ip.h" +#include #include /** * @brief Create img_ip struct * * @param addr Function address - * @param args Function arguments - * @param ret_type Return type + * @param probe_i Pointer to the probe info data. * @return Pointer to the created img_ip struct */ -struct img_ip *create_img_ip(unsigned long addr, const char *args, - char ret_type) +struct img_ip *create_img_ip(unsigned long addr, struct probe_info *probe_i) { struct img_ip *ip; - size_t len; ip = kmalloc(sizeof(*ip), GFP_KERNEL); INIT_LIST_HEAD(&ip->list); ip->addr = addr; - /* copy args */ - len = strlen(args) + 1; - ip->args = kmalloc(len, GFP_KERNEL); - memcpy(ip->args, args, len); - - ip->ret_type = ret_type; + probe_info_copy(probe_i, &ip->probe_i); return ip; } @@ -62,7 +55,7 @@ struct img_ip *create_img_ip(unsigned long addr, const char *args, */ void free_img_ip(struct img_ip *ip) { - kfree(ip->args); + probe_info_cleanup(&ip->probe_i); kfree(ip); } @@ -76,6 +69,8 @@ void free_img_ip(struct img_ip *ip) /* debug */ void img_ip_print(struct img_ip *ip) { - printk("### addr=8%lx, args=%s\n", ip->addr, ip->args); + if (ip->probe_i.probe_type == SWAP_RETPROBE) + printk("### addr=8%lx, args=%s\n", ip->addr, + ip->probe_i.rp_i.args); } /* debug */ diff --git a/us_manager/img/img_ip.h b/us_manager/img/img_ip.h index a6992f7..cd14722 100644 --- a/us_manager/img/img_ip.h +++ b/us_manager/img/img_ip.h @@ -27,6 +27,7 @@ #define _IMG_IP_H #include +#include /** * @struct img_ip @@ -35,12 +36,10 @@ struct img_ip { struct list_head list; /**< For img_file */ unsigned long addr; /**< Function address */ - char *args; /**< Function arguments */ - char ret_type; /**< Return type */ + struct probe_info probe_i; /**< Probe info */ }; -struct img_ip *create_img_ip(unsigned long addr, const char *args, - char ret_type); +struct img_ip *create_img_ip(unsigned long addr, struct probe_info *probe_i); void free_img_ip(struct img_ip *ip); /* debug */ diff --git a/us_manager/img/img_proc.c b/us_manager/img/img_proc.c index ce7749a..71b20d3 100644 --- a/us_manager/img/img_proc.c +++ b/us_manager/img/img_proc.c @@ -90,23 +90,22 @@ static struct img_file *find_img_file(struct img_proc *proc, struct dentry *dent * @param proc Pointer to the img_proc struct * @param dentry Dentry of file * @param addr Function address - * @param args Function address - * @param ret_type Return type + * @param probe_i Pointer to a probe_info struct related with the probe * @return Error code */ int img_proc_add_ip(struct img_proc *proc, struct dentry *dentry, - unsigned long addr, const char *args, char ret_type) + unsigned long addr, struct probe_info *probe_i) { int ret; struct img_file *file; file = find_img_file(proc, dentry); if (file) - return img_file_add_ip(file, addr, args, ret_type); + return img_file_add_ip(file, addr, probe_i); file = create_img_file(dentry); - ret = img_file_add_ip(file, addr, args, ret_type); + ret = img_file_add_ip(file, addr, probe_i); if (ret) { printk("Cannot add ip to img file\n"); free_img_file(file); diff --git a/us_manager/img/img_proc.h b/us_manager/img/img_proc.h index a1b71d5..745df84 100644 --- a/us_manager/img/img_proc.h +++ b/us_manager/img/img_proc.h @@ -28,6 +28,7 @@ #include struct dentry; +struct probe_info; /** * @struct img_proc @@ -41,7 +42,7 @@ struct img_proc *create_img_proc(void); void free_img_proc(struct img_proc *proc); int img_proc_add_ip(struct img_proc *proc, struct dentry *dentry, - unsigned long addr, const char *args, char ret_type); + unsigned long addr, struct probe_info *probe_i); int img_proc_del_ip(struct img_proc *proc, struct dentry *dentry, unsigned long addr); /* debug */ diff --git a/us_manager/pf/pf_group.c b/us_manager/pf/pf_group.c index e5667b0..920c8fc 100644 --- a/us_manager/pf/pf_group.c +++ b/us_manager/pf/pf_group.c @@ -86,8 +86,7 @@ void copy_proc_form_img_to_sspt(struct img_proc *i_proc, struct sspt_proc *proc) file = sspt_proc_find_file_or_new(proc, i_file->dentry); list_for_each_entry(i_ip, &i_file->ip_list, list) - sspt_file_add_ip(file, i_ip->addr, i_ip->args, - i_ip->ret_type); + sspt_file_add_ip(file, i_ip->addr, &i_ip->probe_i); } } @@ -345,14 +344,13 @@ void put_pf_group(struct pf_group *pfg) * @param pfg Pointer to the pf_group struct * @param dentry Dentry of file * @param offset Function offset - * @param args Function arguments - * @param ret_type Return type + * @param probe_info Pointer to the related probe_info struct * @return Error code */ int pf_register_probe(struct pf_group *pfg, struct dentry *dentry, - unsigned long offset, const char *args, char ret_type) + unsigned long offset, struct probe_info *probe_i) { - return img_proc_add_ip(pfg->i_proc, dentry, offset, args, ret_type); + return img_proc_add_ip(pfg->i_proc, dentry, offset, probe_i); } EXPORT_SYMBOL_GPL(pf_register_probe); diff --git a/us_manager/pf/pf_group.h b/us_manager/pf/pf_group.h index 2065768..f69bd0b 100644 --- a/us_manager/pf/pf_group.h +++ b/us_manager/pf/pf_group.h @@ -30,6 +30,7 @@ struct dentry; struct pf_group; struct sspt_proc; +struct probe_info; struct pf_group *get_pf_group_by_dentry(struct dentry *dentry, void *priv); struct pf_group *get_pf_group_by_tgid(pid_t tgid, void *priv); @@ -38,7 +39,7 @@ struct pf_group *get_pf_group_dumb(void *priv); void put_pf_group(struct pf_group *pfg); int pf_register_probe(struct pf_group *pfg, struct dentry *dentry, - unsigned long offset, const char *args, char ret_type); + unsigned long offset, struct probe_info *probe_i); int pf_unregister_probe(struct pf_group *pfg, struct dentry *dentry, unsigned long offset); diff --git a/us_manager/probes/probes.c b/us_manager/probes/probes.c new file mode 100644 index 0000000..52b024f --- /dev/null +++ b/us_manager/probes/probes.c @@ -0,0 +1,229 @@ +/* + * SWAP uprobe manager + * modules/us_manager/probes/probes.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) Samsung Electronics, 2014 + * + * 2014 Alexander Aksenov: Probes interface implement + * + */ + +#include "probes.h" +#include "register_probes.h" +#include "use_probes.h" + +#include +#include +#include + +static struct probe_iface *probes_methods[SWAP_PROBE_MAX_VAL] = { NULL }; + +/* 1 - correct probe type + 0 - wrong probe type +*/ +static inline int correct_probe_type(enum probe_t probe_type) +{ + if (probe_type >= SWAP_PROBE_MAX_VAL) + return 0; + + return 1; +} + +static inline int methods_exist(enum probe_t probe_type) +{ + if (!correct_probe_type(probe_type)) + return 0; + + if (probes_methods[probe_type] == NULL) + return 0; + + return 1; +} + +/** + * @brief Calls specified probe type init method. + * + * @param pi Pointer to the probe_info. + * @param ip Pointer to the probe us_ip struct. + * @return Void. + */ +void probe_info_init(struct probe_info *pi, struct us_ip *ip) +{ + enum probe_t probe_type = pi->probe_type; + + if (!methods_exist(probe_type)) { + printk(KERN_WARNING "SWAP US_MANAGER: Wrong probe type!\n"); + return; + } + + probes_methods[probe_type]->init(ip); +} + +/** + * @brief Calls specified probe type uninit method. + * + * @param pi Pointer to the probe_info. + * @param ip Pointer to the probe us_ip struct. + * @return Void. + */ +void probe_info_uninit(struct probe_info *pi, struct us_ip *ip) +{ + enum probe_t probe_type = pi->probe_type; + + if (!methods_exist(probe_type)) { + printk(KERN_WARNING "SWAP US_MANAGER: Wrong probe type!\n"); + return; + } + + probes_methods[probe_type]->uninit(ip); +} + +/** + * @brief Calls specified probe type register method. + * + * @param pi Pointer to the probe_info. + * @param ip Pointer to the probe us_ip struct. + * @return -EINVAL on wrong probe type, method result otherwise. + */ +int probe_info_register(struct probe_info *pi, struct us_ip *ip) +{ + enum probe_t probe_type = pi->probe_type; + + if (!methods_exist(probe_type)) { + printk(KERN_WARNING "SWAP US_MANAGER: Wrong probe type!\n"); + return -EINVAL; + } + + return probes_methods[probe_type]->reg(ip); +} + +/** + * @brief Calls specified probe type unregister method. + * + * @param pi Pointer to the probe_info. + * @param ip Pointer to the probe us_ip struct. + * @param disarm Disarm flag. + * @return Void. + */ +void probe_info_unregister(struct probe_info *pi, struct us_ip *ip, int disarm) +{ + enum probe_t probe_type = pi->probe_type; + + if (!methods_exist(probe_type)) { + printk(KERN_WARNING "SWAP US_MANAGER: Wrong probe type!\n"); + return; + } + + probes_methods[probe_type]->unreg(ip, disarm); +} + +/** + * @brief Calls specified probe type get underlying uprobe method. + * + * @param pi Pointer to the probe_info. + * @param ip Pointer to the probe us_ip struct. + * @return Pointer to the uprobe struct, NULL on error. + */ +struct uprobe *probe_info_get_uprobe(struct probe_info *pi, struct us_ip *ip) +{ + enum probe_t probe_type = pi->probe_type; + + if (!methods_exist(probe_type)) { + printk(KERN_WARNING "SWAP US_MANAGER: Wrong probe type!\n"); + return NULL; + } + + return probes_methods[probe_type]->get_uprobe(ip); +} + +/** + * @brief Calls specified probe type copy method. + * + * @param pi Pointer to the source probe_info. + * @param dest Pointer to the probe us_ip struct. + * @return -EINVAL on error, method result otherwise. + */ +int probe_info_copy(const struct probe_info *pi, struct probe_info *dest) +{ + enum probe_t probe_type = pi->probe_type; + + if (!methods_exist(probe_type)) { + printk(KERN_WARNING "SWAP US_MANAGER: Wrong probe type!\n"); + return -EINVAL; + } + + return probes_methods[probe_type]->copy(dest, pi); +} + +/** + * @brief Calls specified probe type cleanup method. + * + * @param pi Pointer to the source probe_info. + * @return Void. + */ +void probe_info_cleanup(struct probe_info *pi) +{ + enum probe_t probe_type = pi->probe_type; + + if (!methods_exist(probe_type)) { + printk(KERN_WARNING "SWAP US_MANAGER: Wrong probe type!\n"); + return; + } + + probes_methods[probe_type]->cleanup(pi); +} + +/** + * @brief Registers probe type. + * + * @param probe_type Number, associated with this probe type. + * @param pi Pointer to the probe interface structure + * @return 0 on succes, error code on error. + */ +int swap_register_probe_type(enum probe_t probe_type, struct probe_iface *pi) +{ + if (!correct_probe_type(probe_type)) { + printk(KERN_ERR "SWAP US_MANAGER: Wrong probe type!\n"); + return -EINVAL; + } + + if (probes_methods[probe_type] != NULL) + printk(KERN_WARNING "SWAP US_MANAGER: Re-registering probe %d\n", + probe_type); + + probes_methods[probe_type] = pi; + + return 0; +} +EXPORT_SYMBOL_GPL(swap_register_probe_type); + +/** + * @brief Unregisters probe type. + * + * @param probe_type Probe type that should be unregistered. + * @return Void. + */ +void swap_unregister_probe_type(enum probe_t probe_type) +{ + if (!correct_probe_type(probe_type)) { + printk(KERN_ERR "SWAP US_MANAGER: Wrong probe type!\n"); + return; + } + + probes_methods[probe_type] = NULL; +} +EXPORT_SYMBOL_GPL(swap_unregister_probe_type); diff --git a/us_manager/probes/probes.h b/us_manager/probes/probes.h new file mode 100644 index 0000000..4ba8111 --- /dev/null +++ b/us_manager/probes/probes.h @@ -0,0 +1,53 @@ +/* + * SWAP uprobe manager + * modules/us_manager/probes/probes.h + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) Samsung Electronics, 2014 + * + * 2014 Alexander Aksenov: Probes interface implement + * + */ + + +#ifndef __PROBES_H__ +#define __PROBES_H__ + +#include + +#include /* TODO Remove */ + + + +/* All probe types. Only us_manager should know about them - it is its own + * business to install proper probes on proper places. + */ +enum probe_t { + SWAP_RETPROBE = 0, /* Retprobe */ + SWAP_PROBE_MAX_VAL /* Probes max value. */ +}; + +/* Probe info stuct. It contains the whole information about probe. */ +struct probe_info { + enum probe_t probe_type; + size_t size; + /* Union of all SWAP supported probe types */ + union { + struct retprobe_info rp_i; + }; +}; + +#endif /* __PROBES_H__ */ diff --git a/us_manager/probes/register_probes.h b/us_manager/probes/register_probes.h new file mode 100644 index 0000000..fb6a244 --- /dev/null +++ b/us_manager/probes/register_probes.h @@ -0,0 +1,21 @@ +#ifndef __REGISTER_PROBES_H__ +#define __REGISTER_PROBES_H__ + +#include "probes.h" + +struct us_ip; + +struct probe_iface { + void (*init)(struct us_ip *); + void (*uninit)(struct us_ip *); + int (*reg)(struct us_ip *); + void (*unreg)(struct us_ip *, int); + struct uprobe *(*get_uprobe)(struct us_ip *); + int (*copy)(struct probe_info *, const struct probe_info *); + void (*cleanup)(struct probe_info *); +}; + +int swap_register_probe_type(enum probe_t probe_type, struct probe_iface *pi); +void swap_unregister_probe_type(enum probe_t probe_type); + +#endif /* __REGISTER_PROBES_H__ */ diff --git a/us_manager/probes/use_probes.h b/us_manager/probes/use_probes.h new file mode 100644 index 0000000..80cfb3a --- /dev/null +++ b/us_manager/probes/use_probes.h @@ -0,0 +1,16 @@ +#ifndef __USE_PROBES_H__ +#define __USE_PROBES_H__ + +#include "probes.h" + +struct us_ip; + +void probe_info_init(struct probe_info *pi, struct us_ip *ip); +void probe_info_uninit(struct probe_info *pi, struct us_ip *ip); +int probe_info_register(struct probe_info *pi, struct us_ip *ip); +void probe_info_unregister(struct probe_info *pi, struct us_ip *ip, int disarm); +struct uprobe *probe_info_get_uprobe(struct probe_info *pi, struct us_ip *ip); +int probe_info_copy(const struct probe_info *pi, struct probe_info *dest); +void probe_info_cleanup(struct probe_info *pi); + +#endif /* __USE_PROBES_H__ */ diff --git a/us_manager/sspt/ip.c b/us_manager/sspt/ip.c index a54353e..0a46b33 100644 --- a/us_manager/sspt/ip.c +++ b/us_manager/sspt/ip.c @@ -26,67 +26,29 @@ #include "ip.h" #include "sspt_page.h" #include "sspt_file.h" -#include -#include - - -static int entry_handler(struct uretprobe_instance *ri, struct pt_regs *regs) -{ - struct uretprobe *rp = ri->rp; - - if (rp && get_quiet() == QT_OFF) { - struct us_ip *ip = container_of(rp, struct us_ip, retprobe); - const char *fmt = ip->args; - unsigned long addr = (unsigned long)ip->orig_addr; - - entry_event(fmt, addr, regs, PT_US, PST_NONE); - } - - return 0; -} - -static int ret_handler(struct uretprobe_instance *ri, struct pt_regs *regs) -{ - struct uretprobe *rp = ri->rp; - - if (rp && get_quiet() == QT_OFF) { - struct us_ip *ip = container_of(rp, struct us_ip, retprobe); - unsigned long addr = (unsigned long)ip->orig_addr; - unsigned long ret_addr = (unsigned long)ri->ret_addr; - - exit_event(ip->ret_type, regs, PT_US, PST_NONE, addr, ret_addr); - } - - return 0; -} +#include /** * @brief Create us_ip struct * * @param offset Function offset from the beginning of the page - * @param args Function arguments - * @param ret_type Return type + * @param probe_i Pointer to the probe data. * @return Pointer to the created us_ip struct */ -struct us_ip *create_ip(unsigned long offset, const char *args, char ret_type) +struct us_ip *create_ip(unsigned long offset, const struct probe_info *probe_i) { - size_t len = strlen(args) + 1; - struct us_ip *ip = kmalloc(sizeof(*ip) + len, GFP_ATOMIC); + size_t len = probe_i->size; + struct us_ip *ip; + ip = kmalloc(sizeof(*ip) + len, GFP_ATOMIC); if (ip != NULL) { - memset(ip, 0, sizeof(*ip)); + memset(ip, 0, sizeof(*ip) + len); INIT_LIST_HEAD(&ip->list); ip->offset = offset; - ip->args = (char *)ip + sizeof(*ip); - ip->ret_type = ret_type; - - /* copy args */ - memcpy(ip->args, args, len); - /* retprobe */ - ip->retprobe.handler = ret_handler; - ip->retprobe.entry_handler = entry_handler; + probe_info_copy(probe_i, &ip->probe_i); + probe_info_init(&ip->probe_i, ip); } else { printk("Cannot kmalloc in create_ip function!\n"); } @@ -102,5 +64,6 @@ struct us_ip *create_ip(unsigned long offset, const char *args, char ret_type) */ void free_ip(struct us_ip *ip) { + probe_info_uninit(&ip->probe_i, ip); kfree(ip); } diff --git a/us_manager/sspt/ip.h b/us_manager/sspt/ip.h index 6ceb3d1..30cee3c 100644 --- a/us_manager/sspt/ip.h +++ b/us_manager/sspt/ip.h @@ -26,6 +26,7 @@ #include #include +#include struct sspt_page; @@ -34,19 +35,21 @@ struct sspt_page; * @breaf Image of instrumentation pointer for specified process */ struct us_ip { - struct list_head list; /**< For sspt_page */ - struct sspt_page *page; /**< Pointer on the page (parent) */ + struct list_head list; /**< For sspt_page */ + struct sspt_page *page; /**< Pointer on the page (parent) */ + struct probe_info probe_i; /**< Probe's data */ - struct uretprobe retprobe; /**< uretprobe */ - char *args; /**< Function arguments */ - char ret_type; /**< Return type */ - unsigned long orig_addr; /**< Function address */ + unsigned long orig_addr; /**< Function address */ + unsigned long offset; /**< Page offset */ - unsigned long offset; /**< Page offset */ + union { + struct uretprobe retprobe; + struct uprobe uprobe; + }; }; -struct us_ip *create_ip(unsigned long offset, const char *args, char ret_type); +struct us_ip *create_ip(unsigned long offset, const struct probe_info *probe_i); void free_ip(struct us_ip *ip); #endif /* __IP__ */ diff --git a/us_manager/sspt/sspt.h b/us_manager/sspt/sspt.h index 5cff091..fc10af0 100644 --- a/us_manager/sspt/sspt.h +++ b/us_manager/sspt/sspt.h @@ -35,6 +35,7 @@ #include #include +#include static inline int check_vma(struct vm_area_struct *vma) @@ -48,16 +49,23 @@ static inline int check_vma(struct vm_area_struct *vma) static inline int sspt_register_usprobe(struct us_ip *ip) { int ret; + struct uprobe *up = NULL; - /* for retuprobe */ - ip->retprobe.up.task = ip->page->file->proc->task; - ip->retprobe.up.sm = ip->page->file->proc->sm; + up = probe_info_get_uprobe(&ip->probe_i, ip); - ret = swap_register_uretprobe(&ip->retprobe); + if (!up) { + printk("SWAP US_MANAGER: failed getting uprobe!\n"); + return -EINVAL; + } + + up->task = ip->page->file->proc->task; + up->sm = ip->page->file->proc->sm; + + ret = probe_info_register(&ip->probe_i, ip); if (ret) { struct sspt_file *file = ip->page->file; char *name = file->dentry->d_iname; - unsigned long addr = (unsigned long)ip->retprobe.up.kp.addr; + unsigned long addr = (unsigned long)up->kp.addr; unsigned long offset = addr - file->vm_start; printk("swap_register_uretprobe() failure %d (%s:%lx|%lx)\n", @@ -67,32 +75,26 @@ static inline int sspt_register_usprobe(struct us_ip *ip) return ret; } -static inline int do_unregister_usprobe(struct us_ip *ip, int disarm) -{ - __swap_unregister_uretprobe(&ip->retprobe, disarm); - - return 0; -} - static inline int sspt_unregister_usprobe(struct task_struct *task, struct us_ip *ip, enum US_FLAGS flag) { - int err = 0; + struct uprobe *up = NULL; switch (flag) { case US_UNREGS_PROBE: - err = do_unregister_usprobe(ip, 1); + probe_info_unregister(&ip->probe_i, ip, 1); break; case US_DISARM: - disarm_uprobe(&ip->retprobe.up.kp, task); + up = probe_info_get_uprobe(&ip->probe_i, ip); + disarm_uprobe(&up->kp, task); break; case US_UNINSTALL: - err = do_unregister_usprobe(ip, 0); + probe_info_unregister(&ip->probe_i, ip, 0); break; default: panic("incorrect value flag=%d", flag); } - return err; + return 0; } #endif /* __SSPT__ */ diff --git a/us_manager/sspt/sspt_debug.h b/us_manager/sspt/sspt_debug.h index 26f69ce..9081325 100644 --- a/us_manager/sspt/sspt_debug.h +++ b/us_manager/sspt/sspt_debug.h @@ -26,6 +26,7 @@ */ #include +#include static inline void print_jprobe(struct jprobe *jp) { @@ -41,10 +42,14 @@ static inline void print_retprobe(struct uretprobe *rp) static inline void print_ip(struct us_ip *ip, int i) { - printk("### addr[%2d]=%lx, R_addr=%lx\n", - i, (unsigned long)ip->offset, - (unsigned long)ip->retprobe.up.kp.addr); - print_retprobe(&ip->retprobe); + if (ip->probe_i.probe_type == SWAP_RETPROBE) { + struct uretprobe *rp = &ip->retprobe; + + printk("### addr[%2d]=%lx, R_addr=%lx\n", + i, (unsigned long)ip->offset, + (unsigned long)rp->up.kp.addr); + print_retprobe(rp); + } } static inline void print_page_probes(const struct sspt_page *page) diff --git a/us_manager/sspt/sspt_file.c b/us_manager/sspt/sspt_file.c index c487550..91b0cdf 100644 --- a/us_manager/sspt/sspt_file.c +++ b/us_manager/sspt/sspt_file.c @@ -167,12 +167,12 @@ struct sspt_page *sspt_find_page_mapped(struct sspt_file *file, unsigned long pa * @return Void */ void sspt_file_add_ip(struct sspt_file *file, unsigned long offset, - const char *args, char ret_type) + struct probe_info *probe_i) { struct sspt_page *page = sspt_find_page_or_new(file, offset & PAGE_MASK); // FIXME: delete ip - struct us_ip *ip = create_ip(offset, args, ret_type); + struct us_ip *ip = create_ip(offset, probe_i); sspt_add_ip(page, ip); } diff --git a/us_manager/sspt/sspt_file.h b/us_manager/sspt/sspt_file.h index ce55c38..e2af552 100644 --- a/us_manager/sspt/sspt_file.h +++ b/us_manager/sspt/sspt_file.h @@ -53,7 +53,7 @@ void sspt_file_free(struct sspt_file *file); struct sspt_page *sspt_find_page_mapped(struct sspt_file *file, unsigned long page); void sspt_file_add_ip(struct sspt_file *file, unsigned long offset, - const char *args, char ret_type); + struct probe_info *probe_i); struct sspt_page *sspt_get_page(struct sspt_file *file, unsigned long offset_addr); void sspt_put_page(struct sspt_page *page); diff --git a/us_manager/sspt/sspt_page.c b/us_manager/sspt/sspt_page.c index 0c70f26..31369cf 100644 --- a/us_manager/sspt/sspt_page.c +++ b/us_manager/sspt/sspt_page.c @@ -26,6 +26,7 @@ #include "sspt_page.h" #include "sspt_file.h" #include "ip.h" +#include #include #include @@ -141,6 +142,7 @@ int sspt_register_page(struct sspt_page *page, struct sspt_file *file) int err = 0; struct us_ip *ip, *n; struct list_head ip_list_tmp; + struct uprobe *up; unsigned long addr; spin_lock(&page->lock); @@ -161,7 +163,8 @@ int sspt_register_page(struct sspt_page *page, struct sspt_file *file) addr = file->vm_start + page->offset + ip->offset; ip->orig_addr = addr; - ip->retprobe.up.kp.addr = (kprobe_opcode_t *)addr; + up = probe_info_get_uprobe(&ip->probe_i, ip); + up->kp.addr = (kprobe_opcode_t *)addr; err = sspt_register_usprobe(ip); if (err) {