Messages in this thread Patch in this message | | | Date | Fri, 23 Mar 2012 09:38:17 -0500 | From | Jason Wessel <> | Subject | Re: [PATCH 2/2] kgdb,debug_core,kgdbts: End DEBUG_RODATA limitation using kprobe breakpoints |
| |
On 03/23/2012 09:08 AM, Masami Hiramatsu wrote: > (2012/03/22 20:57), Jason Wessel wrote: >> I will use the arch specific provision to override the >> kgdb_arch_set_breakpoint() and use the text_poke() directly. > > Thanks! that's what I meant. You can use __weak attribute. >
I created and tested a patch yesterday which is show below. I will post a new series at some point soon which addresses this problem as well as a number of problems found with the kgdb test suite.
Cheers, Jason.
Subject: [PATCH] x86,kgdb: End DEBUG_RODATA limitation using text_poke()
There has long been a limitation using software breakpoints with a kernel compiled with CONFIG_DEBUG_RODATA. The kprobes code has long used the text_poke() function which accommodates writing a breakpoint into a read-only page. The x86 arch can override the default breakpoint install remove routines and make use of the text_poke() code that comes from the x86 alternatives.
The x86 arch will first attempt to use the traditional probe_kernel_write(), and next try using a the text_poke() function. The break point install method is tracked such that the correct break point removal routine will get called later on.
Signed-off-by: Jason Wessel <jason.wessel@windriver.com> --- arch/x86/kernel/kgdb.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ include/linux/kgdb.h | 3 ++- 2 files changed, 48 insertions(+), 1 deletion(-)
--- a/include/linux/kgdb.h +++ b/include/linux/kgdb.h @@ -63,7 +63,8 @@ enum kgdb_bptype { BP_HARDWARE_BREAKPOINT, BP_WRITE_WATCHPOINT, BP_READ_WATCHPOINT, - BP_ACCESS_WATCHPOINT + BP_ACCESS_WATCHPOINT, + BP_POKE_BREAKPOINT, }; enum kgdb_bpstate { --- a/arch/x86/kernel/kgdb.c +++ b/arch/x86/kernel/kgdb.c @@ -742,6 +742,52 @@ void kgdb_arch_set_pc(struct pt_regs *re regs->ip = ip; } +int kgdb_arch_set_breakpoint(struct kgdb_bkpt *bpt) +{ + int err; + char opc[BREAK_INSTR_SIZE]; + + bpt->type = BP_BREAKPOINT; + err = probe_kernel_read(bpt->saved_instr, (char *)bpt->bpt_addr, + BREAK_INSTR_SIZE); + if (err) + return err; + err = probe_kernel_write((char *)bpt->bpt_addr, + arch_kgdb_ops.gdb_bpt_instr, BREAK_INSTR_SIZE); +#ifdef CONFIG_DEBUG_RODATA + if (!err) + return err; + text_poke((void *)bpt->bpt_addr, arch_kgdb_ops.gdb_bpt_instr, + BREAK_INSTR_SIZE); + err = probe_kernel_read(opc, (char *)bpt->bpt_addr, BREAK_INSTR_SIZE); + if (err) + return err; + if (memcmp(opc, arch_kgdb_ops.gdb_bpt_instr, BREAK_INSTR_SIZE)) + return -EINVAL; + bpt->type = BP_POKE_BREAKPOINT; +#endif /* CONFIG_DEBUG_RODATA */ + return err; +} + +int kgdb_arch_remove_breakpoint(struct kgdb_bkpt *bpt) +{ +#ifdef CONFIG_DEBUG_RODATA + int err; + char opc[BREAK_INSTR_SIZE]; + + if (bpt->type != BP_POKE_BREAKPOINT) + goto knl_write; + text_poke((void *)bpt->bpt_addr, bpt->saved_instr, BREAK_INSTR_SIZE); + err = probe_kernel_read(opc, (char *)bpt->bpt_addr, BREAK_INSTR_SIZE); + if (err || memcmp(opc, bpt->saved_instr, BREAK_INSTR_SIZE)) + goto knl_write; + return err; +knl_write: +#endif /* CONFIG_DEBUG_RODATA */ + return probe_kernel_write((char *)bpt->bpt_addr, + (char *)bpt->saved_instr, BREAK_INSTR_SIZE); +} + struct kgdb_arch arch_kgdb_ops = { /* Breakpoint instruction: */ .gdb_bpt_instr = { 0xcc },
| |