[PATCH 1/5] KGDB: improve early init

From: Jan Kiszka
Date: Tue Jan 29 2008 - 18:44:36 EST


[Warning in advance]
This patch reintroduces the early KGDB_CONSOLE registration issue: If
you switch this on, trigger the debugger before any tty-providing
console was registered and you do not provide an explicit console=
parameter, you end up with a panic due to lacking /dev/console. But this
time I have a better fix (for register_console), will be posted
separately later on.

<--snip-->

In case "kgdbwait" is passed as kernel parameter, KGDB tries to set up
and connect to the front-end already during early_param evaluation. This
fails on x86 as the exception stack is not yet initialized, effectively
delaying kgdbwait until late-init.

Therefore, this patch hooks into the x86 trap initialization and
re-triggers the KGDB setup, including a potential early rendezvous with
gdb. As a precondition, KGDB's setup states are refactored once again to
allow multiple invocations of kgdb_early_entry and correct tracking of
pending kgdbwait requests.

Signed-off-by: Jan Kiszka <jan.kiszka@xxxxxx>

---
arch/x86/kernel/traps_32.c | 4 +++
arch/x86/kernel/traps_64.c | 4 +++
include/linux/kgdb.h | 7 ++++-
kernel/kgdb.c | 55 ++++++++++++++++++++++++---------------------
4 files changed, 44 insertions(+), 26 deletions(-)

Index: b/arch/x86/kernel/traps_32.c
===================================================================
--- a/arch/x86/kernel/traps_32.c
+++ b/arch/x86/kernel/traps_32.c
@@ -25,6 +25,7 @@
#include <linux/utsname.h>
#include <linux/kprobes.h>
#include <linux/kexec.h>
+#include <linux/kgdb.h>
#include <linux/unwind.h>
#include <linux/uaccess.h>
#include <linux/nmi.h>
@@ -1215,6 +1216,9 @@ void __init trap_init(void)
*/
cpu_init();

+ /* With the TSS set up, it's now save to arm early KGDB. */
+ kgdb_early_entry();
+
trap_init_hook();
}

Index: b/arch/x86/kernel/traps_64.c
===================================================================
--- a/arch/x86/kernel/traps_64.c
+++ b/arch/x86/kernel/traps_64.c
@@ -27,6 +27,7 @@
#include <linux/nmi.h>
#include <linux/kprobes.h>
#include <linux/kexec.h>
+#include <linux/kgdb.h>
#include <linux/unwind.h>
#include <linux/uaccess.h>
#include <linux/bug.h>
@@ -1162,6 +1163,9 @@ void __init trap_init(void)
* Should be a barrier for any external CPU state.
*/
cpu_init();
+
+ /* With the TSS set up, it's now save to arm early KGDB. */
+ kgdb_early_entry();
}


Index: b/include/linux/kgdb.h
===================================================================
--- a/include/linux/kgdb.h
+++ b/include/linux/kgdb.h
@@ -46,7 +46,8 @@ extern struct task_struct *kgdb_usethrea

enum kgdb_initstate {
KGDB_UNINITIALIZED = 0,
- KGDB_SEMI_INITIALIZED,
+ KGDB_ARCH_INITIALIZED,
+ KGDB_DELAYED_CONNECTION,
KGDB_FULLY_INITIALIZED
};

@@ -286,11 +287,15 @@ int kgdb_handle_exception(int ex_vector,
struct pt_regs *regs);
int kgdb_nmihook(int cpu, void *regs);

+void __init kgdb_early_entry(void);
+
extern int debugger_step;
extern atomic_t debugger_active;

#else /* !CONFIG_KGDB */
static const atomic_t debugger_active = ATOMIC_INIT(0);
+
+static inline void kgdb_early_entry(void) { }
#endif /* !CONFIG_KGDB */

#endif /* _KGDB_H_ */
Index: b/kernel/kgdb.c
===================================================================
--- a/kernel/kgdb.c
+++ b/kernel/kgdb.c
@@ -1925,32 +1925,39 @@ void kgdb_unregister_io_module(struct kg
}
EXPORT_SYMBOL_GPL(kgdb_unregister_io_module);

+static void __init kgdb_initial_breakpoint(void)
+{
+ printk(KERN_CRIT "kgdb: Waiting for connection from remote gdb...\n");
+ breakpoint();
+}
+
/*
* This function can be called very early, either via early_param() or
* an explicit breakpoint() early on.
*/
-static void __init kgdb_early_entry(void)
+void __init kgdb_early_entry(void)
{
+ int need_break = (kgdb_state == KGDB_DELAYED_CONNECTION);
+
/* Let the architecture do any setup that it needs to. */
- kgdb_arch_init();
+ if (kgdb_state == KGDB_UNINITIALIZED) {
+ kgdb_arch_init();
+ kgdb_state = KGDB_ARCH_INITIALIZED;
+ }

/*
* Don't try and do anything until the architecture is able to
* setup the exception stack. In this case, it is up to the
* architecture to hook in and look at us when they are ready.
*/
-
- if (!EXCEPTION_STACK_READY()) {
- kgdb_state = KGDB_SEMI_INITIALIZED;
- /* any kind of break point is deferred to late_init */
+ if (!EXCEPTION_STACK_READY())
return;
- }

/* Now try the I/O. */
/* For early entry kgdb_io_ops.init must be defined */
if (!kgdb_io_ops.init || kgdb_io_ops.init()) {
- /* Try again later. */
- kgdb_state = KGDB_SEMI_INITIALIZED;
+ printk(KERN_ERR "kgdb: Could not setup core I/O for KGDB.\n");
+ printk(KERN_INFO "kgdb: Defering I/O setup to late init.\n");
return;
}

@@ -1964,6 +1971,9 @@ static void __init kgdb_early_entry(void
*/
if (kgdb_io_ops.init)
kgdb_register_for_panic();
+
+ if (need_break)
+ kgdb_initial_breakpoint();
}

/*
@@ -1974,14 +1984,16 @@ static void __init kgdb_early_entry(void
*/
static int __init kgdb_late_entry(void)
{
- int need_break = (kgdb_state == KGDB_SEMI_INITIALIZED);
+ int need_break = (kgdb_state == KGDB_DELAYED_CONNECTION);

/*
* If we haven't tried to initialize KGDB yet, we need to call
* kgdb_arch_init before moving onto the I/O.
*/
- if (kgdb_state == KGDB_UNINITIALIZED)
+ if (kgdb_state == KGDB_UNINITIALIZED) {
kgdb_arch_init();
+ kgdb_state = KGDB_ARCH_INITIALIZED;
+ }

if (kgdb_state != KGDB_FULLY_INITIALIZED) {
if (kgdb_io_ops.init && kgdb_io_ops.init()) {
@@ -2015,11 +2027,8 @@ static int __init kgdb_late_entry(void)
if (kgdb_io_ops.late_init)
kgdb_io_ops.late_init();

- if (need_break) {
- printk(KERN_CRIT "kgdb: Waiting for connection from remote"
- " gdb...\n");
- breakpoint();
- }
+ if (need_break)
+ kgdb_initial_breakpoint();

return 0;
}
@@ -2072,7 +2081,6 @@ module_init(gdb_register_sysrq);
static int kgdb_notify_reboot(struct notifier_block *this,
unsigned long code, void *x)
{
-
unsigned long flags;

/* If we're debugging, or KGDB has not connected, don't try
@@ -2093,6 +2101,7 @@ static int __init opt_kgdb_attachwait(ch
attachwait = 1;
return 0;
}
+
static int __init opt_kgdb_enter(char *str)
{
/* We've already done this by an explicit breakpoint() call. */
@@ -2101,15 +2110,11 @@ static int __init opt_kgdb_enter(char *s

kgdb_early_entry();
attachwait = 1;
- if (kgdb_state == KGDB_FULLY_INITIALIZED)
- printk(KERN_CRIT "Waiting for connection from remote "
- "gdb...\n");
- else {
- printk(KERN_CRIT "KGDB cannot initialize I/O yet.\n");
- return 0;
- }

- breakpoint();
+ if (kgdb_state == KGDB_FULLY_INITIALIZED)
+ kgdb_initial_breakpoint();
+ else
+ kgdb_state = KGDB_DELAYED_CONNECTION;

return 0;
}
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/