Skip to contentSkip to conversation

Kprobes base patch

PATCH In review Prasanna S Panchamukhi 1 participant 2 messages Aug 11, 2004 – Aug 12, 2004 kprobes

lore
Share & tools
lore
#0 lore raw

PATCH 2/4 Kprobes base patch

Hi,

Below is [2/4] kprobes-base-268-rc4.patch.
This patch helps developers to trap at almost any kernel
code address, specifying a handler routine to be invoked when the breakpoint is hit.
Useful for analysing the Linux kernel by collecting debugging information non-disruptively. Employs single-stepping out-of-line to avoid probe misses on SMP and may be especially useful in aiding debugging elusive races and problems on live systems. More elaborate dynamic tracing tools such as DProbes can be built over the kprobes interface.

Your comments are welcome!

Thanks
Prasanna

Signature · 5 lines
Prasanna S Panchamukhi
Linux Technology Center
India Software Labs, IBM Bangalore
Ph: 91-80-25044636
<[email protected]>

Helps developers to trap at almost any kernel code address, specifying a handler routine to be invoked when the breakpoint is hit. Useful for analysing the Linux kernel by collecting debugging information non-disruptively. Employs single-stepping out-of-line to avoid probe misses on SMP and may be especially useful in aiding debugging elusive races and problems on live systems. More elaborate dynamic tracing tools such as DProbes can be built over the kprobes interface.

Sample usage:

	To place a probe on __blockdev_direct_IO:
	static int probe_handler(struct kprobe *p, struct pt_regs *)
	{
		... whatever ...
	}
	struct kprobe kp = {
		.addr = __blockdev_direct_IO, 
		.pre_handler = probe_handler
	};
	register_kprobe(&kp);

---

---

---

---

---

 linux-2.6.8-rc4-prasanna/arch/i386/Kconfig          |   10 
 linux-2.6.8-rc4-prasanna/arch/i386/kernel/Makefile  |    1 
 linux-2.6.8-rc4-prasanna/arch/i386/kernel/entry.S   |   24 +
 linux-2.6.8-rc4-prasanna/arch/i386/kernel/kprobes.c |  275 ++++++++++++++++++++
 linux-2.6.8-rc4-prasanna/arch/i386/kernel/traps.c   |   24 +
 linux-2.6.8-rc4-prasanna/include/asm-i386/kprobes.h |   55 ++++
 linux-2.6.8-rc4-prasanna/include/linux/kprobes.h    |   95 ++++++
 linux-2.6.8-rc4-prasanna/kernel/Makefile            |    1 
 linux-2.6.8-rc4-prasanna/kernel/kprobes.c           |  125 +++++++++
 9 files changed, 603 insertions(+), 7 deletions(-)
arch/i386/Kconfig renamed from arch/i386/Kconfig~kprobes-base-268-rc3 +10 -0
diff -puN arch/i386/Kconfig~kprobes-base-268-rc3 arch/i386/Kconfig
@@ -1207,6 +1207,16 @@ config EARLY_PRINTK
 	  with klogd/syslogd or the X server. You should normally N here,
 	  unless you want to debug such a crash.
 
+config KPROBES
+	bool "Kprobes"
+	depends on DEBUG_KERNEL
+	help
+	  Kprobes allows you to trap at almost any kernel address and
+	  execute a callback function.  register_kprobe() establishes
+	  a probepoint and specifies the callback.  Kprobes is useful
+	  for kernel debugging, non-intrusive instrumentation and testing.
+	  If in doubt, say "N".
+
 config DEBUG_STACKOVERFLOW
 	bool "Check for stack overflows"
 	depends on DEBUG_KERNEL
arch/i386/kernel/entry.S renamed from arch/i386/kernel/entry.S~kprobes-base-268-rc3 +19 -5
diff -puN arch/i386/kernel/entry.S~kprobes-base-268-rc3 arch/i386/kernel/entry.S
@@ -489,9 +489,16 @@ ENTRY(debug)
 	jne debug_stack_correct
 	FIX_STACK(12, debug_stack_correct, debug_esp_fix_insn)
 debug_stack_correct:
-	pushl $0
-	pushl $do_debug
-	jmp error_code
+	pushl $-1			# mark this as an int
+	SAVE_ALL
+	movl %esp,%edx
+  	pushl $0
+	pushl %edx
+	call do_debug
+	addl $8,%esp
+	testl %eax,%eax
+	jnz restore_all
+	jmp ret_from_exception
 
 /*
  * NMI is doubly nasty. It can happen _while_ we're handling
@@ -540,9 +547,16 @@ nmi_debug_stack_fixup:
 	jmp nmi_stack_correct
 
 ENTRY(int3)
+	pushl $-1			# mark this as an int
+	SAVE_ALL
+	movl %esp,%edx
 	pushl $0
-	pushl $do_int3
-	jmp error_code
+	pushl %edx
+	call do_int3
+	addl $8,%esp
+	testl %eax,%eax
+	jnz restore_all
+	jmp ret_from_exception
 
 ENTRY(overflow)
 	pushl $0
arch/i386/kernel/kprobes.c new file +275 -0

275 lines not on this page · raw message

arch/i386/kernel/Makefile renamed from arch/i386/kernel/Makefile~kprobes-base-268-rc3 +1 -0
diff -puN arch/i386/kernel/Makefile~kprobes-base-268-rc3 arch/i386/kernel/Makefile
@@ -25,6 +25,7 @@ obj-$(CONFIG_X86_LOCAL_APIC)	+= apic.o n
 obj-$(CONFIG_X86_IO_APIC)	+= io_apic.o
 obj-$(CONFIG_X86_NUMAQ)		+= numaq.o
 obj-$(CONFIG_X86_SUMMIT_NUMA)	+= summit.o
+obj-$(CONFIG_KPROBES)		+= kprobes.o
 obj-$(CONFIG_MODULES)		+= module.o
 obj-y				+= sysenter.o vsyscall.o
 obj-$(CONFIG_ACPI_SRAT) 	+= srat.o
arch/i386/kernel/traps.c renamed from arch/i386/kernel/traps.c~kprobes-base-268-rc3 +22 -2
diff -puN arch/i386/kernel/traps.c~kprobes-base-268-rc3 arch/i386/kernel/traps.c
@@ -26,6 +26,7 @@
 #include <linux/kallsyms.h>
 #include <linux/ptrace.h>
 #include <linux/version.h>
+#include <linux/kprobes.h>
 
 #ifdef CONFIG_EISA
 #include <linux/ioport.h>
@@ -444,7 +445,6 @@ asmlinkage void do_##name(struct pt_regs
 }
 
 DO_VM86_ERROR_INFO( 0, SIGFPE,  "divide error", divide_error, FPE_INTDIV, regs->eip)
-DO_VM86_ERROR( 3, SIGTRAP, "int3", int3)
 DO_VM86_ERROR( 4, SIGSEGV, "overflow", overflow)
 DO_VM86_ERROR( 5, SIGSEGV, "bounds", bounds)
 DO_ERROR_INFO( 6, SIGILL,  "invalid operand", invalid_op, ILL_ILLOPN, regs->eip)
@@ -591,6 +591,18 @@ void unset_nmi_callback(void)
 	nmi_callback = dummy_nmi_callback;
 }
 
+asmlinkage int do_int3(struct pt_regs *regs, long error_code)
+{
+	if (notify_die(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP)
+			== NOTIFY_OK)
+		return 1;
+	/* This is an interrupt gate, because kprobes wants interrupts
+	disabled.  Normal trap handlers don't. */
+	restore_interrupts(regs);
+	do_trap(3, SIGTRAP, "int3", 1, regs, error_code, NULL);
+	return 0;
+}
+
 /*
  * Our handling of the processor debug registers is non-trivial.
  * We do not clear them on entry and exit from the kernel. Therefore
@@ -912,6 +924,14 @@ void set_intr_gate(unsigned int n, void 
 	_set_gate(idt_table+n,14,0,addr,__KERNEL_CS);
 }
 
+/*
+ * This routine sets up an interrupt gate at directory privilege level 3.
+ */
+static inline void set_system_intr_gate(unsigned int n, void *addr)
+{
+	_set_gate(idt_table+n, 14, 3, addr, __KERNEL_CS);
+}
+
 static void __init set_trap_gate(unsigned int n, void *addr)
 {
 	_set_gate(idt_table+n,15,0,addr,__KERNEL_CS);
@@ -948,7 +968,7 @@ void __init trap_init(void)
 	set_trap_gate(0,&divide_error);
 	set_intr_gate(1,&debug);
 	set_intr_gate(2,&nmi);
-	set_system_gate(3,&int3);	/* int3-5 can be called from all */
+	set_system_intr_gate(3, &int3); /* int3-5 can be called from all */
 	set_system_gate(4,&overflow);
 	set_system_gate(5,&bounds);
 	set_trap_gate(6,&invalid_op);
include/asm-i386/kprobes.h new file +55 -0

55 lines not on this page · raw message

include/linux/kprobes.h new file +95 -0

95 lines not on this page · raw message

kernel/kprobes.c new file +125 -0

125 lines not on this page · raw message

kernel/Makefile renamed from kernel/Makefile~kprobes-base-268-rc3 +1 -0
diff -puN kernel/Makefile~kprobes-base-268-rc3 kernel/Makefile
@@ -23,6 +23,7 @@ obj-$(CONFIG_IKCONFIG_PROC) += configs.o
 obj-$(CONFIG_STOP_MACHINE) += stop_machine.o
 obj-$(CONFIG_AUDIT) += audit.o
 obj-$(CONFIG_AUDITSYSCALL) += auditsc.o
+obj-$(CONFIG_KPROBES) += kprobes.o
 
 ifneq ($(CONFIG_IA64),y)
 # According to Alan Modra <[email protected]>, the -fno-omit-frame-pointer is

_

#1 lore raw

Hi Andi,

Please find the updated kprobes patch below. This patch is modified to use register_die_notifier() now.

Your comments are welcome!
Thanks
Prasanna

Signature · 5 lines
Prasanna S Panchamukhi
Linux Technology Center
India Software Labs, IBM Bangalore
Ph: 91-80-25044636
<[email protected]>

Helps developers to trap at almost any kernel code address, specifying a handler routine to be invoked when the breakpoint is hit. Useful for analysing the Linux kernel by collecting debugging information non-disruptively. Employs single-stepping out-of-line to avoid probe misses on SMP and may be especially useful in aiding debugging elusive races and problems on live systems. More elaborate dynamic tracing tools such as DProbes can be built over the kprobes interface.

Sample usage:

	To place a probe on __blockdev_direct_IO:
	static int probe_handler(struct kprobe *p, struct pt_regs *)
	{
		... whatever ...
	}
	struct kprobe kp = {
		.addr = __blockdev_direct_IO, 
		.pre_handler = probe_handler
	};
	register_kprobe(&kp);

---

---

---

---

---

 linux-2.6.8-rc4-prasanna/arch/i386/Kconfig          |   10 
 linux-2.6.8-rc4-prasanna/arch/i386/kernel/Makefile  |    1 
 linux-2.6.8-rc4-prasanna/kernel/Makefile            |    1 

---

 linux-2.6.8-rc4-prasanna/arch/i386/Kconfig          |   10 
 linux-2.6.8-rc4-prasanna/arch/i386/kernel/Makefile  |    1 
 linux-2.6.8-rc4-prasanna/arch/i386/kernel/entry.S   |   24 +
 linux-2.6.8-rc4-prasanna/arch/i386/kernel/kprobes.c |  275 ++++++++++++++++++++
 linux-2.6.8-rc4-prasanna/arch/i386/kernel/traps.c   |   24 +
 linux-2.6.8-rc4-prasanna/include/asm-i386/kprobes.h |   55 ++++
 linux-2.6.8-rc4-prasanna/include/linux/kprobes.h    |   95 ++++++
 linux-2.6.8-rc4-prasanna/kernel/Makefile            |    1 
 linux-2.6.8-rc4-prasanna/kernel/kprobes.c           |  125 +++++++++
 9 files changed, 603 insertions(+), 7 deletions(-)
arch/i386/Kconfig renamed from arch/i386/Kconfig~kprobes-base-268-rc4 +10 -0
diff -puN arch/i386/Kconfig~kprobes-base-268-rc4 arch/i386/Kconfig
@@ -1207,6 +1207,16 @@ config EARLY_PRINTK
 	  with klogd/syslogd or the X server. You should normally N here,
 	  unless you want to debug such a crash.
 
+config KPROBES
+	bool "Kprobes"
+	depends on DEBUG_KERNEL
+	help
+	  Kprobes allows you to trap at almost any kernel address and
+	  execute a callback function.  register_kprobe() establishes
+	  a probepoint and specifies the callback.  Kprobes is useful
+	  for kernel debugging, non-intrusive instrumentation and testing.
+	  If in doubt, say "N".
+
 config DEBUG_STACKOVERFLOW
 	bool "Check for stack overflows"
 	depends on DEBUG_KERNEL
arch/i386/kernel/entry.S renamed from arch/i386/kernel/entry.S~kprobes-base-268-rc4 +19 -5
diff -puN arch/i386/kernel/entry.S~kprobes-base-268-rc4 arch/i386/kernel/entry.S
@@ -489,9 +489,16 @@ ENTRY(debug)
 	jne debug_stack_correct
 	FIX_STACK(12, debug_stack_correct, debug_esp_fix_insn)
 debug_stack_correct:
-	pushl $0
-	pushl $do_debug
-	jmp error_code
+	pushl $-1			# mark this as an int
+	SAVE_ALL
+	movl %esp,%edx
+  	pushl $0
+	pushl %edx
+	call do_debug
+	addl $8,%esp
+	testl %eax,%eax
+	jnz restore_all
+	jmp ret_from_exception
 
 /*
  * NMI is doubly nasty. It can happen _while_ we're handling
@@ -540,9 +547,16 @@ nmi_debug_stack_fixup:
 	jmp nmi_stack_correct
 
 ENTRY(int3)
+	pushl $-1			# mark this as an int
+	SAVE_ALL
+	movl %esp,%edx
 	pushl $0
-	pushl $do_int3
-	jmp error_code
+	pushl %edx
+	call do_int3
+	addl $8,%esp
+	testl %eax,%eax
+	jnz restore_all
+	jmp ret_from_exception
 
 ENTRY(overflow)
 	pushl $0
arch/i386/kernel/kprobes.c new file +275 -0

275 lines not on this page · raw message

arch/i386/kernel/Makefile renamed from arch/i386/kernel/Makefile~kprobes-base-268-rc4 +1 -0
diff -puN arch/i386/kernel/Makefile~kprobes-base-268-rc4 arch/i386/kernel/Makefile
@@ -25,6 +25,7 @@ obj-$(CONFIG_X86_LOCAL_APIC)	+= apic.o n
 obj-$(CONFIG_X86_IO_APIC)	+= io_apic.o
 obj-$(CONFIG_X86_NUMAQ)		+= numaq.o
 obj-$(CONFIG_X86_SUMMIT_NUMA)	+= summit.o
+obj-$(CONFIG_KPROBES)		+= kprobes.o
 obj-$(CONFIG_MODULES)		+= module.o
 obj-y				+= sysenter.o vsyscall.o
 obj-$(CONFIG_ACPI_SRAT) 	+= srat.o
arch/i386/kernel/traps.c renamed from arch/i386/kernel/traps.c~kprobes-base-268-rc4 +22 -2
diff -puN arch/i386/kernel/traps.c~kprobes-base-268-rc4 arch/i386/kernel/traps.c
@@ -26,6 +26,7 @@
 #include <linux/kallsyms.h>
 #include <linux/ptrace.h>
 #include <linux/version.h>
+#include <linux/kprobes.h>
 
 #ifdef CONFIG_EISA
 #include <linux/ioport.h>
@@ -445,7 +446,6 @@ asmlinkage void do_##name(struct pt_regs
 }
 
 DO_VM86_ERROR_INFO( 0, SIGFPE,  "divide error", divide_error, FPE_INTDIV, regs->eip)
-DO_VM86_ERROR( 3, SIGTRAP, "int3", int3)
 DO_VM86_ERROR( 4, SIGSEGV, "overflow", overflow)
 DO_VM86_ERROR( 5, SIGSEGV, "bounds", bounds)
 DO_ERROR_INFO( 6, SIGILL,  "invalid operand", invalid_op, ILL_ILLOPN, regs->eip)
@@ -592,6 +592,18 @@ void unset_nmi_callback(void)
 	nmi_callback = dummy_nmi_callback;
 }
 
+asmlinkage int do_int3(struct pt_regs *regs, long error_code)
+{
+	if (notify_die(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP)
+			== NOTIFY_OK)
+		return 1;
+	/* This is an interrupt gate, because kprobes wants interrupts
+	disabled.  Normal trap handlers don't. */
+	restore_interrupts(regs);
+	do_trap(3, SIGTRAP, "int3", 1, regs, error_code, NULL);
+	return 0;
+}
+
 /*
  * Our handling of the processor debug registers is non-trivial.
  * We do not clear them on entry and exit from the kernel. Therefore
@@ -913,6 +925,14 @@ void set_intr_gate(unsigned int n, void 
 	_set_gate(idt_table+n,14,0,addr,__KERNEL_CS);
 }
 
+/*
+ * This routine sets up an interrupt gate at directory privilege level 3.
+ */
+static inline void set_system_intr_gate(unsigned int n, void *addr)
+{
+	_set_gate(idt_table+n, 14, 3, addr, __KERNEL_CS);
+}
+
 static void __init set_trap_gate(unsigned int n, void *addr)
 {
 	_set_gate(idt_table+n,15,0,addr,__KERNEL_CS);
@@ -949,7 +969,7 @@ void __init trap_init(void)
 	set_trap_gate(0,&divide_error);
 	set_intr_gate(1,&debug);
 	set_intr_gate(2,&nmi);
-	set_system_gate(3,&int3);	/* int3-5 can be called from all */
+	set_system_intr_gate(3, &int3); /* int3-5 can be called from all */
 	set_system_gate(4,&overflow);
 	set_system_gate(5,&bounds);
 	set_trap_gate(6,&invalid_op);
include/asm-i386/kprobes.h new file +55 -0

55 lines not on this page · raw message

include/linux/kprobes.h new file +95 -0

95 lines not on this page · raw message

kernel/kprobes.c new file +125 -0

125 lines not on this page · raw message

kernel/Makefile renamed from kernel/Makefile~kprobes-base-268-rc4 +1 -0
diff -puN kernel/Makefile~kprobes-base-268-rc4 kernel/Makefile
@@ -23,6 +23,7 @@ obj-$(CONFIG_IKCONFIG_PROC) += configs.o
 obj-$(CONFIG_STOP_MACHINE) += stop_machine.o
 obj-$(CONFIG_AUDIT) += audit.o
 obj-$(CONFIG_AUDITSYSCALL) += auditsc.o
+obj-$(CONFIG_KPROBES) += kprobes.o
 
 ifneq ($(CONFIG_IA64),y)
 # According to Alan Modra <[email protected]>, the -fno-omit-frame-pointer is

_