PATCH Kernel watchpoint interface-2.6.9-rc4-mm1
cover PATCH Kernel watchpoint interface-2.6.9-rc4-mm1
Hi,
Often kernel developer try to moniter global variables.
These patches provide a simple interface for monitering global variables. Please see the comments in the watchpoint patch for details. These patches can be applied over 2.6.9-rc4-mm1.
Please provide your comments.
Thanks
Prasanna
Signature · 5 lines
Prasanna S Panchamukhi Linux Technology Center India Software Labs, IBM Bangalore Ph: 91-80-25044636 <[email protected]>
This patch provides global debug register settings. Used by kernel watchpoint interface patch.
---
---
linux-2.6.9-rc4-prasanna/arch/i386/Kconfig.debug | 7 linux-2.6.9-rc4-prasanna/arch/i386/kernel/Makefile | 1 linux-2.6.9-rc4-prasanna/arch/i386/kernel/debugreg.c | 178 +++++++++++++++++++ linux-2.6.9-rc4-prasanna/arch/i386/kernel/process.c | 28 ++ linux-2.6.9-rc4-prasanna/arch/i386/kernel/ptrace.c | 5 linux-2.6.9-rc4-prasanna/arch/i386/kernel/signal.c | 3 linux-2.6.9-rc4-prasanna/arch/i386/kernel/traps.c | 4 linux-2.6.9-rc4-prasanna/include/asm-i386/debugreg.h | 162 +++++++++++++++++ 8 files changed, 383 insertions(+), 5 deletions(-)
arch/i386/Kconfig.debug renamed from arch/i386/Kconfig.debug~kprobes-debug-regs-2.6.9-rc4-mm1 +7 -0
@@ -29,6 +29,13 @@ config KPROBES for kernel debugging, non-intrusive instrumentation and testing. If in doubt, say "N". +config DEBUGREG + bool "Global Debug Registers" + depends on DEBUG_KERNEL + help + Global debug register settings will be honoured if this is turned on. + If in doubt, say "N". + config DEBUG_STACK_USAGE bool "Stack utilization instrumentation" depends on DEBUG_KERNEL
arch/i386/kernel/debugreg.c new file +178 -0
178 lines not on this page · raw message
arch/i386/kernel/Makefile renamed from arch/i386/kernel/Makefile~kprobes-debug-regs-2.6.9-rc4-mm1 +1 -0
@@ -35,6 +35,7 @@ obj-$(CONFIG_ACPI_SRAT) += srat.o obj-$(CONFIG_HPET_TIMER) += time_hpet.o obj-$(CONFIG_EFI) += efi.o efi_stub.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o +obj-$(CONFIG_DEBUGREG) += debugreg.o EXTRA_AFLAGS := -traditional
arch/i386/kernel/process.c renamed from arch/i386/kernel/process.c~kprobes-debug-regs-2.6.9-rc4-mm1 +27 -1
@@ -50,6 +50,7 @@#ifdef CONFIG_MATH_EMULATION #include <asm/math_emu.h> #endif +#include <asm/debugreg.h> #include <linux/irq.h> #include <linux/err.h>
@@ -317,6 +318,8 @@ void exit_thread(void) tss->io_bitmap_base =INVALID_IO_BITMAP_OFFSET ;put_cpu (); } +if (tsk->thread.debugreg[7 ]) +dr_dec_use_count (tsk->thread.debugreg[7 ]);perfctr_exit_thread (&tsk->thread); }
@@ -324,6 +327,8 @@ void flush_thread(void) {struct task_struct *tsk = current; +if (tsk->thread.debugreg[7 ]) +dr_dec_use_count (tsk->thread.debugreg[7 ]);memset (tsk->thread.debugreg,0 ,sizeof (unsigned long )*8 );memset (tsk->thread.tls_array,0 ,sizeof (tsk->thread.tls_array));/*
@@ -416,6 +421,9 @@ int copy_thread(int nr, unsigned long cl desc->b =LDT_entry_b (&info); } +if (tsk->thread.debugreg[7 ]) +dr_inc_use_count (tsk->thread.debugreg[7 ]); + err =0 ; out:if (err && p->thread.io_bitmap_ptr) {
@@ -593,6 +601,24 @@ struct task_struct fastcall * __switch_t/* * Now maybe reload the debug registers */ +#ifdef CONFIG_DEBUGREG +{ +/* +* Don't reload global debug registers. Don't touch the global debug +* register settings in dr7. +*/ +unsigned long next_dr7 = next->debugreg[7 ]; +if (unlikely (next_dr7)) { +if (DR7_L0 (next_dr7))loaddebug (next,0 ); +if (DR7_L1 (next_dr7))loaddebug (next,1 ); +if (DR7_L2 (next_dr7))loaddebug (next,2 ); +if (DR7_L3 (next_dr7))loaddebug (next,3 ); +/* no 4 and 5 */ +loaddebug (next,6 ); +load_process_dr7 (next_dr7); + } +} +#else if (unlikely (next->debugreg[7 ])) {loaddebug (next,0 );loaddebug (next,1 );
@@ -602,7 +628,7 @@ struct task_struct fastcall * __switch_tloaddebug (next,6 ); loaddebug(next, 7); } - +#endif if (unlikely (prev->io_bitmap_ptr || next->io_bitmap_ptr))handle_io_bitmap (next, tss);
arch/i386/kernel/ptrace.c renamed from arch/i386/kernel/ptrace.c~kprobes-debug-regs-2.6.9-rc4-mm1 +5 -0
@@ -353,6 +353,11 @@ asmlinkage int sys_ptrace(long request, addr -= (long ) &dummy->u_debugreg; addr = addr >>2 ; + +if (addr ==7 && (enable_debugreg (child->thread.debugreg[addr], data)) <0 ) { + ret = -EBUSY ; +break ; + } child->thread.debugreg[addr] = data; ret =0 ; }
arch/i386/kernel/signal.c renamed from arch/i386/kernel/signal.c~kprobes-debug-regs-2.6.9-rc4-mm1 +2 -1
@@ -25,6 +25,7 @@#include <asm/ucontext.h> #include <asm/uaccess.h> #include <asm/i387.h> +#include <asm/debugreg.h> #include "sigframe.h" #define DEBUG_SIG 0
@@ -600,7 +601,7 @@ int fastcall do_signal(struct pt_regs *r* have been cleared if the watchpoint triggered * inside the kernel. */ - __asm__("movl %0,%%db7" : :"r" (current->thread.debugreg[7 ])); +load_process_dr7 (current->thread.debugreg[7 ]);/* Whee! Actually deliver the signal. */ handle_signal (signr, &info, &ka, oldset, regs);
arch/i386/kernel/traps.c renamed from arch/i386/kernel/traps.c~kprobes-debug-regs-2.6.9-rc4-mm1 +1 -3
@@ -812,9 +812,7 @@ asmlinkage void do_debug(struct pt_regs* the signal is delivered. */ clear_dr7: - __asm__("movl %0,%%db7" - :/* no output */ - :"r" (0 )); +load_process_dr7 (0 ); CHK_REMOTE_DEBUG(1,SIGTRAP,error_code,regs,)return ;
include/asm-i386/debugreg.h renamed from include/asm-i386/debugreg.h~kprobes-debug-regs-2.6.9-rc4-mm1 +162 -0
166 lines not on this page · raw message
_
Thanks
Prasanna
Signature · 5 lines
Prasanna S Panchamukhi Linux Technology Center India Software Labs, IBM Bangalore Ph: 91-80-25044636 <[email protected]>
This patch provides a simple interface for kernel-space watchpoints
using processor's debug registers. Using Kwatch interface users can moniter kernel global variables and dump the debugging information such as kernel stack, global variables, processor registers.
int register_kwatch(unsigned long addr, u8 length, u8 type,
kwatch_handler_t handler)
-length of the breakpoint can be 1,2 or 4 bytes long. -type can be read, write, execute.
0 Break on instruction execution only.
1 Break on data writes only.
3 Break on data reads or writes but not instruction fetches.
-return value is the debug register number allocated/used for setting up this watch point.
Sample code:
This sample code sets a watchpoint on the instruction
excution at do_fork.
struct kwatch kp;
void kwatch_handler(struct kwatch *p, struct pt_regs *regs)
{
.......<do-any-thing>........
}
debug_regs_num = register_kwatch(do_fork, 1, 0, kwatch_handler);---
---
linux-2.6.9-rc4-prasanna/arch/i386/Kconfig.debug | 7 linux-2.6.9-rc4-prasanna/arch/i386/kernel/Makefile | 1 linux-2.6.9-rc4-prasanna/arch/i386/kernel/kwatch.c | 171 +++++++++++++++++++++ linux-2.6.9-rc4-prasanna/arch/i386/kernel/traps.c | 1 linux-2.6.9-rc4-prasanna/include/asm-i386/kwatch.h | 31 +++ 5 files changed, 211 insertions(+)
arch/i386/Kconfig.debug renamed from arch/i386/Kconfig.debug~kprobes-kernel-watchpoint-2.6.9-rc4-mm1 +7 -0
@@ -36,6 +36,13 @@ config DEBUGREG Global debug register settings will be honoured if this is turned on. If in doubt, say "N". +config KWATCH + bool "Kwatch points" + depends on DEBUG_KERNEL && DEBUGREG + help + This enables kernel-space watchpoints using processor's debug + registers. If in doubt, say "N". + config DEBUG_STACK_USAGE bool "Stack utilization instrumentation" depends on DEBUG_KERNEL
arch/i386/kernel/kwatch.c new file +171 -0
171 lines not on this page · raw message
arch/i386/kernel/Makefile renamed from arch/i386/kernel/Makefile~kprobes-kernel-watchpoint-2.6.9-rc4-mm1 +1 -0
@@ -36,6 +36,7 @@ obj-$(CONFIG_HPET_TIMER) += time_hpet.o obj-$(CONFIG_EFI) += efi.o efi_stub.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o obj-$(CONFIG_DEBUGREG) += debugreg.o +obj-$(CONFIG_KWATCH) += kwatch.o EXTRA_AFLAGS := -traditional
arch/i386/kernel/traps.c renamed from arch/i386/kernel/traps.c~kprobes-kernel-watchpoint-2.6.9-rc4-mm1 +1 -0
@@ -43,6 +43,7 @@#include <asm/io.h> #include <asm/atomic.h> #include <asm/debugreg.h> +#include <asm/kwatch.h> #include <asm/desc.h> #include <asm/i387.h> #include <asm/nmi.h>
include/asm-i386/kwatch.h new file +31 -0
@@ -0,0 +1,31 @@ +#ifndef _ASM_KWATCH_H +#define _ASM_KWATCH_H +/* +* Dynamic Probes (kwatch points) support +* Vamsi Krishna S <[email protected]>, Oct, 2002 +*/ +#include <linux/types.h> +#include <linux/ptrace.h> + +struct kwatch ; +typedef void (*kwatch_handler_t )(struct kwatch *,struct pt_regs *); + +struct kwatch { +unsigned long addr;/* location of watchpoint */ +u8 length;/* range of address */ +u8 type;/* type of watchpoint */ +kwatch_handler_t handler; +}; + +#define RF_MASK 0x00010000 + +#ifdef CONFIG_KWATCH +extern int register_kwatch (unsigned long addr,u8 length,u8 type,kwatch_handler_t handler); +extern void unregister_kwatch (int debugreg); +extern int kwatch_handler (unsigned long condition,struct pt_regs *regs); +#else +static inline int register_kwatch (unsigned long addr,u8 length,u8 type,kwatch_handler_t handler) {return -ENOSYS ; } +static inline void unregister_kwatch (int debugreg) { } +static inline int kwatch_handler (unsigned long condition,struct pt_regs *regs) {return 0 ; } +#endif +#endif /* _ASM_KWATCH_H */
_
Thanks
Prasanna
Signature · 5 lines
Prasanna S Panchamukhi Linux Technology Center India Software Labs, IBM Bangalore Ph: 91-80-25044636 <[email protected]>
Hi All,
Please find the updated kernel watchpoint patch below. This patch can be applied over 2.6.9-final and helpful to setting hardware breakpoints.
Thanks
Prasanna
This patch provides a simple interface for kernel-space watchpoints
using processor's debug registers. Using Kwatch interface users can monitor kernel global variables and dump the debugging information such as kernel stack, global variables, processor registers.
int register_kwatch(unsigned long addr, u8 length, u8 type,
kwatch_handler_t handler)
-length of the breakpoint can be 1,2 or 4 bytes long. -type can be read, write, execute.
0 Break on instruction execution only.
1 Break on data writes only.
3 Break on data reads or writes but not instruction fetches.
-return value is the debug register number allocated/used for setting up this watch point.
Sample code:
This sample code sets a watchpoint on the instruction
excution at do_fork.
struct kwatch kp;
void kwatch_handler(struct kwatch *p, struct pt_regs *regs)
{
.......<do-any-thing>........
}
debug_regs_num = register_kwatch(do_fork, 1, 0, kwatch_handler);---
---
linux-2.6.9-final-prasanna/arch/i386/Kconfig.debug | 8 linux-2.6.9-final-prasanna/arch/i386/kernel/Makefile | 1 linux-2.6.9-final-prasanna/arch/i386/kernel/kwatch.c | 190 +++++++++++++++++++ linux-2.6.9-final-prasanna/include/asm-i386/kwatch.h | 50 +++++ 4 files changed, 249 insertions(+)
arch/i386/Kconfig.debug renamed from arch/i386/Kconfig.debug~kprobes-kernel-watchpoint-2.6.9-final +8 -0
@@ -29,6 +29,14 @@ config KPROBES for kernel debugging, non-intrusive instrumentation and testing. If in doubt, say "N". +config KWATCH + bool "Kwatch points" + depends on DEBUG_KERNEL + select DEBUGREG + help + This enables kernel-space watchpoints using processor's debug + registers. If in doubt, say "N". + config DEBUGREG bool "Global Debug Registers" depends on DEBUG_KERNEL
arch/i386/kernel/kwatch.c new file +190 -0
190 lines not on this page · raw message
arch/i386/kernel/Makefile renamed from arch/i386/kernel/Makefile~kprobes-kernel-watchpoint-2.6.9-final +1 -0
@@ -33,6 +33,7 @@ obj-$(CONFIG_HPET_TIMER) += time_hpet.o obj-$(CONFIG_EFI) += efi.o efi_stub.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o obj-$(CONFIG_DEBUGREG) += debugreg.o +obj-$(CONFIG_KWATCH) += kwatch.o EXTRA_AFLAGS := -traditional
include/asm-i386/kwatch.h new file +50 -0
50 lines not on this page · raw message
_
Signature · 5 lines
Prasanna S Panchamukhi Linux Technology Center India Software Labs, IBM Bangalore Ph: 91-80-25044636 <[email protected]>
arch/i386/Kconfig.debug config KPROBES · line 38
Quoted 10 lines · Prasanna S Panchamukhi
This patch provides global debug register settings. Used by kernel watchpoint interface patch.
arch/i386/Kconfig.debug renamed from arch/i386/Kconfig.debug~kprobes-debug-regs-2.6.9-rc4-mm1 +7
-0+config DEBUGREG + bool "Global Debug Registers" + depends on DEBUG_KERNEL + help + Global debug register settings will be honoured if this is turned on. + If in doubt, say "N". +
I like most of the patch, but Kconfig is wrong. This option should not be exposed to end users, instead CONFIG_DEBUGREG should be selected by the debug code that calls debugreg. IOW, kgdb, kdb or kwatch select debugreg, not the other way around.
arch/i386/Kconfig.debug config KPROBES · line 33
Quoted 2 lines
arch/i386/Kconfig.debug renamed from arch/i386/Kconfig.debug~kprobes-debug-regs-2.6.9-rc4-mm1 +2
-0+config DEBUGREG + bool "Global Debug Registers"
I agree with Keith that it shouldn't be user visible. I would always enable it in fact.
arch/i386/kernel/debugreg.c line 58
Quoted 3 lines
arch/i386/kernel/debugreg.c new file +3
-0+{ +int i; +if (flag ==DR_ALLOC_LOCAL ) {
[...] This all would be simpler if you used lib/idr.c, no?
arch/i386/kernel/debugreg.c line 116
Quoted 6 lines
arch/i386/kernel/debugreg.c new file +6
-0+int dr_free (int regnum) +{ +spin_lock (&dr_lock); +if (regnum >=DR_MAX || dr_list[regnum].flag ==DR_UNUSED ) { +spin_unlock (&dr_lock); +return -1 ;
This should printk
arch/i386/kernel/process.c struct task_struct fastcall * __switch_t · line 615
Quoted 12 lines
arch/i386/kernel/process.c renamed from arch/i386/kernel/process.c~kprobes-debug-regs-2.6.9-rc4-mm1 +12
-0+#ifdef CONFIG_DEBUGREG +{ +/* +* Don't reload global debug registers. Don't touch the global debug +* register settings in dr7. +*/ +unsigned long next_dr7 = next->debugreg[7 ]; +if (unlikely (next_dr7)) { +if (DR7_L0 (next_dr7))loaddebug (next,0 ); +if (DR7_L1 (next_dr7))loaddebug (next,1 ); +if (DR7_L2 (next_dr7))loaddebug (next,2 ); +if (DR7_L3 (next_dr7))loaddebug (next,3 );
I would do this differently - check instead if the registers are different between the tasks and only reload when different. This will make updating/freeing more expensive because you will need to change all tasks, but imho it's worth it.
And then no ifdefs please.
arch/i386/kernel/traps.c asmlinkage void do_debug(struct pt_regs · line 816
Quoted 7 lines
arch/i386/kernel/traps.c renamed from arch/i386/kernel/traps.c~kprobes-debug-regs-2.6.9-rc4-mm1 +1
-3*/ clear_dr7: - __asm__("movl %0,%%db7" - :/* no output */ - :"r" (0 )); +load_process_dr7 (0 ); CHK_REMOTE_DEBUG(1,SIGTRAP,error_code,regs,)
That's mm (and should go away anyways because debug notifiers are better) I would do the patch against mainline so that it can be actually merged.
-Andi
Hi,
I have updated the patch with Andi Kleen's and Keith Owens suggestions. This patch can be applied over 2.6.9-final.
Kindly review and provide your feedback.
Thanks
Prasanna
This patch provides debug register allocation mechanism. Useful for debuggers like IOW, kgdb, kdb, kernel watchpoint.
---
---
---
linux-2.6.9-final-prasanna/arch/i386/Kconfig.debug | 8 linux-2.6.9-final-prasanna/arch/i386/kernel/Makefile | 1 linux-2.6.9-final-prasanna/arch/i386/kernel/debugreg.c | 288 +++++++++++++++++ linux-2.6.9-final-prasanna/arch/i386/kernel/process.c | 25 + linux-2.6.9-final-prasanna/arch/i386/kernel/ptrace.c | 5 linux-2.6.9-final-prasanna/arch/i386/kernel/signal.c | 3 linux-2.6.9-final-prasanna/arch/i386/kernel/traps.c | 4 linux-2.6.9-final-prasanna/include/asm-i386/debugreg.h | 162 +++++++++ 8 files changed, 486 insertions(+), 10 deletions(-)
arch/i386/Kconfig.debug renamed from arch/i386/Kconfig.debug~kprobes-debug-regs-2.6.9-final +8 -0
@@ -29,6 +29,14 @@ config KPROBES for kernel debugging, non-intrusive instrumentation and testing. If in doubt, say "N". +config DEBUGREG + bool "Global Debug Registers" + depends on DEBUG_KERNEL + default off + help + Global debug register settings need to be enabled by the + debuggers using it. + config DEBUG_STACK_USAGE bool "Stack utilization instrumentation" depends on DEBUG_KERNEL
arch/i386/kernel/debugreg.c new file +288 -0
288 lines not on this page · raw message
arch/i386/kernel/Makefile renamed from arch/i386/kernel/Makefile~kprobes-debug-regs-2.6.9-final +1 -0
@@ -32,6 +32,7 @@ obj-$(CONFIG_ACPI_SRAT) += srat.o obj-$(CONFIG_HPET_TIMER) += time_hpet.o obj-$(CONFIG_EFI) += efi.o efi_stub.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o +obj-$(CONFIG_DEBUGREG) += debugreg.o EXTRA_AFLAGS := -traditional
arch/i386/kernel/process.c renamed from arch/i386/kernel/process.c~kprobes-debug-regs-2.6.9-final +19 -6
@@ -49,6 +49,7 @@#ifdef CONFIG_MATH_EMULATION #include <asm/math_emu.h> #endif +#include <asm/debugreg.h> #include <linux/irq.h> #include <linux/err.h>
@@ -316,12 +317,16 @@ void exit_thread(void) tss->io_bitmap_base =INVALID_IO_BITMAP_OFFSET ;put_cpu (); } +if (tsk->thread.debugreg[7 ]) +dr_dec_use_count (tsk->thread.debugreg[7 ]); }void flush_thread (void ) {struct task_struct *tsk = current; +if (tsk->thread.debugreg[7 ]) +dr_dec_use_count (tsk->thread.debugreg[7 ]);memset (tsk->thread.debugreg,0 ,sizeof (unsigned long )*8 );memset (tsk->thread.tls_array,0 ,sizeof (tsk->thread.tls_array));/*
@@ -413,6 +418,9 @@ int copy_thread(int nr, unsigned long cl desc->b =LDT_entry_b (&info); } +if (tsk->thread.debugreg[7 ]) +dr_inc_use_count (tsk->thread.debugreg[7 ]); + err =0 ; out:if (err && p->thread.io_bitmap_ptr) {
@@ -588,14 +596,19 @@ struct task_struct fastcall * __switch_t/* * Now maybe reload the debug registers */ -if (unlikely (next->debugreg[7 ])) { -loaddebug (next,0 ); -loaddebug (next,1 ); -loaddebug (next,2 ); -loaddebug (next,3 ); +/* +* Don't reload global debug registers. Don't touch the global debug +* register settings in dr7. +*/ +unsigned long next_dr7 = next->debugreg[7 ]; +if (unlikely (next_dr7)) { +if (prev->debugreg[0 ] != next->debugreg[0 ])loaddebug (next,0 ); +if (prev->debugreg[1 ] != next->debugreg[1 ])loaddebug (next,1 ); +if (prev->debugreg[2 ] != next->debugreg[2 ])loaddebug (next,2 ); +if (prev->debugreg[3 ] != next->debugreg[3 ])loaddebug (next,3 );/* no 4 and 5 */ loaddebug (next,6 ); -loaddebug (next,7 ); +load_process_dr7 (next_dr7); }if (unlikely (prev->io_bitmap_ptr || next->io_bitmap_ptr))
arch/i386/kernel/ptrace.c renamed from arch/i386/kernel/ptrace.c~kprobes-debug-regs-2.6.9-final +5 -0
@@ -353,6 +353,11 @@ asmlinkage int sys_ptrace(long request, addr -= (long ) &dummy->u_debugreg; addr = addr >>2 ; + +if (addr ==7 && (enable_debugreg (child->thread.debugreg[addr], data)) <0 ) { + ret = -EBUSY ; +break ; + } child->thread.debugreg[addr] = data; ret =0 ; }
arch/i386/kernel/signal.c renamed from arch/i386/kernel/signal.c~kprobes-debug-regs-2.6.9-final +2 -1
@@ -25,6 +25,7 @@#include <asm/ucontext.h> #include <asm/uaccess.h> #include <asm/i387.h> +#include <asm/debugreg.h> #include "sigframe.h" #define DEBUG_SIG 0
@@ -600,7 +601,7 @@ int fastcall do_signal(struct pt_regs *r* have been cleared if the watchpoint triggered * inside the kernel. */ - __asm__("movl %0,%%db7" : :"r" (current->thread.debugreg[7 ])); +load_process_dr7 (current->thread.debugreg[7 ]);/* Whee! Actually deliver the signal. */ handle_signal (signr, &info, &ka, oldset, regs);
arch/i386/kernel/traps.c renamed from arch/i386/kernel/traps.c~kprobes-debug-regs-2.6.9-final +1 -3
@@ -760,9 +760,7 @@ asmlinkage void do_debug(struct pt_regs* the signal is delivered. */ clear_dr7: - __asm__("movl %0,%%db7" - :/* no output */ - :"r" (0 )); +load_process_dr7 (0 );return ; debug_vm86:
include/asm-i386/debugreg.h renamed from include/asm-i386/debugreg.h~kprobes-debug-regs-2.6.9-final +162 -0
166 lines not on this page · raw message
_
Signature · 5 lines
Prasanna S Panchamukhi Linux Technology Center India Software Labs, IBM Bangalore Ph: 91-80-25044636 <[email protected]>