aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/kprobes.c
diff options
context:
space:
mode:
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}