mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-11-19 08:05:27 +08:00
KGDB/KDB regression fixes
3.4: Fix an an Smatch warning that appeared in the 3.4 merge window 3.0: Fix kgdb test suite with SMP for all archs without HW single stepping 2.6.36: Fix kgdb sw breakpoints with CONFIG_DEBUG_RODATA=y limitations on x86 2.6.26: Fix oops on kgdb test suite with CONFIG_DEBUG_RODATA Fix kgdb test suite with SMP for all archs with HW single stepping -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) iQIcBAABAgAGBQJPedocAAoJEIciOldedpOjn7EP/397Rh0zmRlG8oQwMEJcK3E5 gaRyBNpkGoU3ekHXHx/nzgQ/CS9opzW7nBZDu8weWLjRKMT4RyHfuJcWyu525GvQ SnoiX2ZUzP315d8llCYwXmaCEYA7lHQi4T2bGMlDSn1J8kS235EQxllgEfhXDdEC DxRWgHABG2UR62C62sGKbPaMMDO9TcNcrAQK27LDLTS7pKLmYqBWBdZKgWzBM/Pr AF8vakqSgUw3Aq9qrLge+483uT7uhMoUJofxRppWtm1QgnDcTmri9LOagiazDotz RQliRGwVxj9hEo5mLEiQtI0N1kIGCAsK0+9aUJEZRXovRBR9kvqaqHT4c5xdhznr VKYvqqTcHBkKLIfNXFvQZnn2cXtNVNqve9CZZwdBJaFYEkaR7ZVQqE6f2xq8KAb2 RmhvzlEUyLU+89YKkH66uSa22VLSazkeH+4b8AJ4JxYDEab3BHoBCe8axcBQrTsj 7X5NOs7V3Oj+4J3bS1fbUbxq4t0dfpLLyg8e/lELWtT+Kq7nQRzA2XHRZAMTve8M T0cTdrwtUbgY9ZMTpywNB2KlPgTvhWOyfYbH6/Kcks7ecSXlkow3edXoiUbw79iE hP8vcMWbT2Rv3IbLkSMFZEQGAG9qL1YyGv4NDmLOoljO1c/Bi3WQIR5aI+di6asV Z5q5s/bmGa4+OhFFITSd =SW2N -----END PGP SIGNATURE----- Merge tag 'for_linus-3.4-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/jwessel/kgdb Pull KGDB/KDB regression fixes from Jason Wessel: - Fix a Smatch warning that appeared in the 3.4 merge window - Fix kgdb test suite with SMP for all archs without HW single stepping - Fix kgdb sw breakpoints with CONFIG_DEBUG_RODATA=y limitations on x86 - Fix oops on kgdb test suite with CONFIG_DEBUG_RODATA - Fix kgdb test suite with SMP for all archs with HW single stepping * tag 'for_linus-3.4-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/jwessel/kgdb: x86,kgdb: Fix DEBUG_RODATA limitation using text_poke() kgdb,debug_core: pass the breakpoint struct instead of address and memory kgdbts: (2 of 2) fix single step awareness to work correctly with SMP kgdbts: (1 of 2) fix single step awareness to work correctly with SMP kgdbts: Fix kernel oops with CONFIG_DEBUG_RODATA kdb: Fix smatch warning on dbg_io_ops->is_console
This commit is contained in:
commit
6c216ec636
@ -43,6 +43,8 @@
|
||||
#include <linux/smp.h>
|
||||
#include <linux/nmi.h>
|
||||
#include <linux/hw_breakpoint.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/memory.h>
|
||||
|
||||
#include <asm/debugreg.h>
|
||||
#include <asm/apicdef.h>
|
||||
@ -741,6 +743,64 @@ void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long ip)
|
||||
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;
|
||||
/*
|
||||
* It is safe to call text_poke() because normal kernel execution
|
||||
* is stopped on all cores, so long as the text_mutex is not locked.
|
||||
*/
|
||||
if (mutex_is_locked(&text_mutex))
|
||||
return -EBUSY;
|
||||
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;
|
||||
/*
|
||||
* It is safe to call text_poke() because normal kernel execution
|
||||
* is stopped on all cores, so long as the text_mutex is not locked.
|
||||
*/
|
||||
if (mutex_is_locked(&text_mutex))
|
||||
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 },
|
||||
|
@ -134,12 +134,17 @@ static int force_hwbrks;
|
||||
static int hwbreaks_ok;
|
||||
static int hw_break_val;
|
||||
static int hw_break_val2;
|
||||
static int cont_instead_of_sstep;
|
||||
static unsigned long cont_thread_id;
|
||||
static unsigned long sstep_thread_id;
|
||||
#if defined(CONFIG_ARM) || defined(CONFIG_MIPS) || defined(CONFIG_SPARC)
|
||||
static int arch_needs_sstep_emulation = 1;
|
||||
#else
|
||||
static int arch_needs_sstep_emulation;
|
||||
#endif
|
||||
static unsigned long cont_addr;
|
||||
static unsigned long sstep_addr;
|
||||
static int restart_from_top_after_write;
|
||||
static int sstep_state;
|
||||
|
||||
/* Storage for the registers, in GDB format. */
|
||||
@ -187,7 +192,8 @@ static int kgdbts_unreg_thread(void *ptr)
|
||||
*/
|
||||
while (!final_ack)
|
||||
msleep_interruptible(1500);
|
||||
|
||||
/* Pause for any other threads to exit after final ack. */
|
||||
msleep_interruptible(1000);
|
||||
if (configured)
|
||||
kgdb_unregister_io_module(&kgdbts_io_ops);
|
||||
configured = 0;
|
||||
@ -211,7 +217,7 @@ static unsigned long lookup_addr(char *arg)
|
||||
if (!strcmp(arg, "kgdbts_break_test"))
|
||||
addr = (unsigned long)kgdbts_break_test;
|
||||
else if (!strcmp(arg, "sys_open"))
|
||||
addr = (unsigned long)sys_open;
|
||||
addr = (unsigned long)do_sys_open;
|
||||
else if (!strcmp(arg, "do_fork"))
|
||||
addr = (unsigned long)do_fork;
|
||||
else if (!strcmp(arg, "hw_break_val"))
|
||||
@ -283,6 +289,16 @@ static void hw_break_val_write(void)
|
||||
hw_break_val++;
|
||||
}
|
||||
|
||||
static int get_thread_id_continue(char *put_str, char *arg)
|
||||
{
|
||||
char *ptr = &put_str[11];
|
||||
|
||||
if (put_str[1] != 'T' || put_str[2] != '0')
|
||||
return 1;
|
||||
kgdb_hex2long(&ptr, &cont_thread_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int check_and_rewind_pc(char *put_str, char *arg)
|
||||
{
|
||||
unsigned long addr = lookup_addr(arg);
|
||||
@ -299,13 +315,21 @@ static int check_and_rewind_pc(char *put_str, char *arg)
|
||||
if (addr + BREAK_INSTR_SIZE == ip)
|
||||
offset = -BREAK_INSTR_SIZE;
|
||||
#endif
|
||||
if (strcmp(arg, "silent") && ip + offset != addr) {
|
||||
|
||||
if (arch_needs_sstep_emulation && sstep_addr &&
|
||||
ip + offset == sstep_addr &&
|
||||
((!strcmp(arg, "sys_open") || !strcmp(arg, "do_fork")))) {
|
||||
/* This is special case for emulated single step */
|
||||
v2printk("Emul: rewind hit single step bp\n");
|
||||
restart_from_top_after_write = 1;
|
||||
} else if (strcmp(arg, "silent") && ip + offset != addr) {
|
||||
eprintk("kgdbts: BP mismatch %lx expected %lx\n",
|
||||
ip + offset, addr);
|
||||
return 1;
|
||||
}
|
||||
/* Readjust the instruction pointer if needed */
|
||||
ip += offset;
|
||||
cont_addr = ip;
|
||||
#ifdef GDB_ADJUSTS_BREAK_OFFSET
|
||||
instruction_pointer_set(&kgdbts_regs, ip);
|
||||
#endif
|
||||
@ -315,6 +339,8 @@ static int check_and_rewind_pc(char *put_str, char *arg)
|
||||
static int check_single_step(char *put_str, char *arg)
|
||||
{
|
||||
unsigned long addr = lookup_addr(arg);
|
||||
static int matched_id;
|
||||
|
||||
/*
|
||||
* From an arch indepent point of view the instruction pointer
|
||||
* should be on a different instruction
|
||||
@ -324,6 +350,29 @@ static int check_single_step(char *put_str, char *arg)
|
||||
gdb_regs_to_pt_regs(kgdbts_gdb_regs, &kgdbts_regs);
|
||||
v2printk("Singlestep stopped at IP: %lx\n",
|
||||
instruction_pointer(&kgdbts_regs));
|
||||
|
||||
if (sstep_thread_id != cont_thread_id) {
|
||||
/*
|
||||
* Ensure we stopped in the same thread id as before, else the
|
||||
* debugger should continue until the original thread that was
|
||||
* single stepped is scheduled again, emulating gdb's behavior.
|
||||
*/
|
||||
v2printk("ThrID does not match: %lx\n", cont_thread_id);
|
||||
if (arch_needs_sstep_emulation) {
|
||||
if (matched_id &&
|
||||
instruction_pointer(&kgdbts_regs) != addr)
|
||||
goto continue_test;
|
||||
matched_id++;
|
||||
ts.idx -= 2;
|
||||
sstep_state = 0;
|
||||
return 0;
|
||||
}
|
||||
cont_instead_of_sstep = 1;
|
||||
ts.idx -= 4;
|
||||
return 0;
|
||||
}
|
||||
continue_test:
|
||||
matched_id = 0;
|
||||
if (instruction_pointer(&kgdbts_regs) == addr) {
|
||||
eprintk("kgdbts: SingleStep failed at %lx\n",
|
||||
instruction_pointer(&kgdbts_regs));
|
||||
@ -365,10 +414,40 @@ static int got_break(char *put_str, char *arg)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void get_cont_catch(char *arg)
|
||||
{
|
||||
/* Always send detach because the test is completed at this point */
|
||||
fill_get_buf("D");
|
||||
}
|
||||
|
||||
static int put_cont_catch(char *put_str, char *arg)
|
||||
{
|
||||
/* This is at the end of the test and we catch any and all input */
|
||||
v2printk("kgdbts: cleanup task: %lx\n", sstep_thread_id);
|
||||
ts.idx--;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int emul_reset(char *put_str, char *arg)
|
||||
{
|
||||
if (strncmp(put_str, "$OK", 3))
|
||||
return 1;
|
||||
if (restart_from_top_after_write) {
|
||||
restart_from_top_after_write = 0;
|
||||
ts.idx = -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void emul_sstep_get(char *arg)
|
||||
{
|
||||
if (!arch_needs_sstep_emulation) {
|
||||
fill_get_buf(arg);
|
||||
if (cont_instead_of_sstep) {
|
||||
cont_instead_of_sstep = 0;
|
||||
fill_get_buf("c");
|
||||
} else {
|
||||
fill_get_buf(arg);
|
||||
}
|
||||
return;
|
||||
}
|
||||
switch (sstep_state) {
|
||||
@ -398,9 +477,11 @@ static void emul_sstep_get(char *arg)
|
||||
static int emul_sstep_put(char *put_str, char *arg)
|
||||
{
|
||||
if (!arch_needs_sstep_emulation) {
|
||||
if (!strncmp(put_str+1, arg, 2))
|
||||
return 0;
|
||||
return 1;
|
||||
char *ptr = &put_str[11];
|
||||
if (put_str[1] != 'T' || put_str[2] != '0')
|
||||
return 1;
|
||||
kgdb_hex2long(&ptr, &sstep_thread_id);
|
||||
return 0;
|
||||
}
|
||||
switch (sstep_state) {
|
||||
case 1:
|
||||
@ -411,8 +492,7 @@ static int emul_sstep_put(char *put_str, char *arg)
|
||||
v2printk("Stopped at IP: %lx\n",
|
||||
instruction_pointer(&kgdbts_regs));
|
||||
/* Want to stop at IP + break instruction size by default */
|
||||
sstep_addr = instruction_pointer(&kgdbts_regs) +
|
||||
BREAK_INSTR_SIZE;
|
||||
sstep_addr = cont_addr + BREAK_INSTR_SIZE;
|
||||
break;
|
||||
case 2:
|
||||
if (strncmp(put_str, "$OK", 3)) {
|
||||
@ -424,6 +504,9 @@ static int emul_sstep_put(char *put_str, char *arg)
|
||||
if (strncmp(put_str, "$T0", 3)) {
|
||||
eprintk("kgdbts: failed continue sstep\n");
|
||||
return 1;
|
||||
} else {
|
||||
char *ptr = &put_str[11];
|
||||
kgdb_hex2long(&ptr, &sstep_thread_id);
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
@ -502,10 +585,10 @@ static struct test_struct bad_read_test[] = {
|
||||
static struct test_struct singlestep_break_test[] = {
|
||||
{ "?", "S0*" }, /* Clear break points */
|
||||
{ "kgdbts_break_test", "OK", sw_break, }, /* set sw breakpoint */
|
||||
{ "c", "T0*", }, /* Continue */
|
||||
{ "c", "T0*", NULL, get_thread_id_continue }, /* Continue */
|
||||
{ "kgdbts_break_test", "OK", sw_rem_break }, /*remove breakpoint */
|
||||
{ "g", "kgdbts_break_test", NULL, check_and_rewind_pc },
|
||||
{ "write", "OK", write_regs }, /* Write registers */
|
||||
{ "kgdbts_break_test", "OK", sw_rem_break }, /*remove breakpoint */
|
||||
{ "s", "T0*", emul_sstep_get, emul_sstep_put }, /* Single step */
|
||||
{ "g", "kgdbts_break_test", NULL, check_single_step },
|
||||
{ "kgdbts_break_test", "OK", sw_break, }, /* set sw breakpoint */
|
||||
@ -523,16 +606,16 @@ static struct test_struct singlestep_break_test[] = {
|
||||
static struct test_struct do_fork_test[] = {
|
||||
{ "?", "S0*" }, /* Clear break points */
|
||||
{ "do_fork", "OK", sw_break, }, /* set sw breakpoint */
|
||||
{ "c", "T0*", }, /* Continue */
|
||||
{ "g", "do_fork", NULL, check_and_rewind_pc }, /* check location */
|
||||
{ "write", "OK", write_regs }, /* Write registers */
|
||||
{ "c", "T0*", NULL, get_thread_id_continue }, /* Continue */
|
||||
{ "do_fork", "OK", sw_rem_break }, /*remove breakpoint */
|
||||
{ "g", "do_fork", NULL, check_and_rewind_pc }, /* check location */
|
||||
{ "write", "OK", write_regs, emul_reset }, /* Write registers */
|
||||
{ "s", "T0*", emul_sstep_get, emul_sstep_put }, /* Single step */
|
||||
{ "g", "do_fork", NULL, check_single_step },
|
||||
{ "do_fork", "OK", sw_break, }, /* set sw breakpoint */
|
||||
{ "7", "T0*", skip_back_repeat_test }, /* Loop based on repeat_test */
|
||||
{ "D", "OK", NULL, final_ack_set }, /* detach and unregister I/O */
|
||||
{ "", "" },
|
||||
{ "", "", get_cont_catch, put_cont_catch },
|
||||
};
|
||||
|
||||
/* Test for hitting a breakpoint at sys_open for what ever the number
|
||||
@ -541,16 +624,16 @@ static struct test_struct do_fork_test[] = {
|
||||
static struct test_struct sys_open_test[] = {
|
||||
{ "?", "S0*" }, /* Clear break points */
|
||||
{ "sys_open", "OK", sw_break, }, /* set sw breakpoint */
|
||||
{ "c", "T0*", }, /* Continue */
|
||||
{ "g", "sys_open", NULL, check_and_rewind_pc }, /* check location */
|
||||
{ "write", "OK", write_regs }, /* Write registers */
|
||||
{ "c", "T0*", NULL, get_thread_id_continue }, /* Continue */
|
||||
{ "sys_open", "OK", sw_rem_break }, /*remove breakpoint */
|
||||
{ "g", "sys_open", NULL, check_and_rewind_pc }, /* check location */
|
||||
{ "write", "OK", write_regs, emul_reset }, /* Write registers */
|
||||
{ "s", "T0*", emul_sstep_get, emul_sstep_put }, /* Single step */
|
||||
{ "g", "sys_open", NULL, check_single_step },
|
||||
{ "sys_open", "OK", sw_break, }, /* set sw breakpoint */
|
||||
{ "7", "T0*", skip_back_repeat_test }, /* Loop based on repeat_test */
|
||||
{ "D", "OK", NULL, final_ack_set }, /* detach and unregister I/O */
|
||||
{ "", "" },
|
||||
{ "", "", get_cont_catch, put_cont_catch },
|
||||
};
|
||||
|
||||
/*
|
||||
@ -693,8 +776,8 @@ static int run_simple_test(int is_get_char, int chr)
|
||||
/* This callback is a put char which is when kgdb sends data to
|
||||
* this I/O module.
|
||||
*/
|
||||
if (ts.tst[ts.idx].get[0] == '\0' &&
|
||||
ts.tst[ts.idx].put[0] == '\0') {
|
||||
if (ts.tst[ts.idx].get[0] == '\0' && ts.tst[ts.idx].put[0] == '\0' &&
|
||||
!ts.tst[ts.idx].get_handler) {
|
||||
eprintk("kgdbts: ERROR: beyond end of test on"
|
||||
" '%s' line %i\n", ts.name, ts.idx);
|
||||
return 0;
|
||||
@ -907,6 +990,17 @@ static void kgdbts_run_tests(void)
|
||||
if (ptr)
|
||||
sstep_test = simple_strtol(ptr+1, NULL, 10);
|
||||
|
||||
/* All HW break point tests */
|
||||
if (arch_kgdb_ops.flags & KGDB_HW_BREAKPOINT) {
|
||||
hwbreaks_ok = 1;
|
||||
v1printk("kgdbts:RUN hw breakpoint test\n");
|
||||
run_breakpoint_test(1);
|
||||
v1printk("kgdbts:RUN hw write breakpoint test\n");
|
||||
run_hw_break_test(1);
|
||||
v1printk("kgdbts:RUN access write breakpoint test\n");
|
||||
run_hw_break_test(0);
|
||||
}
|
||||
|
||||
/* required internal KGDB tests */
|
||||
v1printk("kgdbts:RUN plant and detach test\n");
|
||||
run_plant_and_detach_test(0);
|
||||
@ -924,35 +1018,11 @@ static void kgdbts_run_tests(void)
|
||||
|
||||
/* ===Optional tests=== */
|
||||
|
||||
/* All HW break point tests */
|
||||
if (arch_kgdb_ops.flags & KGDB_HW_BREAKPOINT) {
|
||||
hwbreaks_ok = 1;
|
||||
v1printk("kgdbts:RUN hw breakpoint test\n");
|
||||
run_breakpoint_test(1);
|
||||
v1printk("kgdbts:RUN hw write breakpoint test\n");
|
||||
run_hw_break_test(1);
|
||||
v1printk("kgdbts:RUN access write breakpoint test\n");
|
||||
run_hw_break_test(0);
|
||||
}
|
||||
|
||||
if (nmi_sleep) {
|
||||
v1printk("kgdbts:RUN NMI sleep %i seconds test\n", nmi_sleep);
|
||||
run_nmi_sleep_test(nmi_sleep);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DEBUG_RODATA
|
||||
/* Until there is an api to write to read-only text segments, use
|
||||
* HW breakpoints for the remainder of any tests, else print a
|
||||
* failure message if hw breakpoints do not work.
|
||||
*/
|
||||
if (!(arch_kgdb_ops.flags & KGDB_HW_BREAKPOINT && hwbreaks_ok)) {
|
||||
eprintk("kgdbts: HW breakpoints do not work,"
|
||||
"skipping remaining tests\n");
|
||||
return;
|
||||
}
|
||||
force_hwbrks = 1;
|
||||
#endif /* CONFIG_DEBUG_RODATA */
|
||||
|
||||
/* If the do_fork test is run it will be the last test that is
|
||||
* executed because a kernel thread will be spawned at the very
|
||||
* end to unregister the debug hooks.
|
||||
|
@ -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 {
|
||||
@ -207,8 +208,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.
|
||||
|
@ -160,37 +160,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);
|
||||
@ -234,7 +236,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;
|
||||
@ -243,16 +244,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;
|
||||
@ -301,7 +301,6 @@ int dbg_set_sw_break(unsigned long addr)
|
||||
|
||||
int dbg_deactivate_sw_breakpoints(void)
|
||||
{
|
||||
unsigned long addr;
|
||||
int error;
|
||||
int ret = 0;
|
||||
int i;
|
||||
@ -309,15 +308,14 @@ int dbg_deactivate_sw_breakpoints(void)
|
||||
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;
|
||||
@ -351,7 +349,6 @@ int kgdb_isremovedbreak(unsigned long addr)
|
||||
|
||||
int dbg_remove_all_break(void)
|
||||
{
|
||||
unsigned long addr;
|
||||
int error;
|
||||
int i;
|
||||
|
||||
@ -359,12 +356,10 @@ int dbg_remove_all_break(void)
|
||||
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;
|
||||
}
|
||||
|
@ -743,7 +743,7 @@ kdb_printit:
|
||||
kdb_input_flush();
|
||||
c = console_drivers;
|
||||
|
||||
if (!dbg_io_ops->is_console) {
|
||||
if (dbg_io_ops && !dbg_io_ops->is_console) {
|
||||
len = strlen(moreprompt);
|
||||
cp = moreprompt;
|
||||
while (len--) {
|
||||
|
Loading…
Reference in New Issue
Block a user