• Rusty Lynch's avatar
    [PATCH] x86_64 specific function return probes · 73649dab
    Rusty Lynch authored
    The following patch adds the x86_64 architecture specific implementation
    for function return probes.
    
    Function return probes is a mechanism built on top of kprobes that allows
    a caller to register a handler to be called when a given function exits.
    For example, to instrument the return path of sys_mkdir:
    
    static int sys_mkdir_exit(struct kretprobe_instance *i, struct pt_regs *regs)
    {
    	printk("sys_mkdir exited\n");
    	return 0;
    }
    static struct kretprobe return_probe = {
    	.handler = sys_mkdir_exit,
    };
    
    <inside setup function>
    
    return_probe.kp.addr = (kprobe_opcode_t *) kallsyms_lookup_name("sys_mkdir");
    if (register_kretprobe(&return_probe)) {
    	printk(KERN_DEBUG "Unable to register return probe!\n");
    	/* do error path */
    }
    
    <inside cleanup function>
    unregister_kretprobe(&return_probe);
    
    The way this works is that:
    
    * At system initialization time, kernel/kprobes.c installs a kprobe
      on a function called kretprobe_trampoline() that is implemented in
      the arch/x86_64/kernel/kprobes.c  (More on this later)
    
    * When a return probe is registered using register_kretprobe(),
      kernel/kprobes.c will install a kprobe on the first instruction of the
      targeted function with the pre handler set to arch_prepare_kretprobe()
      which is implemented in arch/x86_64/kernel/kprobes.c.
    
    * arch_prepare_kretprobe() will prepare a kretprobe instance that stores:
      - nodes for hanging this instance in an empty or free list
      - a pointer to the return probe
      - the original return address
      - a pointer to the stack address
    
      With all this stowed away, arch_prepare_kretprobe() then sets the return
      address for the targeted function to a special trampoline function called
      kretprobe_trampoline() implemented in arch/x86_64/kernel/kprobes.c
    
    * The kprobe completes as normal, with control passing back to the target
      function that executes as normal, and eventually returns to our trampoline
      function.
    
    * Since a kprobe was installed on kretprobe_trampoline() during system
      initialization, control passes back to kprobes via the architecture
      specific function trampoline_probe_handler() which will lookup the
      instance in an hlist maintained by kernel/kprobes.c, and then call
      the handler function.
    
    * When trampoline_probe_handler() is done, the kprobes infrastructure
      single steps the original instruction (in this case just a top), and
      then calls trampoline_post_handler().  trampoline_post_handler() then
      looks up the instance again, puts the instance back on the free list,
      and then makes a long jump back to the original return instruction.
    
    So to recap, to instrument the exit path of a function this implementation
    will cause four interruptions:
    
      - A breakpoint at the very beginning of the function allowing us to
        switch out the return address
      - A single step interruption to execute the original instruction that
        we replaced with the break instruction (normal kprobe flow)
      - A breakpoint in the trampoline function where our instrumented function
        returned to
      - A single step interruption to execute the original instruction that
        we replaced with the break instruction (normal kprobe flow)
    Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
    Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
    73649dab
kprobes.c 21.2 KB