aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/DocBook/kgdb.tmpl8
-rw-r--r--drivers/misc/kgdbts.c75
-rw-r--r--include/linux/kgdb.h4
-rw-r--r--kernel/kgdb.c8
-rw-r--r--lib/Kconfig.kgdb16
5 files changed, 64 insertions, 47 deletions
diff --git a/Documentation/DocBook/kgdb.tmpl b/Documentation/DocBook/kgdb.tmpl
index 97618bed4d6..028a8444d95 100644
--- a/Documentation/DocBook/kgdb.tmpl
+++ b/Documentation/DocBook/kgdb.tmpl
@@ -72,7 +72,7 @@
kgdb is a source level debugger for linux kernel. It is used along
with gdb to debug a linux kernel. The expectation is that gdb can
be used to "break in" to the kernel to inspect memory, variables
- and look through a cal stack information similar to what an
+ and look through call stack information similar to what an
application developer would use gdb for. It is possible to place
breakpoints in kernel code and perform some limited execution
stepping.
@@ -93,8 +93,10 @@
<chapter id="CompilingAKernel">
<title>Compiling a kernel</title>
<para>
- To enable <symbol>CONFIG_KGDB</symbol>, look under the "Kernel debugging"
- and then select "KGDB: kernel debugging with remote gdb".
+ To enable <symbol>CONFIG_KGDB</symbol> you should first turn on
+ "Prompt for development and/or incomplete code/drivers"
+ (CONFIG_EXPERIMENTAL) in "General setup", then under the
+ "Kernel debugging" select "KGDB: kernel debugging with remote gdb".
</para>
<para>
Next you should choose one of more I/O drivers to interconnect debugging
diff --git a/drivers/misc/kgdbts.c b/drivers/misc/kgdbts.c
index 30a1af857c7..fa394104339 100644
--- a/drivers/misc/kgdbts.c
+++ b/drivers/misc/kgdbts.c
@@ -47,6 +47,7 @@
* to test the HW NMI watchdog
* F## = Break at do_fork for ## iterations
* S## = Break at sys_open for ## iterations
+ * I## = Run the single step test ## iterations
*
* NOTE: that the do_fork and sys_open tests are mutually exclusive.
*
@@ -375,7 +376,7 @@ static void emul_sstep_get(char *arg)
break;
case 1:
/* set breakpoint */
- break_helper("Z0", 0, sstep_addr);
+ break_helper("Z0", NULL, sstep_addr);
break;
case 2:
/* Continue */
@@ -383,7 +384,7 @@ static void emul_sstep_get(char *arg)
break;
case 3:
/* Clear breakpoint */
- break_helper("z0", 0, sstep_addr);
+ break_helper("z0", NULL, sstep_addr);
break;
default:
eprintk("kgdbts: ERROR failed sstep get emulation\n");
@@ -465,11 +466,11 @@ static struct test_struct sw_breakpoint_test[] = {
{ "?", "S0*" }, /* Clear break points */
{ "kgdbts_break_test", "OK", sw_break, }, /* set sw breakpoint */
{ "c", "T0*", }, /* Continue */
- { "g", "kgdbts_break_test", 0, check_and_rewind_pc },
+ { "g", "kgdbts_break_test", NULL, check_and_rewind_pc },
{ "write", "OK", write_regs },
{ "kgdbts_break_test", "OK", sw_rem_break }, /*remove breakpoint */
{ "D", "OK" }, /* Detach */
- { "D", "OK", 0, got_break }, /* If the test worked we made it here */
+ { "D", "OK", NULL, got_break }, /* On success we made it here */
{ "", "" },
};
@@ -499,14 +500,14 @@ static struct test_struct singlestep_break_test[] = {
{ "?", "S0*" }, /* Clear break points */
{ "kgdbts_break_test", "OK", sw_break, }, /* set sw breakpoint */
{ "c", "T0*", }, /* Continue */
- { "g", "kgdbts_break_test", 0, check_and_rewind_pc },
+ { "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", 0, check_single_step },
+ { "g", "kgdbts_break_test", NULL, check_single_step },
{ "kgdbts_break_test", "OK", sw_break, }, /* set sw breakpoint */
{ "c", "T0*", }, /* Continue */
- { "g", "kgdbts_break_test", 0, check_and_rewind_pc },
+ { "g", "kgdbts_break_test", NULL, check_and_rewind_pc },
{ "write", "OK", write_regs }, /* Write registers */
{ "D", "OK" }, /* Remove all breakpoints and continues */
{ "", "" },
@@ -520,14 +521,14 @@ 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", 0, check_and_rewind_pc }, /* check location */
+ { "g", "do_fork", NULL, check_and_rewind_pc }, /* check location */
{ "write", "OK", write_regs }, /* Write registers */
{ "do_fork", "OK", sw_rem_break }, /*remove breakpoint */
{ "s", "T0*", emul_sstep_get, emul_sstep_put }, /* Single step */
- { "g", "do_fork", 0, check_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", 0, final_ack_set }, /* detach and unregister I/O */
+ { "D", "OK", NULL, final_ack_set }, /* detach and unregister I/O */
{ "", "" },
};
@@ -538,14 +539,14 @@ 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", 0, check_and_rewind_pc }, /* check location */
+ { "g", "sys_open", NULL, check_and_rewind_pc }, /* check location */
{ "write", "OK", write_regs }, /* Write registers */
{ "sys_open", "OK", sw_rem_break }, /*remove breakpoint */
{ "s", "T0*", emul_sstep_get, emul_sstep_put }, /* Single step */
- { "g", "sys_open", 0, check_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", 0, final_ack_set }, /* detach and unregister I/O */
+ { "D", "OK", NULL, final_ack_set }, /* detach and unregister I/O */
{ "", "" },
};
@@ -556,11 +557,11 @@ static struct test_struct hw_breakpoint_test[] = {
{ "?", "S0*" }, /* Clear break points */
{ "kgdbts_break_test", "OK", hw_break, }, /* set hw breakpoint */
{ "c", "T0*", }, /* Continue */
- { "g", "kgdbts_break_test", 0, check_and_rewind_pc },
+ { "g", "kgdbts_break_test", NULL, check_and_rewind_pc },
{ "write", "OK", write_regs },
{ "kgdbts_break_test", "OK", hw_rem_break }, /*remove breakpoint */
{ "D", "OK" }, /* Detach */
- { "D", "OK", 0, got_break }, /* If the test worked we made it here */
+ { "D", "OK", NULL, got_break }, /* On success we made it here */
{ "", "" },
};
@@ -570,12 +571,12 @@ static struct test_struct hw_breakpoint_test[] = {
static struct test_struct hw_write_break_test[] = {
{ "?", "S0*" }, /* Clear break points */
{ "hw_break_val", "OK", hw_write_break, }, /* set hw breakpoint */
- { "c", "T0*", 0, got_break }, /* Continue */
- { "g", "silent", 0, check_and_rewind_pc },
+ { "c", "T0*", NULL, got_break }, /* Continue */
+ { "g", "silent", NULL, check_and_rewind_pc },
{ "write", "OK", write_regs },
{ "hw_break_val", "OK", hw_rem_write_break }, /*remove breakpoint */
{ "D", "OK" }, /* Detach */
- { "D", "OK", 0, got_break }, /* If the test worked we made it here */
+ { "D", "OK", NULL, got_break }, /* On success we made it here */
{ "", "" },
};
@@ -585,12 +586,12 @@ static struct test_struct hw_write_break_test[] = {
static struct test_struct hw_access_break_test[] = {
{ "?", "S0*" }, /* Clear break points */
{ "hw_break_val", "OK", hw_access_break, }, /* set hw breakpoint */
- { "c", "T0*", 0, got_break }, /* Continue */
- { "g", "silent", 0, check_and_rewind_pc },
+ { "c", "T0*", NULL, got_break }, /* Continue */
+ { "g", "silent", NULL, check_and_rewind_pc },
{ "write", "OK", write_regs },
{ "hw_break_val", "OK", hw_rem_access_break }, /*remove breakpoint */
{ "D", "OK" }, /* Detach */
- { "D", "OK", 0, got_break }, /* If the test worked we made it here */
+ { "D", "OK", NULL, got_break }, /* On success we made it here */
{ "", "" },
};
@@ -599,9 +600,9 @@ static struct test_struct hw_access_break_test[] = {
*/
static struct test_struct nmi_sleep_test[] = {
{ "?", "S0*" }, /* Clear break points */
- { "c", "T0*", 0, got_break }, /* Continue */
+ { "c", "T0*", NULL, got_break }, /* Continue */
{ "D", "OK" }, /* Detach */
- { "D", "OK", 0, got_break }, /* If the test worked we made it here */
+ { "D", "OK", NULL, got_break }, /* On success we made it here */
{ "", "" },
};
@@ -874,18 +875,23 @@ static void kgdbts_run_tests(void)
{
char *ptr;
int fork_test = 0;
- int sys_open_test = 0;
+ int do_sys_open_test = 0;
+ int sstep_test = 1000;
int nmi_sleep = 0;
+ int i;
ptr = strstr(config, "F");
if (ptr)
- fork_test = simple_strtol(ptr+1, NULL, 10);
+ fork_test = simple_strtol(ptr + 1, NULL, 10);
ptr = strstr(config, "S");
if (ptr)
- sys_open_test = simple_strtol(ptr+1, NULL, 10);
+ do_sys_open_test = simple_strtol(ptr + 1, NULL, 10);
ptr = strstr(config, "N");
if (ptr)
nmi_sleep = simple_strtol(ptr+1, NULL, 10);
+ ptr = strstr(config, "I");
+ if (ptr)
+ sstep_test = simple_strtol(ptr+1, NULL, 10);
/* required internal KGDB tests */
v1printk("kgdbts:RUN plant and detach test\n");
@@ -894,8 +900,13 @@ static void kgdbts_run_tests(void)
run_breakpoint_test(0);
v1printk("kgdbts:RUN bad memory access test\n");
run_bad_read_test();
- v1printk("kgdbts:RUN singlestep breakpoint test\n");
- run_singlestep_break_test();
+ v1printk("kgdbts:RUN singlestep test %i iterations\n", sstep_test);
+ for (i = 0; i < sstep_test; i++) {
+ run_singlestep_break_test();
+ if (i % 100 == 0)
+ v1printk("kgdbts:RUN singlestep [%i/%i]\n",
+ i, sstep_test);
+ }
/* ===Optional tests=== */
@@ -922,7 +933,7 @@ static void kgdbts_run_tests(void)
repeat_test = fork_test;
printk(KERN_INFO "kgdbts:RUN do_fork for %i breakpoints\n",
repeat_test);
- kthread_run(kgdbts_unreg_thread, 0, "kgdbts_unreg");
+ kthread_run(kgdbts_unreg_thread, NULL, "kgdbts_unreg");
run_do_fork_test();
return;
}
@@ -931,11 +942,11 @@ static void kgdbts_run_tests(void)
* executed because a kernel thread will be spawned at the very
* end to unregister the debug hooks.
*/
- if (sys_open_test) {
- repeat_test = sys_open_test;
+ if (do_sys_open_test) {
+ repeat_test = do_sys_open_test;
printk(KERN_INFO "kgdbts:RUN sys_open for %i breakpoints\n",
repeat_test);
- kthread_run(kgdbts_unreg_thread, 0, "kgdbts_unreg");
+ kthread_run(kgdbts_unreg_thread, NULL, "kgdbts_unreg");
run_sys_open_test();
return;
}
diff --git a/include/linux/kgdb.h b/include/linux/kgdb.h
index 9757b1a6d9d..6adcc297e35 100644
--- a/include/linux/kgdb.h
+++ b/include/linux/kgdb.h
@@ -261,10 +261,12 @@ struct kgdb_io {
extern struct kgdb_arch arch_kgdb_ops;
+extern unsigned long __weak kgdb_arch_pc(int exception, struct pt_regs *regs);
+
extern int kgdb_register_io_module(struct kgdb_io *local_kgdb_io_ops);
extern void kgdb_unregister_io_module(struct kgdb_io *local_kgdb_io_ops);
-extern int kgdb_hex2long(char **ptr, long *long_val);
+extern int kgdb_hex2long(char **ptr, unsigned long *long_val);
extern int kgdb_mem2hex(char *mem, char *buf, int count);
extern int kgdb_hex2mem(char *buf, char *mem, int count);
diff --git a/kernel/kgdb.c b/kernel/kgdb.c
index 1bd0ec1c80b..39e31a036f5 100644
--- a/kernel/kgdb.c
+++ b/kernel/kgdb.c
@@ -61,7 +61,7 @@ struct kgdb_state {
int err_code;
int cpu;
int pass_exception;
- long threadid;
+ unsigned long threadid;
long kgdb_usethreadid;
struct pt_regs *linux_regs;
};
@@ -146,7 +146,7 @@ atomic_t kgdb_cpu_doing_single_step = ATOMIC_INIT(-1);
* the other CPUs might interfere with your debugging context, so
* use this with care:
*/
-int kgdb_do_roundup = 1;
+static int kgdb_do_roundup = 1;
static int __init opt_nokgdbroundup(char *str)
{
@@ -438,7 +438,7 @@ int kgdb_hex2mem(char *buf, char *mem, int count)
* While we find nice hex chars, build a long_val.
* Return number of chars processed.
*/
-int kgdb_hex2long(char **ptr, long *long_val)
+int kgdb_hex2long(char **ptr, unsigned long *long_val)
{
int hex_val;
int num = 0;
@@ -709,7 +709,7 @@ int kgdb_isremovedbreak(unsigned long addr)
return 0;
}
-int remove_all_break(void)
+static int remove_all_break(void)
{
unsigned long addr;
int error;
diff --git a/lib/Kconfig.kgdb b/lib/Kconfig.kgdb
index f2e01ac5ab0..a5d4b1dac2a 100644
--- a/lib/Kconfig.kgdb
+++ b/lib/Kconfig.kgdb
@@ -1,4 +1,10 @@
+config HAVE_ARCH_KGDB_SHADOW_INFO
+ bool
+
+config HAVE_ARCH_KGDB
+ bool
+
menuconfig KGDB
bool "KGDB: kernel debugging with remote gdb"
select FRAME_POINTER
@@ -10,15 +16,10 @@ menuconfig KGDB
at http://kgdb.sourceforge.net as well as in DocBook form
in Documentation/DocBook/. If unsure, say N.
-config HAVE_ARCH_KGDB_SHADOW_INFO
- bool
-
-config HAVE_ARCH_KGDB
- bool
+if KGDB
config KGDB_SERIAL_CONSOLE
tristate "KGDB: use kgdb over the serial console"
- depends on KGDB
select CONSOLE_POLL
select MAGIC_SYSRQ
default y
@@ -28,7 +29,6 @@ config KGDB_SERIAL_CONSOLE
config KGDB_TESTS
bool "KGDB: internal test suite"
- depends on KGDB
default n
help
This is a kgdb I/O module specifically designed to test
@@ -56,3 +56,5 @@ config KGDB_TESTS_BOOT_STRING
boot. See the drivers/misc/kgdbts.c for detailed
information about other strings you could use beyond the
default of V1F100.
+
+endif # KGDB