Skip to content

Commit

Permalink
kgdb,debug_core: pass the breakpoint struct instead of address and me…
Browse files Browse the repository at this point in the history
…mory

There is extra state information that needs to be exposed in the
kgdb_bpt structure for tracking how a breakpoint was installed.  The
debug_core only uses the the probe_kernel_write() to install
breakpoints, but this is not enough for all the archs.  Some arch such
as x86 need to use text_poke() in order to install a breakpoint into a
read only page.

Passing the kgdb_bpt structure to kgdb_arch_set_breakpoint() and
kgdb_arch_remove_breakpoint() allows other archs to set the type
variable which indicates how the breakpoint was installed.

Cc: stable@vger.kernel.org # >= 2.6.36
Signed-off-by: Jason Wessel <jason.wessel@windriver.com>
  • Loading branch information
jwessel committed Mar 29, 2012
1 parent 23bbd8e commit 98b54aa
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 31 deletions.
4 changes: 2 additions & 2 deletions include/linux/kgdb.h
Original file line number Diff line number Diff line change
Expand Up @@ -207,8 +207,8 @@ extern void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc);

/* Optional functions. */
extern int kgdb_validate_break_address(unsigned long addr);
extern int kgdb_arch_set_breakpoint(unsigned long addr, char *saved_instr);
extern int kgdb_arch_remove_breakpoint(unsigned long addr, char *bundle);
extern int kgdb_arch_set_breakpoint(struct kgdb_bkpt *bpt);
extern int kgdb_arch_remove_breakpoint(struct kgdb_bkpt *bpt);

/**
* kgdb_arch_late - Perform any architecture specific initalization.
Expand Down
53 changes: 24 additions & 29 deletions kernel/debug/debug_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -161,37 +161,39 @@ early_param("nokgdbroundup", opt_nokgdbroundup);
* Weak aliases for breakpoint management,
* can be overriden by architectures when needed:
*/
int __weak kgdb_arch_set_breakpoint(unsigned long addr, char *saved_instr)
int __weak kgdb_arch_set_breakpoint(struct kgdb_bkpt *bpt)
{
int err;

err = probe_kernel_read(saved_instr, (char *)addr, BREAK_INSTR_SIZE);
err = probe_kernel_read(bpt->saved_instr, (char *)bpt->bpt_addr,
BREAK_INSTR_SIZE);
if (err)
return err;

return probe_kernel_write((char *)addr, arch_kgdb_ops.gdb_bpt_instr,
BREAK_INSTR_SIZE);
err = probe_kernel_write((char *)bpt->bpt_addr,
arch_kgdb_ops.gdb_bpt_instr, BREAK_INSTR_SIZE);
return err;
}

int __weak kgdb_arch_remove_breakpoint(unsigned long addr, char *bundle)
int __weak kgdb_arch_remove_breakpoint(struct kgdb_bkpt *bpt)
{
return probe_kernel_write((char *)addr,
(char *)bundle, BREAK_INSTR_SIZE);
return probe_kernel_write((char *)bpt->bpt_addr,
(char *)bpt->saved_instr, BREAK_INSTR_SIZE);
}

int __weak kgdb_validate_break_address(unsigned long addr)
{
char tmp_variable[BREAK_INSTR_SIZE];
struct kgdb_bkpt tmp;
int err;
/* Validate setting the breakpoint and then removing it. In the
/* Validate setting the breakpoint and then removing it. If the
* remove fails, the kernel needs to emit a bad message because we
* are deep trouble not being able to put things back the way we
* found them.
*/
err = kgdb_arch_set_breakpoint(addr, tmp_variable);
tmp.bpt_addr = addr;
err = kgdb_arch_set_breakpoint(&tmp);
if (err)
return err;
err = kgdb_arch_remove_breakpoint(addr, tmp_variable);
err = kgdb_arch_remove_breakpoint(&tmp);
if (err)
printk(KERN_ERR "KGDB: Critical breakpoint error, kernel "
"memory destroyed at: %lx", addr);
Expand Down Expand Up @@ -235,7 +237,6 @@ static void kgdb_flush_swbreak_addr(unsigned long addr)
*/
int dbg_activate_sw_breakpoints(void)
{
unsigned long addr;
int error;
int ret = 0;
int i;
Expand All @@ -244,16 +245,15 @@ int dbg_activate_sw_breakpoints(void)
if (kgdb_break[i].state != BP_SET)
continue;

addr = kgdb_break[i].bpt_addr;
error = kgdb_arch_set_breakpoint(addr,
kgdb_break[i].saved_instr);
error = kgdb_arch_set_breakpoint(&kgdb_break[i]);
if (error) {
ret = error;
printk(KERN_INFO "KGDB: BP install failed: %lx", addr);
printk(KERN_INFO "KGDB: BP install failed: %lx",
kgdb_break[i].bpt_addr);
continue;
}

kgdb_flush_swbreak_addr(addr);
kgdb_flush_swbreak_addr(kgdb_break[i].bpt_addr);
kgdb_break[i].state = BP_ACTIVE;
}
return ret;
Expand Down Expand Up @@ -302,23 +302,21 @@ int dbg_set_sw_break(unsigned long addr)

int dbg_deactivate_sw_breakpoints(void)
{
unsigned long addr;
int error;
int ret = 0;
int i;

for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) {
if (kgdb_break[i].state != BP_ACTIVE)
continue;
addr = kgdb_break[i].bpt_addr;
error = kgdb_arch_remove_breakpoint(addr,
kgdb_break[i].saved_instr);
error = kgdb_arch_remove_breakpoint(&kgdb_break[i]);
if (error) {
printk(KERN_INFO "KGDB: BP remove failed: %lx\n", addr);
printk(KERN_INFO "KGDB: BP remove failed: %lx\n",
kgdb_break[i].bpt_addr);
ret = error;
}

kgdb_flush_swbreak_addr(addr);
kgdb_flush_swbreak_addr(kgdb_break[i].bpt_addr);
kgdb_break[i].state = BP_SET;
}
return ret;
Expand Down Expand Up @@ -352,20 +350,17 @@ int kgdb_isremovedbreak(unsigned long addr)

int dbg_remove_all_break(void)
{
unsigned long addr;
int error;
int i;

/* Clear memory breakpoints. */
for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) {
if (kgdb_break[i].state != BP_ACTIVE)
goto setundefined;
addr = kgdb_break[i].bpt_addr;
error = kgdb_arch_remove_breakpoint(addr,
kgdb_break[i].saved_instr);
error = kgdb_arch_remove_breakpoint(&kgdb_break[i]);
if (error)
printk(KERN_ERR "KGDB: breakpoint remove failed: %lx\n",
addr);
kgdb_break[i].bpt_addr);
setundefined:
kgdb_break[i].state = BP_UNDEFINED;
}
Expand Down

0 comments on commit 98b54aa

Please sign in to comment.