aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/kprobes.c
diff options
context:
space:
mode:
authorPrasanna S Panchamukhi <prasanna@in.ibm.com>2005-06-23 03:09:41 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-06-23 12:45:25 -0400
commit8b0914ea7475615c7c8965c1ac8fe4069270f25c (patch)
treefb85ed3b08d9c61090bbc9dee9d06f54b945e52a /kernel/kprobes.c
parent852caccc89d3883522e87a91bfa89fd9c9cfe15a (diff)
[PATCH] jprobes: allow a jprobe to coexist with muliple kprobes
Presently either multiple kprobes or only one jprobe could be inserted. This patch removes the above limitation and allows one jprobe and multiple kprobes to coexist at the same address. However multiple jprobes cannot coexist with multiple kprobes. Currently I am working on the prototype to allow multiple jprobes coexist with multiple kprobes. Signed-off-by: Ananth N Mavinakayanhalli <amavin@redhat.com> Signed-off-by: Prasanna S Panchamukhi <prasanna@in.ibm.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'kernel/kprobes.c')
-rw-r--r--kernel/kprobes.c61
1 files changed, 51 insertions, 10 deletions
diff --git a/kernel/kprobes.c b/kernel/kprobes.c
index 456ecedff2d4..334f37472c56 100644
--- a/kernel/kprobes.c
+++ b/kernel/kprobes.c
@@ -89,9 +89,10 @@ static int aggr_pre_handler(struct kprobe *p, struct pt_regs *regs)
89 list_for_each_entry(kp, &p->list, list) { 89 list_for_each_entry(kp, &p->list, list) {
90 if (kp->pre_handler) { 90 if (kp->pre_handler) {
91 curr_kprobe = kp; 91 curr_kprobe = kp;
92 kp->pre_handler(kp, regs); 92 if (kp->pre_handler(kp, regs))
93 curr_kprobe = NULL; 93 return 1;
94 } 94 }
95 curr_kprobe = NULL;
95 } 96 }
96 return 0; 97 return 0;
97} 98}
@@ -125,6 +126,19 @@ static int aggr_fault_handler(struct kprobe *p, struct pt_regs *regs,
125 return 0; 126 return 0;
126} 127}
127 128
129static int aggr_break_handler(struct kprobe *p, struct pt_regs *regs)
130{
131 struct kprobe *kp = curr_kprobe;
132 if (curr_kprobe && kp->break_handler) {
133 if (kp->break_handler(kp, regs)) {
134 curr_kprobe = NULL;
135 return 1;
136 }
137 }
138 curr_kprobe = NULL;
139 return 0;
140}
141
128struct kprobe trampoline_p = { 142struct kprobe trampoline_p = {
129 .addr = (kprobe_opcode_t *) &kretprobe_trampoline, 143 .addr = (kprobe_opcode_t *) &kretprobe_trampoline,
130 .pre_handler = trampoline_probe_handler, 144 .pre_handler = trampoline_probe_handler,
@@ -258,18 +272,45 @@ static inline void free_rp_inst(struct kretprobe *rp)
258} 272}
259 273
260/* 274/*
275 * Keep all fields in the kprobe consistent
276 */
277static inline void copy_kprobe(struct kprobe *old_p, struct kprobe *p)
278{
279 memcpy(&p->opcode, &old_p->opcode, sizeof(kprobe_opcode_t));
280 memcpy(&p->ainsn, &old_p->ainsn, sizeof(struct arch_specific_insn));
281}
282
283/*
284* Add the new probe to old_p->list. Fail if this is the
285* second jprobe at the address - two jprobes can't coexist
286*/
287static int add_new_kprobe(struct kprobe *old_p, struct kprobe *p)
288{
289 struct kprobe *kp;
290
291 if (p->break_handler) {
292 list_for_each_entry(kp, &old_p->list, list) {
293 if (kp->break_handler)
294 return -EEXIST;
295 }
296 list_add_tail(&p->list, &old_p->list);
297 } else
298 list_add(&p->list, &old_p->list);
299 return 0;
300}
301
302/*
261 * Fill in the required fields of the "manager kprobe". Replace the 303 * Fill in the required fields of the "manager kprobe". Replace the
262 * earlier kprobe in the hlist with the manager kprobe 304 * earlier kprobe in the hlist with the manager kprobe
263 */ 305 */
264static inline void add_aggr_kprobe(struct kprobe *ap, struct kprobe *p) 306static inline void add_aggr_kprobe(struct kprobe *ap, struct kprobe *p)
265{ 307{
308 copy_kprobe(p, ap);
266 ap->addr = p->addr; 309 ap->addr = p->addr;
267 memcpy(&ap->opcode, &p->opcode, sizeof(kprobe_opcode_t));
268 memcpy(&ap->ainsn, &p->ainsn, sizeof(struct arch_specific_insn));
269
270 ap->pre_handler = aggr_pre_handler; 310 ap->pre_handler = aggr_pre_handler;
271 ap->post_handler = aggr_post_handler; 311 ap->post_handler = aggr_post_handler;
272 ap->fault_handler = aggr_fault_handler; 312 ap->fault_handler = aggr_fault_handler;
313 ap->break_handler = aggr_break_handler;
273 314
274 INIT_LIST_HEAD(&ap->list); 315 INIT_LIST_HEAD(&ap->list);
275 list_add(&p->list, &ap->list); 316 list_add(&p->list, &ap->list);
@@ -290,16 +331,16 @@ static int register_aggr_kprobe(struct kprobe *old_p, struct kprobe *p)
290 int ret = 0; 331 int ret = 0;
291 struct kprobe *ap; 332 struct kprobe *ap;
292 333
293 if (old_p->break_handler || p->break_handler) { 334 if (old_p->pre_handler == aggr_pre_handler) {
294 ret = -EEXIST; /* kprobe and jprobe can't (yet) coexist */ 335 copy_kprobe(old_p, p);
295 } else if (old_p->pre_handler == aggr_pre_handler) { 336 ret = add_new_kprobe(old_p, p);
296 list_add(&p->list, &old_p->list);
297 } else { 337 } else {
298 ap = kcalloc(1, sizeof(struct kprobe), GFP_ATOMIC); 338 ap = kcalloc(1, sizeof(struct kprobe), GFP_ATOMIC);
299 if (!ap) 339 if (!ap)
300 return -ENOMEM; 340 return -ENOMEM;
301 add_aggr_kprobe(ap, old_p); 341 add_aggr_kprobe(ap, old_p);
302 list_add(&p->list, &ap->list); 342 copy_kprobe(ap, p);
343 ret = add_new_kprobe(ap, p);
303 } 344 }
304 return ret; 345 return ret;
305} 346}