diff options
author | Rusty Lynch <rusty.lynch@intel.com> | 2005-06-27 18:17:15 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-06-27 18:23:53 -0400 |
commit | 97f7943d70ff0e1e92ea627c44cfacfdae65dbc4 (patch) | |
tree | e2a042a3bb5014ee98551bd5d42dc3b21a42e1ec /arch/ppc64/kernel/kprobes.c | |
parent | 9508dbfe39112813612085c00d55bacd398eddc6 (diff) |
[PATCH] Return probe redesign: ppc64 specific implementation
The following is a patch provided by Ananth Mavinakayanahalli that implements
the new PPC64 specific parts of the new function return probe design.
NOTE: Since getting Ananth's patch, I changed trampoline_probe_handler()
to consume each of the outstanding return probem instances (feedback
on my original RFC after Ananth cut a patch), and also added the
arch_init() function (adding arch specific initialization.) I have
cross compiled but have not testing this on a PPC64 machine.
Changes include:
* Addition of kretprobe_trampoline to act as a dummy function for instrumented
functions to return to, and for the return probe infrastructure to place
a kprobe on on, gaining control so that the return probe handler
can be called, and so that the instruction pointer can be moved back
to the original return address.
* Addition of arch_init(), allowing a kprobe to be registered on
kretprobe_trampoline
* Addition of trampoline_probe_handler() which is used as the pre_handler
for the kprobe inserted on kretprobe_implementation. This is the function
that handles the details for calling the return probe handler function
and returning control back at the original return address
* Addition of arch_prepare_kretprobe() which is setup as the pre_handler
for a kprobe registered at the beginning of the target function by
kernel/kprobes.c so that a return probe instance can be setup when
a caller enters the target function. (A return probe instance contains
all the needed information for trampoline_probe_handler to do it's job.)
* Hooks added to the exit path of a task so that we can cleanup any left-over
return probe instances (i.e. if a task dies while inside a targeted function
then the return probe instance was reserved at the beginning of the function
but the function never returns so we need to mark the instance as unused.)
Signed-off-by: Rusty Lynch <rusty.lynch@intel.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/ppc64/kernel/kprobes.c')
-rw-r--r-- | arch/ppc64/kernel/kprobes.c | 99 |
1 files changed, 99 insertions, 0 deletions
diff --git a/arch/ppc64/kernel/kprobes.c b/arch/ppc64/kernel/kprobes.c index 86cc5496db9f..1d2ff6d6b0b3 100644 --- a/arch/ppc64/kernel/kprobes.c +++ b/arch/ppc64/kernel/kprobes.c | |||
@@ -122,6 +122,23 @@ static inline void restore_previous_kprobe(void) | |||
122 | kprobe_saved_msr = kprobe_saved_msr_prev; | 122 | kprobe_saved_msr = kprobe_saved_msr_prev; |
123 | } | 123 | } |
124 | 124 | ||
125 | void arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs) | ||
126 | { | ||
127 | struct kretprobe_instance *ri; | ||
128 | |||
129 | if ((ri = get_free_rp_inst(rp)) != NULL) { | ||
130 | ri->rp = rp; | ||
131 | ri->task = current; | ||
132 | ri->ret_addr = (kprobe_opcode_t *)regs->link; | ||
133 | |||
134 | /* Replace the return addr with trampoline addr */ | ||
135 | regs->link = (unsigned long)kretprobe_trampoline; | ||
136 | add_rp_inst(ri); | ||
137 | } else { | ||
138 | rp->nmissed++; | ||
139 | } | ||
140 | } | ||
141 | |||
125 | static inline int kprobe_handler(struct pt_regs *regs) | 142 | static inline int kprobe_handler(struct pt_regs *regs) |
126 | { | 143 | { |
127 | struct kprobe *p; | 144 | struct kprobe *p; |
@@ -212,6 +229,78 @@ no_kprobe: | |||
212 | } | 229 | } |
213 | 230 | ||
214 | /* | 231 | /* |
232 | * Function return probe trampoline: | ||
233 | * - init_kprobes() establishes a probepoint here | ||
234 | * - When the probed function returns, this probe | ||
235 | * causes the handlers to fire | ||
236 | */ | ||
237 | void kretprobe_trampoline_holder(void) | ||
238 | { | ||
239 | asm volatile(".global kretprobe_trampoline\n" | ||
240 | "kretprobe_trampoline:\n" | ||
241 | "nop\n"); | ||
242 | } | ||
243 | |||
244 | /* | ||
245 | * Called when the probe at kretprobe trampoline is hit | ||
246 | */ | ||
247 | int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) | ||
248 | { | ||
249 | struct kretprobe_instance *ri = NULL; | ||
250 | struct hlist_head *head; | ||
251 | struct hlist_node *node, *tmp; | ||
252 | unsigned long orig_ret_address = 0; | ||
253 | unsigned long trampoline_address =(unsigned long)&kretprobe_trampoline; | ||
254 | |||
255 | head = kretprobe_inst_table_head(current); | ||
256 | |||
257 | /* | ||
258 | * It is possible to have multiple instances associated with a given | ||
259 | * task either because an multiple functions in the call path | ||
260 | * have a return probe installed on them, and/or more then one return | ||
261 | * return probe was registered for a target function. | ||
262 | * | ||
263 | * We can handle this because: | ||
264 | * - instances are always inserted at the head of the list | ||
265 | * - when multiple return probes are registered for the same | ||
266 | * function, the first instance's ret_addr will point to the | ||
267 | * real return address, and all the rest will point to | ||
268 | * kretprobe_trampoline | ||
269 | */ | ||
270 | hlist_for_each_entry_safe(ri, node, tmp, head, hlist) { | ||
271 | if (ri->task != current) | ||
272 | /* another task is sharing our hash bucket */ | ||
273 | continue; | ||
274 | |||
275 | if (ri->rp && ri->rp->handler) | ||
276 | ri->rp->handler(ri, regs); | ||
277 | |||
278 | orig_ret_address = (unsigned long)ri->ret_addr; | ||
279 | recycle_rp_inst(ri); | ||
280 | |||
281 | if (orig_ret_address != trampoline_address) | ||
282 | /* | ||
283 | * This is the real return address. Any other | ||
284 | * instances associated with this task are for | ||
285 | * other calls deeper on the call stack | ||
286 | */ | ||
287 | break; | ||
288 | } | ||
289 | |||
290 | BUG_ON(!orig_ret_address || (orig_ret_address == trampoline_address)); | ||
291 | regs->nip = orig_ret_address; | ||
292 | |||
293 | unlock_kprobes(); | ||
294 | |||
295 | /* | ||
296 | * By returning a non-zero value, we are telling | ||
297 | * kprobe_handler() that we have handled unlocking | ||
298 | * and re-enabling preemption. | ||
299 | */ | ||
300 | return 1; | ||
301 | } | ||
302 | |||
303 | /* | ||
215 | * Called after single-stepping. p->addr is the address of the | 304 | * Called after single-stepping. p->addr is the address of the |
216 | * instruction whose first byte has been replaced by the "breakpoint" | 305 | * instruction whose first byte has been replaced by the "breakpoint" |
217 | * instruction. To avoid the SMP problems that can occur when we | 306 | * instruction. To avoid the SMP problems that can occur when we |
@@ -349,3 +438,13 @@ int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) | |||
349 | memcpy(regs, &jprobe_saved_regs, sizeof(struct pt_regs)); | 438 | memcpy(regs, &jprobe_saved_regs, sizeof(struct pt_regs)); |
350 | return 1; | 439 | return 1; |
351 | } | 440 | } |
441 | |||
442 | static struct kprobe trampoline_p = { | ||
443 | .addr = (kprobe_opcode_t *) &kretprobe_trampoline, | ||
444 | .pre_handler = trampoline_probe_handler | ||
445 | }; | ||
446 | |||
447 | int __init arch_init(void) | ||
448 | { | ||
449 | return register_kprobe(&trampoline_p); | ||
450 | } | ||