mirror of
https://github.com/adulau/aha.git
synced 2024-12-28 03:36:19 +00:00
[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>
This commit is contained in:
parent
852caccc89
commit
8b0914ea74
1 changed files with 51 additions and 10 deletions
|
@ -89,9 +89,10 @@ static int aggr_pre_handler(struct kprobe *p, struct pt_regs *regs)
|
||||||
list_for_each_entry(kp, &p->list, list) {
|
list_for_each_entry(kp, &p->list, list) {
|
||||||
if (kp->pre_handler) {
|
if (kp->pre_handler) {
|
||||||
curr_kprobe = kp;
|
curr_kprobe = kp;
|
||||||
kp->pre_handler(kp, regs);
|
if (kp->pre_handler(kp, regs))
|
||||||
curr_kprobe = NULL;
|
return 1;
|
||||||
}
|
}
|
||||||
|
curr_kprobe = NULL;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -125,6 +126,19 @@ static int aggr_fault_handler(struct kprobe *p, struct pt_regs *regs,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int aggr_break_handler(struct kprobe *p, struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
struct kprobe *kp = curr_kprobe;
|
||||||
|
if (curr_kprobe && kp->break_handler) {
|
||||||
|
if (kp->break_handler(kp, regs)) {
|
||||||
|
curr_kprobe = NULL;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
curr_kprobe = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
struct kprobe trampoline_p = {
|
struct kprobe trampoline_p = {
|
||||||
.addr = (kprobe_opcode_t *) &kretprobe_trampoline,
|
.addr = (kprobe_opcode_t *) &kretprobe_trampoline,
|
||||||
.pre_handler = trampoline_probe_handler,
|
.pre_handler = trampoline_probe_handler,
|
||||||
|
@ -257,19 +271,46 @@ static inline void free_rp_inst(struct kretprobe *rp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Keep all fields in the kprobe consistent
|
||||||
|
*/
|
||||||
|
static inline void copy_kprobe(struct kprobe *old_p, struct kprobe *p)
|
||||||
|
{
|
||||||
|
memcpy(&p->opcode, &old_p->opcode, sizeof(kprobe_opcode_t));
|
||||||
|
memcpy(&p->ainsn, &old_p->ainsn, sizeof(struct arch_specific_insn));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add the new probe to old_p->list. Fail if this is the
|
||||||
|
* second jprobe at the address - two jprobes can't coexist
|
||||||
|
*/
|
||||||
|
static int add_new_kprobe(struct kprobe *old_p, struct kprobe *p)
|
||||||
|
{
|
||||||
|
struct kprobe *kp;
|
||||||
|
|
||||||
|
if (p->break_handler) {
|
||||||
|
list_for_each_entry(kp, &old_p->list, list) {
|
||||||
|
if (kp->break_handler)
|
||||||
|
return -EEXIST;
|
||||||
|
}
|
||||||
|
list_add_tail(&p->list, &old_p->list);
|
||||||
|
} else
|
||||||
|
list_add(&p->list, &old_p->list);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Fill in the required fields of the "manager kprobe". Replace the
|
* Fill in the required fields of the "manager kprobe". Replace the
|
||||||
* earlier kprobe in the hlist with the manager kprobe
|
* earlier kprobe in the hlist with the manager kprobe
|
||||||
*/
|
*/
|
||||||
static inline void add_aggr_kprobe(struct kprobe *ap, struct kprobe *p)
|
static inline void add_aggr_kprobe(struct kprobe *ap, struct kprobe *p)
|
||||||
{
|
{
|
||||||
|
copy_kprobe(p, ap);
|
||||||
ap->addr = p->addr;
|
ap->addr = p->addr;
|
||||||
memcpy(&ap->opcode, &p->opcode, sizeof(kprobe_opcode_t));
|
|
||||||
memcpy(&ap->ainsn, &p->ainsn, sizeof(struct arch_specific_insn));
|
|
||||||
|
|
||||||
ap->pre_handler = aggr_pre_handler;
|
ap->pre_handler = aggr_pre_handler;
|
||||||
ap->post_handler = aggr_post_handler;
|
ap->post_handler = aggr_post_handler;
|
||||||
ap->fault_handler = aggr_fault_handler;
|
ap->fault_handler = aggr_fault_handler;
|
||||||
|
ap->break_handler = aggr_break_handler;
|
||||||
|
|
||||||
INIT_LIST_HEAD(&ap->list);
|
INIT_LIST_HEAD(&ap->list);
|
||||||
list_add(&p->list, &ap->list);
|
list_add(&p->list, &ap->list);
|
||||||
|
@ -290,16 +331,16 @@ static int register_aggr_kprobe(struct kprobe *old_p, struct kprobe *p)
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
struct kprobe *ap;
|
struct kprobe *ap;
|
||||||
|
|
||||||
if (old_p->break_handler || p->break_handler) {
|
if (old_p->pre_handler == aggr_pre_handler) {
|
||||||
ret = -EEXIST; /* kprobe and jprobe can't (yet) coexist */
|
copy_kprobe(old_p, p);
|
||||||
} else if (old_p->pre_handler == aggr_pre_handler) {
|
ret = add_new_kprobe(old_p, p);
|
||||||
list_add(&p->list, &old_p->list);
|
|
||||||
} else {
|
} else {
|
||||||
ap = kcalloc(1, sizeof(struct kprobe), GFP_ATOMIC);
|
ap = kcalloc(1, sizeof(struct kprobe), GFP_ATOMIC);
|
||||||
if (!ap)
|
if (!ap)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
add_aggr_kprobe(ap, old_p);
|
add_aggr_kprobe(ap, old_p);
|
||||||
list_add(&p->list, &ap->list);
|
copy_kprobe(ap, p);
|
||||||
|
ret = add_new_kprobe(ap, p);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue