Skip to contentSkip to conversation

Kernel probes for i386 2.5.26

PATCH In review Rusty Russell 2 participants 2 messages Jul 20, 2002 – Jul 25, 2002

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 Kernel probes for i386 2.5.26

Hi Linus,

This is a neat patch by Vamsi which allows code to trap on
kernel instructions. The IBM guys have stuff for non-intrusive testing, debugging, instrumentation on top of this. It's also nice to insert assertions in core code without having to reboot 8)

Thanks,
Rusty.
--
Anyone who quotes me in their sig is an idiot. -- Rusty Russell.

Name: Cache Align Cleanup Patch
Author: Vamsi Krishna S
Status: Tested on 2.5.26 SMP

D: This patch allows trapping at almost any kernel address, useful for
D: various kernel-hacking tasks, and building on for more
D: infrastructure. This patch is x86 only.

include/asm-i386/kprobes.h +63 -0
diff -urpN -I \$.*\$ --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal linux-2.5.26/include/asm-i386/kprobes.h working-2.5.26-kprobes/include/asm-i386/kprobes.h
@@ -0,0 +1,63 @@
+#ifndef _ASM_KPROBES_H
+#define _ASM_KPROBES_H
+/*
+ *  Dynamic Probes (kprobes) support
+ *  	Vamsi Krishna S <[email protected]>, July, 2002
+ *	Mailing list: [email protected]
+ */
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/percpu.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/ptrace.h>
+
+struct kprobe;
+
+typedef void (*kprobe_pre_handler_t)(struct kprobe *, struct pt_regs *);
+typedef void (*kprobe_post_handler_t)(struct kprobe *, struct pt_regs *,
+				      unsigned long flags);
+typedef int (*kprobe_fault_handler_t)(struct kprobe *, struct pt_regs *,
+				      int trapnr);
+
+struct kprobe {
+	u8 * addr;	/* location of the probe point */
+	struct list_head list;
+	unsigned long status;
+	 /* Called before addr is executed. */
+	kprobe_pre_handler_t pre_handler;
+	/* Called after addr is executed, unless... */
+	kprobe_post_handler_t post_handler;
+	 /* ... called if executing addr causes a fault (eg. page fault).
+	  * Return 1 if it handled fault, otherwise kernel will see it. */
+	kprobe_fault_handler_t fault_handler;
+	u8 opcode;
+};
+
+/* Set to cpu currently running a probe hit */
+extern unsigned int kprobe_cpu;
+
+#define BREAKPOINT_INSTRUCTION	0xcc
+#define EF_TF	0x00000100
+#define EF_IE	0x00000200
+
+#ifdef CONFIG_KPROBES
+extern int register_kprobe(struct kprobe *p);
+extern void unregister_kprobe(struct kprobe *p);
+
+extern int kprobe_fault_handler(struct pt_regs * regs, int trapnr);
+
+static inline int kprobe_fault(struct pt_regs *regs, int trapnr)
+{
+	if (kprobe_cpu == smp_processor_id()
+	    && kprobe_fault_handler(regs, trapnr))
+		return 1;
+	return 0;
+}
+#else /* ! CONFIG_KPROBES */
+static inline int register_kprobe(struct probe_struct *p) { return -ENOSYS; }
+static inline void unregister_kprobe(struct probe_struct *p) { }
+static inline int kprobe_fault(struct pt_regs *regs, int trapnr) { return 0; }
+#endif
+
+#endif /* _ASM_KPROBES_H */
arch/i386/Config.help +6 -0
diff -urpN -I \$.*\$ --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal linux-2.5.26/arch/i386/Config.help working-2.5.26-kprobes/arch/i386/Config.help
@@ -967,3 +967,9 @@ CONFIG_SOFTWARE_SUSPEND
   absence of features.
 
   For more information take a look at Documentation/swsusp.txt.
+
+CONFIG_KPROBES
+  Kprobes allows you to trap at almost any kernel address, using
+  register_kprobe(), and providing a callback function.  This is useful
+  for kernel debugging, non-intrusive instrumentation and testing.  If
+  in doubt, say "N".
arch/i386/config.in +1 -0
diff -urpN -I \$.*\$ --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal linux-2.5.26/arch/i386/config.in working-2.5.26-kprobes/arch/i386/config.in
@@ -419,6 +419,7 @@ if [ "$CONFIG_DEBUG_KERNEL" != "n" ]; th
    if [ "$CONFIG_HIGHMEM" = "y" ]; then
       bool '  Highmem debugging' CONFIG_DEBUG_HIGHMEM
    fi
+   bool '  Probes' CONFIG_KPROBES
 fi
 
 endmenu
arch/i386/kernel/entry.S +30 -0
diff -urpN -I \$.*\$ --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal linux-2.5.26/arch/i386/kernel/entry.S working-2.5.26-kprobes/arch/i386/kernel/entry.S
@@ -442,9 +442,24 @@ device_not_available_emulate:
 	jmp ret_from_exception
 
 ENTRY(debug)
+#ifdef CONFIG_KPROBES
+	pushl %eax
+	SAVE_ALL
+	GET_THREAD_INFO(%ebx)
+	movl %esp,%edx
+	pushl $0
+	pushl %edx
+	call do_debug
+	addl $8,%esp
+	cmpl $0,%eax 
+	jnz restore_all
+	preempt_stop
+	jmp ret_from_exception
+#else
 	pushl $0
 	pushl $do_debug
 	jmp error_code
+#endif
 
 ENTRY(nmi)
 	pushl %eax
@@ -457,9 +472,24 @@ ENTRY(nmi)
 	RESTORE_ALL
 
 ENTRY(int3)
+#ifdef CONFIG_KPROBES
+	pushl %eax
+	SAVE_ALL
+	GET_THREAD_INFO(%ebx)
+	movl %esp,%edx
+	pushl $0
+	pushl %edx
+	call do_int3
+	addl $8,%esp
+	cmpl $0,%eax 
+	jnz restore_all
+	preempt_stop
+	jmp ret_from_exception
+#else
 	pushl $0
 	pushl $do_int3
 	jmp error_code
+#endif
 
 ENTRY(overflow)
 	pushl $0
arch/i386/kernel/i386_ksyms.c +6 -0
diff -urpN -I \$.*\$ --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal linux-2.5.26/arch/i386/kernel/i386_ksyms.c working-2.5.26-kprobes/arch/i386/kernel/i386_ksyms.c
@@ -29,6 +29,7 @@
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
 #include <asm/tlbflush.h>
+#include <asm/kprobes.h>
 
 extern void dump_thread(struct pt_regs *, struct user *);
 extern spinlock_t rtc_lock;
@@ -176,6 +177,11 @@ extern int is_sony_vaio_laptop;
 EXPORT_SYMBOL(is_sony_vaio_laptop);
 
 EXPORT_SYMBOL(__PAGE_KERNEL);
+
+#ifdef CONFIG_KPROBES
+EXPORT_SYMBOL(register_kprobe);
+EXPORT_SYMBOL(unregister_kprobe);
+#endif
 
 #ifdef CONFIG_MULTIQUAD
 EXPORT_SYMBOL(xquad_portio);
arch/i386/kernel/traps.c +257 -4

343 lines not on this page · raw message

arch/i386/mm/fault.c +4 -0
diff -urpN -I \$.*\$ --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal linux-2.5.26/arch/i386/mm/fault.c working-2.5.26-kprobes/arch/i386/mm/fault.c
@@ -20,6 +20,7 @@
 #include <linux/tty.h>
 #include <linux/vt_kern.h>		/* For unblank_screen() */
 
+#include <asm/kprobes.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/pgalloc.h>
@@ -156,6 +157,9 @@ asmlinkage void do_page_fault(struct pt_
 
 	/* get the address */
 	__asm__("movl %%cr2,%0":"=r" (address));
+
+	if (kprobe_fault(regs, 14))
+		return;
 
 	/* It's safe to allow irq's after cr2 has been saved */
 	if (regs->eflags & X86_EFLAGS_IF)
#1 lore raw
Quoted 12 lines · Rusty Russell

Hi Linus,

This is a neat patch by Vamsi which allows code to trap on
kernel instructions. The IBM guys have stuff for non-intrusive testing, debugging, instrumentation on top of this. It's also nice to insert assertions in core code without having to reboot 8)

Thanks,
Rusty.
--
Anyone who quotes me in their sig is an idiot. -- Rusty Russell.

Quoted 8 lines

Name: Kernel Probes Patch
Author: Vamsi Krishna S
Status: Tested on 2.5.26 SMP

D: This patch allows trapping at almost any kernel address, useful for
D: various kernel-hacking tasks, and building on for more D:
infrastructure. This patch is x86 only.

Here is a somewhat brief writeup we had available about kernel probes - hope it helps provide a little more information as suggested by some people offline.

Feedback, questions, comments welcome !

Regards
Suparna

Suparna Bhattacharya
Linux Technology Center
IBM Software Lab, India
E-mail : [email protected]

Kernel Dynamic Probes
---------------------

Kernel Dynamic Probes (kprobes) provides a lightweight interface for kernel modules to implant probes and register corresponding probe handlers. A probe is an automated breakpoint that is implanted dynamically in executing (kernel-space) modules without the need to modify their underlying source. Probes are intended to be used as an ad hoc service aid where minimal disruption to the system is required. They are particularly advocated in production environments where the use of interactive debuggers is undesirable. kprobes also has substantial applicability in test and development environments. During test, faults may be injected or simulated by the probing module. In development, debugging code (for example a printk) may be easily inserted without having to recompile to module under test.

With each probe, a corresponding probe event handler address is specified. Probe event handlers run as extensions to the system breakpoint interrupt handler and are expected to have little or no dependence on system facilities. Because of this design point, probes are able to be implanted in the most hostile environments -- interrupt-time, task-time, disabled, inter-context switch and SMP-enabled code paths -- without adversely skewing system performance.

kprobes Interfaces
--------------------
kprobes provides two interfaces: register_probe and unregister_probe.

register_probe:
----------------

Registration defines the probe location, which must be at an instruction boundary that precedes any associated opcode prefixes. It also defines three call-back addresses for the probing module:

- the probe-event handler address, which is called as the probed instruction is about to execute. On return kprobes will single-step the probed instruction;
- the post-execution handler address, which is called when single-stepping completes
- the fault handler address, which is called if an exception is generated for any instruction within the fault-handler or when kprobes single-steps the probed instruction.

register_probe passes a struct kprobe:

struct kprobe {
       u8 * addr;      /* location of the probe point */
       spinlock_t lock;
       struct list_head list;
       unsigned long status;
        /* Called before addr is executed. */
       kprobe_pre_handler_t pre_handler;
       /* Called after addr is executed, unless... */
       kprobe_post_handler_t post_handler;
        /* ... called if executing addr causes a fault (eg. page fault).
         * Return 1 if it handled fault, otherwise kernel will see it. */
       kprobe_fault_handler_t fault_handler;
       u8 opcode;
};

addr:
the location of the probepoint, which must be at an instruction boundary including any associated opcode prefixes - referencing label in C will guarantee this.

pre_handler:
the function that will be called when the probed instruction is about to execute.

post_handler:
the function that will be called on completion of successful execution of the probed instruction

fault_handler:
the function that will be called if any software
exceptions occur
- while executing inside the probe_handler
- when single-stepping the probed instruction

The user is required to retain this structure in resident memory for as long as the probe remains active. Some of the fields are used internally by kprobes and must be initialised to NULL or ZERO. The fields the user is required to initialise are the addr and the pre_handler fields. The post_handler and fault_handler are optional.

unregister_probe:
-----------------

unregister_probe also requires struct kprobe. The user has to unregister explicitely all registered probes before removing the probe handling module.

Extensions to Kernel Dynamic Probes
-----------------------------------

Kernel Dynamic Probes has been developed from the full Dynamic Probes patch. It includes the essential mechanism to allow probes to exist in kernel space. The RPN Language Interpreter, Watchpoints and User-space probes extensions, which are part of the Dynamic Probes Package, will be available as add-on patches from the Dynamic Probes web-site.

http://oss.software.ibm.com/developerworks/opensource/linux/projects/dprobes/