[REFACTOR] remove field priv_arg from struct kretprobe
[kernel/swap-modules.git] / ks_manager / ks_manager.c
1 /*
2  *  Dynamic Binary Instrumentation Module based on KProbes
3  *  modules/ks_manager/ks_manager.c
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  *
19  * Copyright (C) Samsung Electronics, 2013
20  *
21  * 2013         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
22  *
23  */
24
25 #include <linux/module.h>
26 #include <linux/slab.h>
27 #include <dbi_kprobes.h>
28 #include <dbi_kprobes_deps.h>
29 #include "ks_manager.h"
30
31 struct probe {
32         struct hlist_node hlist;
33         struct kern_probe p;
34 };
35
36 static HLIST_HEAD(list_probes);
37
38 static struct probe *create_probe(unsigned long addr, void *pre_handler,
39                                   void *jp_handler, void *rp_handler)
40 {
41         struct probe *p = kzalloc(sizeof(*p), GFP_KERNEL);
42
43         p->p.jp.kp.addr = p->p.rp.kp.addr = (void *)addr;
44         p->p.jp.pre_entry = pre_handler;
45         p->p.jp.entry = jp_handler;
46         p->p.rp.handler = rp_handler;
47         INIT_HLIST_NODE(&p->hlist);
48
49         return p;
50 }
51
52 static void free_probe(struct probe *p)
53 {
54         kfree(p);
55 }
56
57 static void add_probe_to_list(struct probe *p)
58 {
59         hlist_add_head(&p->hlist, &list_probes);
60 }
61
62 static void remove_probe_to_list(struct probe *p)
63 {
64         hlist_del(&p->hlist);
65 }
66
67 static struct probe *find_probe(unsigned long addr)
68 {
69         struct probe *p;
70         struct hlist_node *node;
71
72         /* check if such probe does exist */
73         swap_hlist_for_each_entry(p, node, &list_probes, hlist)
74                 if (p->p.jp.kp.addr == addr)
75                         return p;
76
77         return NULL;
78 }
79
80 int ksm_register_probe(unsigned long addr, void *pre_handler,
81                        void *jp_handler, void *rp_handler)
82 {
83         int ret;
84         struct probe *p;
85
86         p = create_probe(addr, pre_handler, jp_handler, rp_handler);
87         if (!p)
88                 return -ENOMEM;
89
90         ret = dbi_register_jprobe(&p->p.jp);
91         if (ret)
92                 goto free;
93
94         ret = dbi_register_kretprobe(&p->p.rp);
95         if (ret)
96                 goto unregister_jprobe;
97
98         add_probe_to_list(p);
99         return 0;
100
101 unregister_jprobe:
102         dbi_unregister_jprobe(&p->p.jp);
103 free:
104         free_probe(p);
105         return ret;
106 }
107 EXPORT_SYMBOL_GPL(ksm_register_probe);
108
109 static void do_ksm_unregister_probe(struct probe *p)
110 {
111         remove_probe_to_list(p);
112         dbi_unregister_kretprobe(&p->p.rp);
113         dbi_unregister_jprobe(&p->p.jp);
114         free_probe(p);
115 }
116
117 int ksm_unregister_probe(unsigned long addr)
118 {
119         struct probe *p;
120
121         p = find_probe(addr);
122         if (p)
123                 return -EINVAL;
124
125         do_ksm_unregister_probe(p);
126
127         return 0;
128 }
129 EXPORT_SYMBOL_GPL(ksm_unregister_probe);
130
131 int ksm_unregister_probe_all(void)
132 {
133         struct probe *p;
134         struct hlist_node *node, *n;
135
136         swap_hlist_for_each_entry_safe(p, node, n, &list_probes, hlist) {
137                 do_ksm_unregister_probe(p);
138         }
139
140         return 0;
141 }
142 EXPORT_SYMBOL_GPL(ksm_unregister_probe_all);
143
144 static int __init init_ks_manager(void)
145 {
146        return 0;
147 }
148
149 static void __exit exit_ks_manager(void)
150 {
151         ksm_unregister_probe_all();
152 }
153
154 module_init(init_ks_manager);
155 module_exit(exit_ks_manager);
156
157 MODULE_LICENSE ("GPL");