diff options
-rw-r--r-- | include/linux/kprobes.h | 28 | ||||
-rw-r--r-- | kernel/kprobes.c | 69 |
2 files changed, 22 insertions, 75 deletions
diff --git a/include/linux/kprobes.h b/include/linux/kprobes.h index d304d4579856..b7a194c4362a 100644 --- a/include/linux/kprobes.h +++ b/include/linux/kprobes.h | |||
@@ -104,33 +104,12 @@ struct jprobe { | |||
104 | }; | 104 | }; |
105 | 105 | ||
106 | #ifdef ARCH_SUPPORTS_KRETPROBES | 106 | #ifdef ARCH_SUPPORTS_KRETPROBES |
107 | extern int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs); | ||
108 | extern void trampoline_post_handler(struct kprobe *p, struct pt_regs *regs, | ||
109 | unsigned long flags); | ||
110 | extern struct task_struct *arch_get_kprobe_task(void *ptr); | ||
111 | extern void arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs); | 107 | extern void arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs); |
112 | extern void arch_kprobe_flush_task(struct task_struct *tk); | ||
113 | #else /* ARCH_SUPPORTS_KRETPROBES */ | 108 | #else /* ARCH_SUPPORTS_KRETPROBES */ |
114 | static inline void kretprobe_trampoline(void) | ||
115 | { | ||
116 | } | ||
117 | static inline int trampoline_probe_handler(struct kprobe *p, | ||
118 | struct pt_regs *regs) | ||
119 | { | ||
120 | return 0; | ||
121 | } | ||
122 | static inline void trampoline_post_handler(struct kprobe *p, | ||
123 | struct pt_regs *regs, unsigned long flags) | ||
124 | { | ||
125 | } | ||
126 | static inline void arch_prepare_kretprobe(struct kretprobe *rp, | 109 | static inline void arch_prepare_kretprobe(struct kretprobe *rp, |
127 | struct pt_regs *regs) | 110 | struct pt_regs *regs) |
128 | { | 111 | { |
129 | } | 112 | } |
130 | static inline void arch_kprobe_flush_task(struct task_struct *tk) | ||
131 | { | ||
132 | } | ||
133 | #define arch_get_kprobe_task(ptr) ((struct task_struct *)NULL) | ||
134 | #endif /* ARCH_SUPPORTS_KRETPROBES */ | 113 | #endif /* ARCH_SUPPORTS_KRETPROBES */ |
135 | /* | 114 | /* |
136 | * Function-return probe - | 115 | * Function-return probe - |
@@ -155,8 +134,8 @@ struct kretprobe_instance { | |||
155 | struct hlist_node uflist; /* either on free list or used list */ | 134 | struct hlist_node uflist; /* either on free list or used list */ |
156 | struct hlist_node hlist; | 135 | struct hlist_node hlist; |
157 | struct kretprobe *rp; | 136 | struct kretprobe *rp; |
158 | void *ret_addr; | 137 | kprobe_opcode_t *ret_addr; |
159 | void *stack_addr; | 138 | struct task_struct *task; |
160 | }; | 139 | }; |
161 | 140 | ||
162 | #ifdef CONFIG_KPROBES | 141 | #ifdef CONFIG_KPROBES |
@@ -176,6 +155,7 @@ extern void arch_copy_kprobe(struct kprobe *p); | |||
176 | extern void arch_arm_kprobe(struct kprobe *p); | 155 | extern void arch_arm_kprobe(struct kprobe *p); |
177 | extern void arch_disarm_kprobe(struct kprobe *p); | 156 | extern void arch_disarm_kprobe(struct kprobe *p); |
178 | extern void arch_remove_kprobe(struct kprobe *p); | 157 | extern void arch_remove_kprobe(struct kprobe *p); |
158 | extern int arch_init(void); | ||
179 | extern void show_registers(struct pt_regs *regs); | 159 | extern void show_registers(struct pt_regs *regs); |
180 | extern kprobe_opcode_t *get_insn_slot(void); | 160 | extern kprobe_opcode_t *get_insn_slot(void); |
181 | extern void free_insn_slot(kprobe_opcode_t *slot); | 161 | extern void free_insn_slot(kprobe_opcode_t *slot); |
@@ -196,8 +176,6 @@ int register_kretprobe(struct kretprobe *rp); | |||
196 | void unregister_kretprobe(struct kretprobe *rp); | 176 | void unregister_kretprobe(struct kretprobe *rp); |
197 | 177 | ||
198 | struct kretprobe_instance *get_free_rp_inst(struct kretprobe *rp); | 178 | struct kretprobe_instance *get_free_rp_inst(struct kretprobe *rp); |
199 | struct kretprobe_instance *get_rp_inst(void *sara); | ||
200 | struct kretprobe_instance *get_rp_inst_tsk(struct task_struct *tk); | ||
201 | void add_rp_inst(struct kretprobe_instance *ri); | 179 | void add_rp_inst(struct kretprobe_instance *ri); |
202 | void kprobe_flush_task(struct task_struct *tk); | 180 | void kprobe_flush_task(struct task_struct *tk); |
203 | void recycle_rp_inst(struct kretprobe_instance *ri); | 181 | void recycle_rp_inst(struct kretprobe_instance *ri); |
diff --git a/kernel/kprobes.c b/kernel/kprobes.c index 65242529a75f..90c0e82b650c 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c | |||
@@ -240,12 +240,6 @@ static int aggr_break_handler(struct kprobe *p, struct pt_regs *regs) | |||
240 | return 0; | 240 | return 0; |
241 | } | 241 | } |
242 | 242 | ||
243 | struct kprobe trampoline_p = { | ||
244 | .addr = (kprobe_opcode_t *) &kretprobe_trampoline, | ||
245 | .pre_handler = trampoline_probe_handler, | ||
246 | .post_handler = trampoline_post_handler | ||
247 | }; | ||
248 | |||
249 | struct kretprobe_instance *get_free_rp_inst(struct kretprobe *rp) | 243 | struct kretprobe_instance *get_free_rp_inst(struct kretprobe *rp) |
250 | { | 244 | { |
251 | struct hlist_node *node; | 245 | struct hlist_node *node; |
@@ -264,35 +258,18 @@ static struct kretprobe_instance *get_used_rp_inst(struct kretprobe *rp) | |||
264 | return NULL; | 258 | return NULL; |
265 | } | 259 | } |
266 | 260 | ||
267 | struct kretprobe_instance *get_rp_inst(void *sara) | ||
268 | { | ||
269 | struct hlist_head *head; | ||
270 | struct hlist_node *node; | ||
271 | struct task_struct *tsk; | ||
272 | struct kretprobe_instance *ri; | ||
273 | |||
274 | tsk = arch_get_kprobe_task(sara); | ||
275 | head = &kretprobe_inst_table[hash_ptr(tsk, KPROBE_HASH_BITS)]; | ||
276 | hlist_for_each_entry(ri, node, head, hlist) { | ||
277 | if (ri->stack_addr == sara) | ||
278 | return ri; | ||
279 | } | ||
280 | return NULL; | ||
281 | } | ||
282 | |||
283 | void add_rp_inst(struct kretprobe_instance *ri) | 261 | void add_rp_inst(struct kretprobe_instance *ri) |
284 | { | 262 | { |
285 | struct task_struct *tsk; | ||
286 | /* | 263 | /* |
287 | * Remove rp inst off the free list - | 264 | * Remove rp inst off the free list - |
288 | * Add it back when probed function returns | 265 | * Add it back when probed function returns |
289 | */ | 266 | */ |
290 | hlist_del(&ri->uflist); | 267 | hlist_del(&ri->uflist); |
291 | tsk = arch_get_kprobe_task(ri->stack_addr); | 268 | |
292 | /* Add rp inst onto table */ | 269 | /* Add rp inst onto table */ |
293 | INIT_HLIST_NODE(&ri->hlist); | 270 | INIT_HLIST_NODE(&ri->hlist); |
294 | hlist_add_head(&ri->hlist, | 271 | hlist_add_head(&ri->hlist, |
295 | &kretprobe_inst_table[hash_ptr(tsk, KPROBE_HASH_BITS)]); | 272 | &kretprobe_inst_table[hash_ptr(ri->task, KPROBE_HASH_BITS)]); |
296 | 273 | ||
297 | /* Also add this rp inst to the used list. */ | 274 | /* Also add this rp inst to the used list. */ |
298 | INIT_HLIST_NODE(&ri->uflist); | 275 | INIT_HLIST_NODE(&ri->uflist); |
@@ -319,34 +296,25 @@ struct hlist_head * kretprobe_inst_table_head(struct task_struct *tsk) | |||
319 | return &kretprobe_inst_table[hash_ptr(tsk, KPROBE_HASH_BITS)]; | 296 | return &kretprobe_inst_table[hash_ptr(tsk, KPROBE_HASH_BITS)]; |
320 | } | 297 | } |
321 | 298 | ||
322 | struct kretprobe_instance *get_rp_inst_tsk(struct task_struct *tk) | ||
323 | { | ||
324 | struct task_struct *tsk; | ||
325 | struct hlist_head *head; | ||
326 | struct hlist_node *node; | ||
327 | struct kretprobe_instance *ri; | ||
328 | |||
329 | head = &kretprobe_inst_table[hash_ptr(tk, KPROBE_HASH_BITS)]; | ||
330 | |||
331 | hlist_for_each_entry(ri, node, head, hlist) { | ||
332 | tsk = arch_get_kprobe_task(ri->stack_addr); | ||
333 | if (tsk == tk) | ||
334 | return ri; | ||
335 | } | ||
336 | return NULL; | ||
337 | } | ||
338 | |||
339 | /* | 299 | /* |
340 | * This function is called from do_exit or do_execv when task tk's stack is | 300 | * This function is called from exit_thread or flush_thread when task tk's |
341 | * about to be recycled. Recycle any function-return probe instances | 301 | * stack is being recycled so that we can recycle any function-return probe |
342 | * associated with this task. These represent probed functions that have | 302 | * instances associated with this task. These left over instances represent |
343 | * been called but may never return. | 303 | * probed functions that have been called but will never return. |
344 | */ | 304 | */ |
345 | void kprobe_flush_task(struct task_struct *tk) | 305 | void kprobe_flush_task(struct task_struct *tk) |
346 | { | 306 | { |
307 | struct kretprobe_instance *ri; | ||
308 | struct hlist_head *head; | ||
309 | struct hlist_node *node, *tmp; | ||
347 | unsigned long flags = 0; | 310 | unsigned long flags = 0; |
311 | |||
348 | spin_lock_irqsave(&kprobe_lock, flags); | 312 | spin_lock_irqsave(&kprobe_lock, flags); |
349 | arch_kprobe_flush_task(tk); | 313 | head = kretprobe_inst_table_head(current); |
314 | hlist_for_each_entry_safe(ri, node, tmp, head, hlist) { | ||
315 | if (ri->task == tk) | ||
316 | recycle_rp_inst(ri); | ||
317 | } | ||
350 | spin_unlock_irqrestore(&kprobe_lock, flags); | 318 | spin_unlock_irqrestore(&kprobe_lock, flags); |
351 | } | 319 | } |
352 | 320 | ||
@@ -606,9 +574,10 @@ static int __init init_kprobes(void) | |||
606 | INIT_HLIST_HEAD(&kretprobe_inst_table[i]); | 574 | INIT_HLIST_HEAD(&kretprobe_inst_table[i]); |
607 | } | 575 | } |
608 | 576 | ||
609 | err = register_die_notifier(&kprobe_exceptions_nb); | 577 | err = arch_init(); |
610 | /* Register the trampoline probe for return probe */ | 578 | if (!err) |
611 | register_kprobe(&trampoline_p); | 579 | err = register_die_notifier(&kprobe_exceptions_nb); |
580 | |||
612 | return err; | 581 | return err; |
613 | } | 582 | } |
614 | 583 | ||