Преглед изворни кода

Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jwessel/linux-2.6-kgdb

* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jwessel/linux-2.6-kgdb:
  kgdb: kconfig fix xconfig/menuconfig element
  kgdb: fix signedness mixmatches, add statics, add declaration to header
  kgdb: 1000 loops for the single step test in kgdbts
  kgdb: trivial sparse fixes in kgdb test-suite
  kgdb: minor documentation fixes
Linus Torvalds пре 17 година
родитељ
комит
5717922a1b
5 измењених фајлова са 64 додато и 47 уклоњено
  1. 5 3
      Documentation/DocBook/kgdb.tmpl
  2. 43 32
      drivers/misc/kgdbts.c
  3. 3 1
      include/linux/kgdb.h
  4. 4 4
      kernel/kgdb.c
  5. 9 7
      lib/Kconfig.kgdb

+ 5 - 3
Documentation/DocBook/kgdb.tmpl

@@ -72,7 +72,7 @@
     kgdb is a source level debugger for linux kernel. It is used along
     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
     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
     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
     application developer would use gdb for.  It is possible to place
     breakpoints in kernel code and perform some limited execution
     breakpoints in kernel code and perform some limited execution
     stepping.
     stepping.
@@ -93,8 +93,10 @@
   <chapter id="CompilingAKernel">
   <chapter id="CompilingAKernel">
     <title>Compiling a kernel</title>
     <title>Compiling a kernel</title>
     <para>
     <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>
     <para>
     <para>
     Next you should choose one of more I/O drivers to interconnect debugging
     Next you should choose one of more I/O drivers to interconnect debugging

+ 43 - 32
drivers/misc/kgdbts.c

@@ -47,6 +47,7 @@
  *       to test the HW NMI watchdog
  *       to test the HW NMI watchdog
  * F## = Break at do_fork for ## iterations
  * F## = Break at do_fork for ## iterations
  * S## = Break at sys_open 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.
  * NOTE: that the do_fork and sys_open tests are mutually exclusive.
  *
  *
@@ -375,7 +376,7 @@ static void emul_sstep_get(char *arg)
 		break;
 		break;
 	case 1:
 	case 1:
 		/* set breakpoint */
 		/* set breakpoint */
-		break_helper("Z0", 0, sstep_addr);
+		break_helper("Z0", NULL, sstep_addr);
 		break;
 		break;
 	case 2:
 	case 2:
 		/* Continue */
 		/* Continue */
@@ -383,7 +384,7 @@ static void emul_sstep_get(char *arg)
 		break;
 		break;
 	case 3:
 	case 3:
 		/* Clear breakpoint */
 		/* Clear breakpoint */
-		break_helper("z0", 0, sstep_addr);
+		break_helper("z0", NULL, sstep_addr);
 		break;
 		break;
 	default:
 	default:
 		eprintk("kgdbts: ERROR failed sstep get emulation\n");
 		eprintk("kgdbts: ERROR failed sstep get emulation\n");
@@ -465,11 +466,11 @@ static struct test_struct sw_breakpoint_test[] = {
 	{ "?", "S0*" }, /* Clear break points */
 	{ "?", "S0*" }, /* Clear break points */
 	{ "kgdbts_break_test", "OK", sw_break, }, /* set sw breakpoint */
 	{ "kgdbts_break_test", "OK", sw_break, }, /* set sw breakpoint */
 	{ "c", "T0*", }, /* Continue */
 	{ "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", "OK", write_regs },
 	{ "kgdbts_break_test", "OK", sw_rem_break }, /*remove breakpoint */
 	{ "kgdbts_break_test", "OK", sw_rem_break }, /*remove breakpoint */
 	{ "D", "OK" }, /* Detach */
 	{ "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 */
 	{ "?", "S0*" }, /* Clear break points */
 	{ "kgdbts_break_test", "OK", sw_break, }, /* set sw breakpoint */
 	{ "kgdbts_break_test", "OK", sw_break, }, /* set sw breakpoint */
 	{ "c", "T0*", }, /* Continue */
 	{ "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 */
 	{ "write", "OK", write_regs }, /* Write registers */
 	{ "kgdbts_break_test", "OK", sw_rem_break }, /*remove breakpoint */
 	{ "kgdbts_break_test", "OK", sw_rem_break }, /*remove breakpoint */
 	{ "s", "T0*", emul_sstep_get, emul_sstep_put }, /* Single step */
 	{ "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 */
 	{ "kgdbts_break_test", "OK", sw_break, }, /* set sw breakpoint */
 	{ "c", "T0*", }, /* Continue */
 	{ "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 */
 	{ "write", "OK", write_regs }, /* Write registers */
 	{ "D", "OK" }, /* Remove all breakpoints and continues */
 	{ "D", "OK" }, /* Remove all breakpoints and continues */
 	{ "", "" },
 	{ "", "" },
@@ -520,14 +521,14 @@ static struct test_struct do_fork_test[] = {
 	{ "?", "S0*" }, /* Clear break points */
 	{ "?", "S0*" }, /* Clear break points */
 	{ "do_fork", "OK", sw_break, }, /* set sw breakpoint */
 	{ "do_fork", "OK", sw_break, }, /* set sw breakpoint */
 	{ "c", "T0*", }, /* Continue */
 	{ "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 */
 	{ "write", "OK", write_regs }, /* Write registers */
 	{ "do_fork", "OK", sw_rem_break }, /*remove breakpoint */
 	{ "do_fork", "OK", sw_rem_break }, /*remove breakpoint */
 	{ "s", "T0*", emul_sstep_get, emul_sstep_put }, /* Single step */
 	{ "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 */
 	{ "do_fork", "OK", sw_break, }, /* set sw breakpoint */
 	{ "7", "T0*", skip_back_repeat_test }, /* Loop based on repeat_test */
 	{ "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 */
 	{ "?", "S0*" }, /* Clear break points */
 	{ "sys_open", "OK", sw_break, }, /* set sw breakpoint */
 	{ "sys_open", "OK", sw_break, }, /* set sw breakpoint */
 	{ "c", "T0*", }, /* Continue */
 	{ "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 */
 	{ "write", "OK", write_regs }, /* Write registers */
 	{ "sys_open", "OK", sw_rem_break }, /*remove breakpoint */
 	{ "sys_open", "OK", sw_rem_break }, /*remove breakpoint */
 	{ "s", "T0*", emul_sstep_get, emul_sstep_put }, /* Single step */
 	{ "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 */
 	{ "sys_open", "OK", sw_break, }, /* set sw breakpoint */
 	{ "7", "T0*", skip_back_repeat_test }, /* Loop based on repeat_test */
 	{ "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 */
 	{ "?", "S0*" }, /* Clear break points */
 	{ "kgdbts_break_test", "OK", hw_break, }, /* set hw breakpoint */
 	{ "kgdbts_break_test", "OK", hw_break, }, /* set hw breakpoint */
 	{ "c", "T0*", }, /* Continue */
 	{ "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", "OK", write_regs },
 	{ "kgdbts_break_test", "OK", hw_rem_break }, /*remove breakpoint */
 	{ "kgdbts_break_test", "OK", hw_rem_break }, /*remove breakpoint */
 	{ "D", "OK" }, /* Detach */
 	{ "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[] = {
 static struct test_struct hw_write_break_test[] = {
 	{ "?", "S0*" }, /* Clear break points */
 	{ "?", "S0*" }, /* Clear break points */
 	{ "hw_break_val", "OK", hw_write_break, }, /* set hw breakpoint */
 	{ "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 },
 	{ "write", "OK", write_regs },
 	{ "hw_break_val", "OK", hw_rem_write_break }, /*remove breakpoint */
 	{ "hw_break_val", "OK", hw_rem_write_break }, /*remove breakpoint */
 	{ "D", "OK" }, /* Detach */
 	{ "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[] = {
 static struct test_struct hw_access_break_test[] = {
 	{ "?", "S0*" }, /* Clear break points */
 	{ "?", "S0*" }, /* Clear break points */
 	{ "hw_break_val", "OK", hw_access_break, }, /* set hw breakpoint */
 	{ "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 },
 	{ "write", "OK", write_regs },
 	{ "hw_break_val", "OK", hw_rem_access_break }, /*remove breakpoint */
 	{ "hw_break_val", "OK", hw_rem_access_break }, /*remove breakpoint */
 	{ "D", "OK" }, /* Detach */
 	{ "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[] = {
 static struct test_struct nmi_sleep_test[] = {
 	{ "?", "S0*" }, /* Clear break points */
 	{ "?", "S0*" }, /* Clear break points */
-	{ "c", "T0*", 0, got_break }, /* Continue */
+	{ "c", "T0*", NULL, got_break }, /* Continue */
 	{ "D", "OK" }, /* Detach */
 	{ "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;
 	char *ptr;
 	int fork_test = 0;
 	int fork_test = 0;
-	int sys_open_test = 0;
+	int do_sys_open_test = 0;
+	int sstep_test = 1000;
 	int nmi_sleep = 0;
 	int nmi_sleep = 0;
+	int i;
 
 
 	ptr = strstr(config, "F");
 	ptr = strstr(config, "F");
 	if (ptr)
 	if (ptr)
-		fork_test = simple_strtol(ptr+1, NULL, 10);
+		fork_test = simple_strtol(ptr + 1, NULL, 10);
 	ptr = strstr(config, "S");
 	ptr = strstr(config, "S");
 	if (ptr)
 	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");
 	ptr = strstr(config, "N");
 	if (ptr)
 	if (ptr)
 		nmi_sleep = simple_strtol(ptr+1, NULL, 10);
 		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 */
 	/* required internal KGDB tests */
 	v1printk("kgdbts:RUN plant and detach test\n");
 	v1printk("kgdbts:RUN plant and detach test\n");
@@ -894,8 +900,13 @@ static void kgdbts_run_tests(void)
 	run_breakpoint_test(0);
 	run_breakpoint_test(0);
 	v1printk("kgdbts:RUN bad memory access test\n");
 	v1printk("kgdbts:RUN bad memory access test\n");
 	run_bad_read_test();
 	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=== */
 	/* ===Optional tests=== */
 
 
@@ -922,7 +933,7 @@ static void kgdbts_run_tests(void)
 		repeat_test = fork_test;
 		repeat_test = fork_test;
 		printk(KERN_INFO "kgdbts:RUN do_fork for %i breakpoints\n",
 		printk(KERN_INFO "kgdbts:RUN do_fork for %i breakpoints\n",
 			repeat_test);
 			repeat_test);
-		kthread_run(kgdbts_unreg_thread, 0, "kgdbts_unreg");
+		kthread_run(kgdbts_unreg_thread, NULL, "kgdbts_unreg");
 		run_do_fork_test();
 		run_do_fork_test();
 		return;
 		return;
 	}
 	}
@@ -931,11 +942,11 @@ static void kgdbts_run_tests(void)
 	 * executed because a kernel thread will be spawned at the very
 	 * executed because a kernel thread will be spawned at the very
 	 * end to unregister the debug hooks.
 	 * 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",
 		printk(KERN_INFO "kgdbts:RUN sys_open for %i breakpoints\n",
 			repeat_test);
 			repeat_test);
-		kthread_run(kgdbts_unreg_thread, 0, "kgdbts_unreg");
+		kthread_run(kgdbts_unreg_thread, NULL, "kgdbts_unreg");
 		run_sys_open_test();
 		run_sys_open_test();
 		return;
 		return;
 	}
 	}

+ 3 - 1
include/linux/kgdb.h

@@ -261,10 +261,12 @@ struct kgdb_io {
 
 
 extern struct kgdb_arch		arch_kgdb_ops;
 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 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 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_mem2hex(char *mem, char *buf, int count);
 extern int kgdb_hex2mem(char *buf, char *mem, int count);
 extern int kgdb_hex2mem(char *buf, char *mem, int count);
 
 

+ 4 - 4
kernel/kgdb.c

@@ -61,7 +61,7 @@ struct kgdb_state {
 	int			err_code;
 	int			err_code;
 	int			cpu;
 	int			cpu;
 	int			pass_exception;
 	int			pass_exception;
-	long			threadid;
+	unsigned long		threadid;
 	long			kgdb_usethreadid;
 	long			kgdb_usethreadid;
 	struct pt_regs		*linux_regs;
 	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
  * the other CPUs might interfere with your debugging context, so
  * use this with care:
  * use this with care:
  */
  */
-int				kgdb_do_roundup = 1;
+static int kgdb_do_roundup = 1;
 
 
 static int __init opt_nokgdbroundup(char *str)
 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.
  * While we find nice hex chars, build a long_val.
  * Return number of chars processed.
  * 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 hex_val;
 	int num = 0;
 	int num = 0;
@@ -709,7 +709,7 @@ int kgdb_isremovedbreak(unsigned long addr)
 	return 0;
 	return 0;
 }
 }
 
 
-int remove_all_break(void)
+static int remove_all_break(void)
 {
 {
 	unsigned long addr;
 	unsigned long addr;
 	int error;
 	int error;

+ 9 - 7
lib/Kconfig.kgdb

@@ -1,4 +1,10 @@
 
 
+config HAVE_ARCH_KGDB_SHADOW_INFO
+	bool
+
+config HAVE_ARCH_KGDB
+	bool
+
 menuconfig KGDB
 menuconfig KGDB
 	bool "KGDB: kernel debugging with remote gdb"
 	bool "KGDB: kernel debugging with remote gdb"
 	select FRAME_POINTER
 	select FRAME_POINTER
@@ -10,15 +16,10 @@ menuconfig KGDB
 	  at http://kgdb.sourceforge.net as well as in DocBook form
 	  at http://kgdb.sourceforge.net as well as in DocBook form
 	  in Documentation/DocBook/.  If unsure, say N.
 	  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
 config KGDB_SERIAL_CONSOLE
 	tristate "KGDB: use kgdb over the serial console"
 	tristate "KGDB: use kgdb over the serial console"
-	depends on KGDB
 	select CONSOLE_POLL
 	select CONSOLE_POLL
 	select MAGIC_SYSRQ
 	select MAGIC_SYSRQ
 	default y
 	default y
@@ -28,7 +29,6 @@ config KGDB_SERIAL_CONSOLE
 
 
 config KGDB_TESTS
 config KGDB_TESTS
 	bool "KGDB: internal test suite"
 	bool "KGDB: internal test suite"
-	depends on KGDB
 	default n
 	default n
 	help
 	help
 	  This is a kgdb I/O module specifically designed to test
 	  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
 	  boot.  See the drivers/misc/kgdbts.c for detailed
 	  information about other strings you could use beyond the
 	  information about other strings you could use beyond the
 	  default of V1F100.
 	  default of V1F100.
+
+endif # KGDB