public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* kgdb for mainline kernel: core-lite [patch 1/3]
@ 2004-03-08  9:39 Amit S. Kale
  2004-03-08  9:54 ` Andrew Morton
  0 siblings, 1 reply; 27+ messages in thread
From: Amit S. Kale @ 2004-03-08  9:39 UTC (permalink / raw)
  To: Andrew Morton, Linux Kernel; +Cc: Tom Rini, George Anzinger, Pavel Machek

[-- Attachment #1: Type: text/plain, Size: 482 bytes --]

Hi Andrew,

Here is kgdb for mainline kernel in three patches. This is a lite 
version of kgdb available from kgdb.sourceforge.net. I believe that all of us 
agree on this lite kgdb.

It supports basic debugging of i386 architecture and debugging over a serial 
line. Contents of these patches are as follows:

[1] core-lite.patch: architecture indepndent code
[2] i386-lite.patch: i386 architecture dependent code
[3] 8250.patch: support for generic serial driver

Thanks.
-Amit



[-- Attachment #2: core-lite.patch --]
[-- Type: text/x-diff, Size: 41806 bytes --]

Index: linux-2.6.4-rc2-bk3-kgdb/Makefile
===================================================================
--- linux-2.6.4-rc2-bk3-kgdb.orig/Makefile	2004-03-08 14:30:27.382791896 +0530
+++ linux-2.6.4-rc2-bk3-kgdb/Makefile	2004-03-08 14:31:42.813324712 +0530
@@ -440,6 +440,8 @@
 
 ifndef CONFIG_FRAME_POINTER
 CFLAGS		+= -fomit-frame-pointer
+else
+CFLAGS		+= -fno-omit-frame-pointer
 endif
 
 ifdef CONFIG_DEBUG_INFO
Index: linux-2.6.4-rc2-bk3-kgdb/include/linux/debugger.h
===================================================================
--- linux-2.6.4-rc2-bk3-kgdb.orig/include/linux/debugger.h	2003-01-30 15:54:37.000000000 +0530
+++ linux-2.6.4-rc2-bk3-kgdb/include/linux/debugger.h	2004-03-08 14:31:42.814324560 +0530
@@ -0,0 +1,70 @@
+#ifndef _DEBUGGER_H_
+#define _DEBUGGER_H_
+
+/*
+ * Copyright (C) 2003-2004 Amit S. Kale
+ *
+ * Definition switchout for debuggers
+ */
+
+/*
+ * KGDB
+ */
+#ifdef CONFIG_KGDB
+
+typedef int gdb_debug_hook(int exVector, int signo, int err_code,
+			   struct pt_regs *regs);
+extern gdb_debug_hook *linux_debug_hook;
+#define CHK_DEBUGGER(trapnr,signr,error_code,regs,after)			\
+    {									\
+	if (linux_debug_hook != (gdb_debug_hook *) NULL && !user_mode(regs)) \
+	{								\
+		(*linux_debug_hook)(trapnr, signr, error_code, regs) ;	\
+		after;							\
+	}								\
+    }
+
+void kgdb_nmihook(int cpu, void *regs);
+static inline void debugger_nmihook(int cpu, void *regs)
+{
+	kgdb_nmihook(cpu, regs);
+}
+
+void kgdb_entry(void);
+static inline void debugger_entry(void)
+{
+	kgdb_entry();
+}
+
+extern int debugger_step;
+extern atomic_t debugger_active;
+
+/*
+ * No debugger in the kernel
+ */
+#else
+
+#define CHK_DEBUGGER(trapnr,signr,error_code,regs,after)	\
+{									\
+	if (0)								\
+		after;							\
+}
+
+static inline void debugger_nmihook(int cpu, void *regs)
+{
+	/* Do nothing */
+}
+
+static inline void debugger_entry(void)
+{
+	/* Do nothing */
+}
+
+#define debugger_step 0
+static const atomic_t debugger_active = { 0 };
+
+#define debugger_memerr_expected 0
+
+#endif
+
+#endif				/* _DEBUGGER_H_ */
Index: linux-2.6.4-rc2-bk3-kgdb/include/linux/kgdb.h
===================================================================
--- linux-2.6.4-rc2-bk3-kgdb.orig/include/linux/kgdb.h	2003-01-30 15:54:37.000000000 +0530
+++ linux-2.6.4-rc2-bk3-kgdb/include/linux/kgdb.h	2004-03-08 14:31:42.814324560 +0530
@@ -0,0 +1,128 @@
+#ifndef _KGDB_H_
+#define _KGDB_H_
+
+/*
+ * Copyright (C) 2001-2004 Amit S. Kale
+ */
+
+#include <linux/ptrace.h>
+#include <asm/kgdb.h>
+#include <linux/spinlock.h>
+#include <asm/atomic.h>
+#include <linux/debugger.h>
+
+/*
+ * This file should not include ANY others.  This makes it usable
+ * most anywhere without the fear of include order or inclusion.
+ * TODO: Make it so!
+ *
+ * This file may be included all the time.  It is only active if
+ * CONFIG_KGDB is defined, otherwise it stubs out all the macros
+ * and entry points.
+ */
+
+#if defined(CONFIG_KGDB) && !defined(__ASSEMBLY__)
+/* To enter the debugger explicitly. */
+extern void breakpoint(void);
+extern void kgdb_schedule_breakpoint(void);
+extern void kgdb_process_breakpoint(void);
+extern volatile int kgdb_connected;
+
+#ifndef KGDB_MAX_NO_CPUS
+#if CONFIG_NR_CPUS > 8
+#error KGDB can handle max 8 CPUs
+#endif
+#define KGDB_MAX_NO_CPUS 8
+#endif
+
+extern atomic_t kgdb_setting_breakpoint;
+
+extern struct task_struct *kgdb_usethread, *kgdb_contthread;
+
+enum kgdb_bptype {
+	bp_breakpoint = '0',
+	bp_hardware_breakpoint,
+	bp_write_watchpoint,
+	bp_read_watchpoint,
+	bp_access_watchpoint
+};
+
+enum kgdb_bpstate {
+	bp_disabled,
+	bp_enabled
+};
+
+struct kgdb_bkpt {
+	unsigned long bpt_addr;
+	unsigned char saved_instr[BREAK_INSTR_SIZE];
+	enum kgdb_bptype type;
+	enum kgdb_bpstate state;
+};
+
+#ifndef BREAK_INSTR_SIZE
+#error BREAK_INSTR_SIZE  needed by kgdb
+#endif
+
+#ifndef MAX_BREAKPOINTS
+#define MAX_BREAKPOINTS        16
+#endif
+
+#define KGDB_HW_BREAKPOINT          1
+
+/* These are functions that the arch specific code can, and in some cases
+ * must, provide. */
+extern int kgdb_arch_init(void);
+extern void regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs);
+extern void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs,
+					struct task_struct *p);
+extern void gdb_regs_to_regs(unsigned long *gdb_regs, struct pt_regs *regs);
+extern void kgdb_printexceptioninfo(int exceptionNo, int errorcode,
+				    char *buffer);
+extern void kgdb_disable_hw_debug(struct pt_regs *regs);
+extern void kgdb_post_master_code(struct pt_regs *regs, int eVector,
+				  int err_code);
+extern int kgdb_arch_handle_exception(int vector, int signo, int err_code,
+				      char *InBuffer, char *outBuffer,
+				      struct pt_regs *regs);
+extern int kgdb_arch_set_break(unsigned long addr, int type);
+extern int kgdb_arch_remove_break(unsigned long addr, int type);
+extern void kgdb_correct_hw_break(void);
+extern void kgdb_shadowinfo(struct pt_regs *regs, char *buffer,
+			    unsigned threadid);
+extern struct task_struct *kgdb_get_shadow_thread(struct pt_regs *regs,
+						  int threadid);
+extern struct pt_regs *kgdb_shadow_regs(struct pt_regs *regs, int threadid);
+
+struct kgdb_arch {
+	unsigned char gdb_bpt_instr[BREAK_INSTR_SIZE];
+	unsigned long flags;
+	unsigned shadowth;
+};
+
+/* Thread reference */
+typedef unsigned char threadref[8];
+
+struct kgdb_serial {
+	int (*read_char) (void);
+	void (*write_char) (int);
+	void (*flush) (void);
+	int (*hook) (void);
+};
+
+extern struct kgdb_serial *kgdb_serial;
+extern struct kgdb_arch arch_kgdb_ops;
+extern int kgdb_initialized;
+
+struct uart_port;
+
+extern void kgdb8250_add_port(int i, struct uart_port *serial_req);
+
+int kgdb_hex2long(char **ptr, long *longValue);
+char *kgdb_mem2hex(char *mem, char *buf, int count);
+char *kgdb_hex2mem(char *buf, char *mem, int count);
+int kgdb_get_mem(char *addr, unsigned char *buf, int count);
+
+#else
+#define kgdb_process_breakpoint()      do {} while(0)
+#endif /* KGDB && !__ASSEMBLY__ */
+#endif				/* _KGDB_H_ */
Index: linux-2.6.4-rc2-bk3-kgdb/init/main.c
===================================================================
--- linux-2.6.4-rc2-bk3-kgdb.orig/init/main.c	2004-03-08 14:30:27.283806944 +0530
+++ linux-2.6.4-rc2-bk3-kgdb/init/main.c	2004-03-08 14:31:42.815324408 +0530
@@ -39,6 +39,7 @@
 #include <linux/writeback.h>
 #include <linux/cpu.h>
 #include <linux/efi.h>
+#include <linux/debugger.h>
 
 #include <asm/io.h>
 #include <asm/bugs.h>
@@ -581,6 +582,7 @@
 
 	smp_init();
 	do_basic_setup();
+	debugger_entry();
 
 	prepare_namespace();
 
Index: linux-2.6.4-rc2-bk3-kgdb/kernel/Makefile
===================================================================
--- linux-2.6.4-rc2-bk3-kgdb.orig/kernel/Makefile	2004-03-08 14:30:26.920862120 +0530
+++ linux-2.6.4-rc2-bk3-kgdb/kernel/Makefile	2004-03-08 14:31:42.815324408 +0530
@@ -19,6 +19,7 @@
 obj-$(CONFIG_COMPAT) += compat.o
 obj-$(CONFIG_IKCONFIG) += configs.o
 obj-$(CONFIG_IKCONFIG_PROC) += configs.o
+obj-$(CONFIG_KGDB) += kgdb.o
 
 ifneq ($(CONFIG_IA64),y)
 # According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
Index: linux-2.6.4-rc2-bk3-kgdb/kernel/kgdb.c
===================================================================
--- linux-2.6.4-rc2-bk3-kgdb.orig/kernel/kgdb.c	2003-01-30 15:54:37.000000000 +0530
+++ linux-2.6.4-rc2-bk3-kgdb/kernel/kgdb.c	2004-03-08 14:31:42.818323952 +0530
@@ -0,0 +1,1275 @@
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+/*
+ * Copyright (C) 2000-2001 VERITAS Software Corporation.
+ * Copyright (C) 2002-2004 Timesys Corporation
+ * Copyright (C) 2003-2004 Amit S. Kale
+ * Copyright (C) 2004 Pavel Machek <pavel@suse.cz>
+ * Copyright (C) 2004 Tom Rini <trini@kernel.crashing.org>
+ *
+ * Restructured KGDB for 2.6 kernels.
+ * thread support, support for multiple processors,support for ia-32(x86) 
+ * hardware debugging, Console support, handling nmi watchdog
+ * - Amit S. Kale ( amitkale@emsyssoft.com )
+ *
+ * Several enhancements by George Anzinger <george@mvista.com>
+ * Generic KGDB Support
+ * Implemented by Anurekh Saxena (anurekh.saxena@timesys.com)
+ * 
+ * Contributor:     Lake Stevens Instrument Division
+ * Written by:      Glenn Engel
+ *  
+ * Modified for 386 by Jim Kingdon, Cygnus Support.
+ * Origianl kgdb, compatibility with 2.1.xx kernel by David Grothe <dave@gcom.com>
+ * Integrated into 2.2.5 kernel by Tigran Aivazian <tigran@sco.com>
+ */
+
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <asm/system.h>
+#include <asm/ptrace.h>
+#include <asm/uaccess.h>
+#include <linux/kgdb.h>
+#include <asm/atomic.h>
+#include <linux/notifier.h>
+#include <linux/module.h>
+#include <asm/cacheflush.h>
+#ifdef CONFIG_KGDB_CONSOLE
+#include <linux/console.h>
+#endif
+#include <linux/init.h>
+
+extern int pid_max;
+
+#define BUF_THREAD_ID_SIZE 16
+
+/*
+ * kgdb_initialized indicates that kgdb is setup and is all ready to serve
+ * breakpoints and other kernel exceptions. kgdb_connected indicates that kgdb
+ * has connected to kgdb.
+ */
+int kgdb_initialized = 0;
+volatile int kgdb_connected;
+
+/* If non-zero, wait for a gdb connection when kgdb_entry is called */
+int kgdb_enter = 0;
+
+/* Set to 1 to make kgdb allow access to user addresses. Can be set from gdb
+ * also at runtime. */
+int kgdb_useraccess = 0;
+
+struct kgdb_serial *kgdb_serial;
+
+/*
+ * Holds information about breakpoints in a kernel. These breakpoints are
+ * added and removed by gdb.
+ */
+struct kgdb_bkpt kgdb_break[MAX_BREAKPOINTS];
+
+struct kgdb_arch *kgdb_ops = &arch_kgdb_ops;
+
+static const char hexchars[] = "0123456789abcdef";
+
+static spinlock_t slavecpulocks[KGDB_MAX_NO_CPUS];
+static volatile int procindebug[KGDB_MAX_NO_CPUS];
+atomic_t kgdb_setting_breakpoint;
+struct task_struct *kgdb_usethread, *kgdb_contthread;
+
+int debugger_step;
+atomic_t debugger_active;
+
+/* This will point to kgdb_handle_exception by default.
+ * The architecture code can override this in its init function
+ */
+gdb_debug_hook *linux_debug_hook;
+
+static char remcom_in_buffer[BUFMAX];
+static char remcom_out_buffer[BUFMAX];
+
+/*
+ * The following are the stub functions for code which is arch specific
+ * and can be omitted on some arches
+ * This function will handle the initalization of any architecture specific
+ * hooks.  If there is a suitable early output driver, kgdb_serial
+ * can be pointed at it now.
+ */
+int __attribute__ ((weak))
+    kgdb_arch_init(void)
+{
+	return 0;
+}
+
+void __attribute__ ((weak))
+    regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+{
+}
+
+void __attribute__ ((weak))
+    sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
+{
+}
+
+void __attribute__ ((weak))
+    gdb_regs_to_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+{
+}
+
+void __attribute__ ((weak))
+    kgdb_printexceptioninfo(int exceptionNo, int errorcode, char *buffer)
+{
+}
+
+void __attribute__ ((weak))
+    kgdb_disable_hw_debug(struct pt_regs *regs)
+{
+}
+
+void __attribute__ ((weak))
+    kgdb_post_master_code(struct pt_regs *regs, int eVector, int err_code)
+{
+}
+
+/*
+ * Handle any additional commands.  This must handle the 'c' and 's'
+ * command packets.
+ * Return -1 to loop over other commands, and 0 to exit from KGDB
+ */
+int __attribute__ ((weak))
+    kgdb_arch_handle_exception(int vector, int signo, int err_code, char *InBuffer,
+			   char *outBuffer, struct pt_regs *regs)
+{
+	return 0;
+}
+
+int __attribute__ ((weak))
+    kgdb_arch_set_break(unsigned long addr, int type)
+{
+	return 0;
+}
+
+int __attribute__ ((weak))
+    kgdb_arch_remove_break(unsigned long addr, int type)
+{
+	return 0;
+}
+
+void __attribute__ ((weak))
+    kgdb_correct_hw_break(void)
+{
+}
+
+void __attribute__ ((weak))
+    kgdb_shadowinfo(struct pt_regs *regs, char *buffer, unsigned threadid)
+{
+}
+
+struct task_struct __attribute__ ((weak))
+    * kgdb_get_shadow_thread(struct pt_regs *regs, int threadid)
+{
+	return NULL;
+}
+
+struct pt_regs __attribute__ ((weak))
+    * kgdb_shadow_regs(struct pt_regs *regs, int threadid)
+{
+	return NULL;
+}
+
+static int hex(char ch)
+{
+	if ((ch >= 'a') && (ch <= 'f'))
+		return (ch - 'a' + 10);
+	if ((ch >= '0') && (ch <= '9'))
+		return (ch - '0');
+	if ((ch >= 'A') && (ch <= 'F'))
+		return (ch - 'A' + 10);
+	return (-1);
+}
+
+/* scan for the sequence $<data>#<checksum>	*/
+static void get_packet(char *buffer)
+{
+	unsigned char checksum;
+	unsigned char xmitcsum;
+	int i;
+	int count;
+	char ch;
+
+	do {
+		/* wait around for the start character, ignore all other
+		 * characters */
+		while ((ch = (kgdb_serial->read_char() & 0x7f)) != '$')
+			;	/* Spin. */
+		kgdb_connected = 1;
+		checksum = 0;
+		xmitcsum = -1;
+
+		count = 0;
+
+		/* now, read until a # or end of buffer is found */
+		while (count < (BUFMAX - 1)) {
+			ch = kgdb_serial->read_char() & 0x7f;
+			if (ch == '#')
+				break;
+			checksum = checksum + ch;
+			buffer[count] = ch;
+			count = count + 1;
+		}
+		buffer[count] = 0;
+
+		if (ch == '#') {
+			xmitcsum = hex(kgdb_serial->read_char() & 0x7f) << 4;
+			xmitcsum += hex(kgdb_serial->read_char() & 0x7f);
+
+			if (checksum != xmitcsum)
+				kgdb_serial->write_char('-');	/* failed checksum */
+			else
+				kgdb_serial->write_char('+');	/* successful transfer */
+			if (kgdb_serial->flush)
+				kgdb_serial->flush();
+		}
+	} while (checksum != xmitcsum);
+}
+
+/*
+ * Send the packet in buffer.
+ * Check for gdb connection if asked for.
+ */
+static void put_packet(char *buffer)
+{
+	unsigned char checksum;
+	int count;
+	char ch;
+
+	/*  $<packet info>#<checksum>. */
+	while (1) {
+		kgdb_serial->write_char('$');
+		checksum = 0;
+		count = 0;
+
+		while ((ch = buffer[count])) {
+			kgdb_serial->write_char(ch);
+			checksum += ch;
+			count++;
+		}
+
+		kgdb_serial->write_char('#');
+		kgdb_serial->write_char(hexchars[checksum >> 4]);
+		kgdb_serial->write_char(hexchars[checksum % 16]);
+		if (kgdb_serial->flush)
+			kgdb_serial->flush();
+
+		/* Now see what we get in reply. */
+		ch = kgdb_serial->read_char();
+
+		if (ch == 3)
+			ch = kgdb_serial->read_char();
+
+		/* If we get an ACK, we are done. */
+		if (ch == '+')
+			return;
+
+		/* If we get the start of another packet, this means
+		 * that GDB is attempting to reconnect.  We will NAK
+		 * the packet being sent, and stop trying to send this
+		 * packet. */
+		if (ch == '$') {
+			kgdb_serial->write_char('-');
+			if (kgdb_serial->flush)
+				kgdb_serial->flush();
+			return;
+		}
+	}
+}
+
+static int get_char(char *addr, unsigned char *data)
+{
+	mm_segment_t fs;
+	int ret = 0;
+
+	if (!kgdb_useraccess && (unsigned long)addr < TASK_SIZE) {
+		return -EINVAL;
+	}
+	wmb();
+	fs = get_fs();
+	set_fs(KERNEL_DS);
+
+	if (get_user(*data, addr) != 0) {
+		ret = -EFAULT;
+	}
+
+	set_fs(fs);
+	return ret;
+}
+
+static int set_char(char *addr, int data)
+{
+	mm_segment_t fs;
+	int ret = 0;
+
+	if (!kgdb_useraccess && (unsigned long)addr < TASK_SIZE) {
+		return -EINVAL;
+	}
+	wmb();
+	fs = get_fs();
+	set_fs(KERNEL_DS);
+
+	if (put_user(data, addr) != 0) {
+		ret = -EFAULT;
+	}
+
+	set_fs(fs);
+	return ret;
+}
+
+/*
+ * convert the memory pointed to by mem into hex, placing result in buf
+ * return a pointer to the last char put in buf (null). May return an error.
+ */
+char *kgdb_mem2hex(char *mem, char *buf, int count)
+{
+	int i;
+	unsigned char ch;
+	int error;
+
+	for (i = 0; i < count; i++) {
+
+		if ((error = get_char(mem++, &ch)) < 0)
+			return ERR_PTR(error);
+
+		*buf++ = hexchars[ch >> 4];
+		*buf++ = hexchars[ch % 16];
+	}
+	*buf = 0;
+	return (buf);
+}
+
+/*
+ * convert the hex array pointed to by buf into binary to be placed in mem
+ * return a pointer to the character AFTER the last byte written
+ * May return an error.
+ */
+char *kgdb_hex2mem(char *buf, char *mem, int count)
+{
+	int i;
+	unsigned char ch;
+	int error;
+
+	for (i = 0; i < count; i++) {
+		ch = hex(*buf++) << 4;
+		ch = ch + hex(*buf++);
+		if ((error = set_char(mem++, ch)) < 0)
+			return ERR_PTR(error);
+	}
+	return (mem);
+}
+
+/*
+ * While we find nice hex chars, build a longValue.
+ * Return number of chars processed.
+ */
+int kgdb_hex2long(char **ptr, long *longValue)
+{
+	int numChars = 0;
+	int hexValue;
+
+	*longValue = 0;
+
+	while (**ptr) {
+		hexValue = hex(**ptr);
+		if (hexValue >= 0) {
+			*longValue = (*longValue << 4) | hexValue;
+			numChars++;
+		} else
+			break;
+
+		(*ptr)++;
+	}
+
+	return (numChars);
+}
+
+static inline char *pack_hex_byte(char *pkt, int byte)
+{
+	*pkt++ = hexchars[(byte >> 4) & 0xf];
+	*pkt++ = hexchars[(byte & 0xf)];
+	return pkt;
+}
+
+static inline void error_packet(char *pkt, int error)
+{
+	error = -error;
+	pkt[0] = 'E';
+	pkt[1] = hexchars[(error / 10)];
+	pkt[2] = hexchars[(error % 10)];
+	pkt[3] = '\0';
+}
+
+static char *pack_threadid(char *pkt, threadref * id)
+{
+	char *limit;
+	unsigned char *altid;
+
+	altid = (unsigned char *)id;
+	limit = pkt + BUF_THREAD_ID_SIZE;
+	while (pkt < limit)
+		pkt = pack_hex_byte(pkt, *altid++);
+
+	return pkt;
+}
+
+void int_to_threadref(threadref * id, int value)
+{
+	unsigned char *scan;
+
+	scan = (unsigned char *)id;
+	{
+		int i = 4;
+		while (i--)
+			*scan++ = 0;
+	}
+	*scan++ = (value >> 24) & 0xff;
+	*scan++ = (value >> 16) & 0xff;
+	*scan++ = (value >> 8) & 0xff;
+	*scan++ = (value & 0xff);
+}
+
+static struct task_struct *getthread(struct pt_regs *regs, int tid)
+{
+	int i;
+	struct list_head *l;
+	struct task_struct *p;
+	struct pid *pid;
+
+	if (tid >= pid_max + num_online_cpus() + kgdb_ops->shadowth) {
+		return NULL;
+	}
+	if (tid >= pid_max + num_online_cpus()) {
+		return kgdb_get_shadow_thread(regs, tid - pid_max -
+					      num_online_cpus());
+	}
+	if (tid >= pid_max) {
+		i = 0;
+		for_each_task_pid(0, PIDTYPE_PID, p, l, pid) {
+			if (tid == pid_max + i) {
+				return p;
+			}
+			i++;
+		}
+		return NULL;
+	}
+	if (!tid) {
+		return NULL;
+	}
+	return find_task_by_pid(tid);
+}
+
+#ifdef CONFIG_SMP
+void kgdb_wait(struct pt_regs *regs)
+{
+	unsigned long flags;
+	int processor;
+
+	local_irq_save(flags);
+	processor = smp_processor_id();
+	procindebug[processor] = 1;
+	current->thread.debuggerinfo = regs;
+
+	/* Wait till master processor goes completely into the debugger.
+	 * FIXME: this looks racy */
+	while (!procindebug[atomic_read(&debugger_active) - 1]) {
+		int i = 10;	/* an arbitrary number */
+
+		while (--i)
+			asm volatile ("nop":::"memory");
+		barrier();
+	}
+
+	/* Wait till master processor is done with debugging */
+	spin_lock(slavecpulocks + processor);
+
+	/* This has been taken from x86 kgdb implementation and
+	 * will be needed by architectures that have SMP support
+	 */
+	kgdb_correct_hw_break();
+
+	/* Signal the master processor that we are done */
+	procindebug[processor] = 0;
+	spin_unlock(slavecpulocks + processor);
+	local_irq_restore(flags);
+}
+#endif
+
+int kgdb_get_mem(char *addr, unsigned char *buf, int count)
+{
+	int error;
+	while (count) {
+		if ((error = get_char(addr++, buf)) < 0)
+			return error;
+		buf++;
+		count--;
+	}
+	return 0;
+}
+
+static int set_mem(char *addr, unsigned char *buf, int count)
+{
+	int error;
+	while (count) {
+		if ((error = set_char(addr++, *buf++)) < 0)
+			return error;
+		count--;
+	}
+	return 0;
+}
+
+static int set_break(unsigned long addr)
+{
+	int i, breakno = -1;
+	int error;
+
+	for (i = 0; i < MAX_BREAKPOINTS; i++) {
+		if ((kgdb_break[i].state == bp_enabled) &&
+		    (kgdb_break[i].bpt_addr == addr)) {
+			return -EEXIST;
+		}
+
+		if (kgdb_break[i].state == bp_disabled) {
+			if ((breakno == -1) || (kgdb_break[i].bpt_addr == addr))
+				breakno = i;
+		}
+	}
+	if (breakno == -1)
+		return -E2BIG;
+
+	if ((error = kgdb_get_mem((char *)addr, kgdb_break[breakno].saved_instr,
+				  BREAK_INSTR_SIZE)) < 0)
+		return error;
+
+	if ((error = set_mem((char *)addr, kgdb_ops->gdb_bpt_instr,
+			     BREAK_INSTR_SIZE)) < 0)
+		return error;
+	flush_cache_range(current->mm, addr, addr + BREAK_INSTR_SIZE);
+	flush_icache_range(addr, addr + BREAK_INSTR_SIZE);
+
+	kgdb_break[breakno].state = bp_enabled;
+	kgdb_break[breakno].type = bp_breakpoint;
+	kgdb_break[breakno].bpt_addr = addr;
+
+	return 0;
+}
+
+static int remove_break(unsigned long addr)
+{
+	int i;
+	int error;
+
+	for (i = 0; i < MAX_BREAKPOINTS; i++) {
+		if ((kgdb_break[i].state == bp_enabled) &&
+		    (kgdb_break[i].bpt_addr == addr)) {
+			if ((error =
+			     set_mem((char *)addr, kgdb_break[i].saved_instr,
+				     BREAK_INSTR_SIZE)) < 0)
+				return error;
+			flush_cache_range(current->mm, addr,
+					  addr + BREAK_INSTR_SIZE);
+			flush_icache_range(addr, addr + BREAK_INSTR_SIZE);
+			kgdb_break[i].state = bp_disabled;
+			return 0;
+		}
+	}
+	return -ENOENT;
+}
+
+int remove_all_break(void)
+{
+	int i;
+	int error;
+	for (i = 0; i < MAX_BREAKPOINTS; i++) {
+		if (kgdb_break[i].state == bp_enabled) {
+			unsigned long addr = kgdb_break[i].bpt_addr;
+			if ((error =
+			     set_mem((char *)addr, kgdb_break[i].saved_instr,
+				     BREAK_INSTR_SIZE)) < 0)
+				return error;
+			flush_cache_range(current->mm, addr,
+					  addr + BREAK_INSTR_SIZE);
+			flush_icache_range(addr, addr + BREAK_INSTR_SIZE);
+		}
+		kgdb_break[i].state = bp_disabled;
+	}
+	return 0;
+}
+
+static inline int shadow_pid(int realpid)
+{
+	if (realpid) {
+		return realpid;
+	}
+	return pid_max + smp_processor_id();
+}
+
+/*
+ * This function does all command procesing for interfacing to gdb.
+ *
+ * Locking hierarchy:
+ *	interface locks, if any (begin_session)
+ *	kgdb lock (debugger_active)
+ *
+ */
+int kgdb_handle_exception(int exVector, int signo, int err_code,
+			  struct pt_regs *linux_regs)
+{
+	unsigned long length, addr;
+	char *ptr;
+	unsigned long flags;
+	unsigned long gdb_regs[NUMREGBYTES / sizeof(unsigned long)];
+	int i;
+	long threadid;
+	threadref thref;
+	struct task_struct *thread = NULL;
+	unsigned procid;
+	static char tmpstr[256];
+	int numshadowth = num_online_cpus() + kgdb_ops->shadowth;
+	long kgdb_usethreadid = 0;
+	int error = 0;
+	struct pt_regs *shadowregs;
+
+	/* Panic on recursive debugger calls. */
+	if (atomic_read(&debugger_active) == smp_processor_id() + 1) {
+		return 0;
+	}
+
+	/* 
+	 * Interrupts will be restored by the 'trap return' code, except when
+	 * single stepping.
+	 */
+	local_irq_save(flags);
+
+	/* Hold debugger_active */
+	procid = smp_processor_id();
+	while (cmpxchg(&atomic_read(&debugger_active), 0, (procid + 1)) != 0) {
+		int i = 25;	/* an arbitrary number */
+
+		while (--i)
+			asm volatile ("nop":::"memory");
+	}
+
+	debugger_step = 0;
+
+	current->thread.debuggerinfo = linux_regs;
+
+	kgdb_disable_hw_debug(linux_regs);
+
+	for (i = 0; i < num_online_cpus(); i++) {
+		spin_lock(&slavecpulocks[i]);
+	}
+
+	/* spin_lock code is good enough as a barrier so we don't
+	 * need one here */
+	procindebug[smp_processor_id()] = 1;
+
+	/* Clear the out buffer. */
+	memset(remcom_out_buffer, 0, sizeof(remcom_out_buffer));
+
+	/* Master processor is completely in the debugger */
+	kgdb_post_master_code(linux_regs, exVector, err_code);
+
+	if (kgdb_connected) {
+		/* reply to host that an exception has occurred */
+		ptr = remcom_out_buffer;
+		*ptr++ = 'T';
+		*ptr++ = hexchars[(signo >> 4) % 16];
+		*ptr++ = hexchars[signo % 16];
+		ptr += strlen(strcpy(ptr, "thread:"));
+		int_to_threadref(&thref, shadow_pid(current->pid));
+		ptr = pack_threadid(ptr, &thref);
+		*ptr++ = ';';
+
+		put_packet(remcom_out_buffer);
+	}
+
+	kgdb_usethread = current;
+	kgdb_usethreadid = shadow_pid(current->pid);
+
+	while (1) {
+		int bpt_type = 0;
+		error = 0;
+
+		/* Clear the out buffer. */
+		memset(remcom_out_buffer, 0, sizeof(remcom_out_buffer));
+
+		get_packet(remcom_in_buffer);
+
+		switch (remcom_in_buffer[0]) {
+		case '?':
+			/* We know that this packet is only sent
+			 * during initial connect.  So to be safe,
+			 * we clear out our breakpoints now incase
+			 * GDB is reconnecting. */
+			remove_all_break();
+			remcom_out_buffer[0] = 'S';
+			remcom_out_buffer[1] = hexchars[signo >> 4];
+			remcom_out_buffer[2] = hexchars[signo % 16];
+			break;
+
+		case 'g':	/* return the value of the CPU registers */
+			thread = kgdb_usethread;
+
+			if (!thread)
+				thread = current;
+
+			/* All threads that don't have debuggerinfo should be
+			   in __schedule() sleeping, since all other CPUs
+			   are in kgdb_wait, and thus have debuggerinfo. */
+
+			if (kgdb_usethreadid >= pid_max + num_online_cpus()) {
+				shadowregs = kgdb_shadow_regs(linux_regs,
+							      kgdb_usethreadid -
+							      pid_max -
+							      num_online_cpus
+							      ());
+				if (!shadowregs) {
+					error_packet(remcom_out_buffer,
+						     -EINVAL);
+					break;
+				}
+				regs_to_gdb_regs(gdb_regs, shadowregs);
+			} else if (thread->thread.debuggerinfo) {
+				if ((error =
+				     get_char(thread->thread.debuggerinfo,
+					      (unsigned char *)gdb_regs)) < 0) {
+					error_packet(remcom_out_buffer, error);
+					break;
+				}
+				regs_to_gdb_regs(gdb_regs, (struct pt_regs *)
+						 thread->thread.debuggerinfo);
+			} else {
+				/* Pull stuff saved during 
+				 * switch_to; nothing else is
+				 * accessible (or even particularly relevant).
+				 * This should be enough for a stack trace. */
+				sleeping_thread_to_gdb_regs(gdb_regs, thread);
+			}
+
+			kgdb_mem2hex((char *)gdb_regs, remcom_out_buffer,
+				     NUMREGBYTES);
+			break;
+
+		case 'G':	/* set the value of the CPU registers - return OK */
+			kgdb_hex2mem(&remcom_in_buffer[1], (char *)gdb_regs,
+				     NUMREGBYTES);
+
+			if (kgdb_usethread && kgdb_usethread != current)
+				error_packet(remcom_out_buffer, -EINVAL);
+			else {
+				gdb_regs_to_regs(gdb_regs, (struct pt_regs *)
+						 current->thread.debuggerinfo);
+				strcpy(remcom_out_buffer, "OK");
+			}
+
+			break;
+
+			/* mAA..AA,LLLL  Read LLLL bytes at address AA..AA */
+		case 'm':
+			ptr = &remcom_in_buffer[1];
+			if (kgdb_hex2long(&ptr, &addr) > 0 && *ptr++ == ',' &&
+			    kgdb_hex2long(&ptr, &length) > 0) {
+				if (IS_ERR(ptr = kgdb_mem2hex((char *)addr,
+							      remcom_out_buffer,
+							      length)))
+					error_packet(remcom_out_buffer,
+						     PTR_ERR(ptr));
+			} else
+				error_packet(remcom_out_buffer, -EINVAL);
+			break;
+
+			/* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
+		case 'M':
+			ptr = &remcom_in_buffer[1];
+			if (kgdb_hex2long(&ptr, &addr) > 0 && *(ptr++) == ','
+			    && kgdb_hex2long(&ptr, &length) > 0 &&
+			    *(ptr++) == ':') {
+				if (IS_ERR(ptr = kgdb_hex2mem(ptr, (char *)addr,
+							      length)))
+					error_packet(remcom_out_buffer,
+						     PTR_ERR(ptr));
+			} else
+				error_packet(remcom_out_buffer, -EINVAL);
+			break;
+
+			/* kill or detach. KGDB should treat this like a 
+			 * continue.
+			 */
+		case 'D':
+			if ((error = remove_all_break()) < 0) {
+				error_packet(remcom_out_buffer, error);
+			} else {
+				strcpy(remcom_out_buffer, "OK");
+				kgdb_connected = 0;
+			}
+			put_packet(remcom_out_buffer);
+			goto default_handle;
+
+		case 'k':
+			/* Don't care about error from remove_all_break */
+			remove_all_break();
+			kgdb_connected = 0;
+			goto default_handle;
+
+			/* query */
+		case 'q':
+			switch (remcom_in_buffer[1]) {
+			case 's':
+			case 'f':
+				if (memcmp
+				    (remcom_in_buffer + 2, "ThreadInfo", 10)) {
+					error_packet(remcom_out_buffer,
+						     -EINVAL);
+					break;
+				}
+				if (remcom_in_buffer[1] == 'f') {
+					threadid = 1;
+				}
+				remcom_out_buffer[0] = 'm';
+				ptr = remcom_out_buffer + 1;
+				for (i = 0; i < 32 && threadid < pid_max +
+				     numshadowth; threadid++) {
+					thread = getthread(linux_regs,
+							   threadid);
+					if (thread) {
+						int_to_threadref(&thref,
+								 threadid);
+						pack_threadid(ptr, &thref);
+						ptr += 16;
+						*(ptr++) = ',';
+						i++;
+					}
+				}
+				*(--ptr) = '\0';
+				break;
+
+			case 'C':
+				/* Current thread id */
+				strcpy(remcom_out_buffer, "QC");
+
+				threadid = shadow_pid(current->pid);
+
+				int_to_threadref(&thref, threadid);
+				pack_threadid(remcom_out_buffer + 2, &thref);
+				break;
+
+			case 'E':
+				/* Print exception info */
+				kgdb_printexceptioninfo(exVector, err_code,
+							remcom_out_buffer);
+				break;
+			case 'T':
+				if (memcmp(remcom_in_buffer + 1,
+					   "ThreadExtraInfo,", 16)) {
+					error_packet(remcom_out_buffer,
+						     -EINVAL);
+					break;
+				}
+				threadid = 0;
+				ptr = remcom_in_buffer + 17;
+				kgdb_hex2long(&ptr, &threadid);
+				if (!getthread(linux_regs, threadid)) {
+					error_packet(remcom_out_buffer,
+						     -EINVAL);
+					break;
+				}
+				if (threadid < pid_max) {
+					kgdb_mem2hex(getthread(linux_regs,
+							       threadid)->comm,
+						     remcom_out_buffer, 16);
+				} else if (threadid >= pid_max +
+					   num_online_cpus()) {
+					kgdb_shadowinfo(linux_regs,
+							remcom_out_buffer,
+							threadid - pid_max -
+							num_online_cpus());
+				} else {
+					sprintf(tmpstr, "Shadow task %d"
+						" for pid 0",
+						(int)(threadid - pid_max));
+					kgdb_mem2hex(tmpstr, remcom_out_buffer,
+						     strlen(tmpstr));
+				}
+				break;
+			}
+			break;
+
+			/* task related */
+		case 'H':
+			switch (remcom_in_buffer[1]) {
+			case 'g':
+				ptr = &remcom_in_buffer[2];
+				kgdb_hex2long(&ptr, &threadid);
+				thread = getthread(linux_regs, threadid);
+				if (!thread && threadid > 0) {
+					error_packet(remcom_out_buffer,
+						     -EINVAL);
+					break;
+				}
+				kgdb_usethread = thread;
+				kgdb_usethreadid = threadid;
+				strcpy(remcom_out_buffer, "OK");
+				break;
+
+			case 'c':
+				ptr = &remcom_in_buffer[2];
+				kgdb_hex2long(&ptr, &threadid);
+				if (!threadid) {
+					kgdb_contthread = 0;
+				} else {
+					thread =
+					    getthread(linux_regs, threadid);
+					if (!thread && threadid > 0) {
+						error_packet(remcom_out_buffer,
+							     -EINVAL);
+						break;
+					}
+					kgdb_contthread = thread;
+				}
+				strcpy(remcom_out_buffer, "OK");
+				break;
+			}
+			break;
+
+			/* Query thread status */
+		case 'T':
+			ptr = &remcom_in_buffer[1];
+			kgdb_hex2long(&ptr, &threadid);
+			thread = getthread(linux_regs, threadid);
+			if (thread)
+				strcpy(remcom_out_buffer, "OK");
+			else
+				error_packet(remcom_out_buffer, -EINVAL);
+			break;
+		case 'z':
+		case 'Z':
+			ptr = &remcom_in_buffer[2];
+			if (*(ptr++) != ',') {
+				error_packet(remcom_out_buffer, -EINVAL);
+				break;
+			}
+			kgdb_hex2long(&ptr, &addr);
+
+			bpt_type = remcom_in_buffer[1];
+			if (bpt_type != bp_breakpoint) {
+				if (bpt_type == bp_hardware_breakpoint &&
+				    !(kgdb_ops->flags & KGDB_HW_BREAKPOINT))
+					break;
+
+				/* if set_break is not defined, then
+				 * remove_break does not matter
+				 */
+				if (!(kgdb_ops->flags & KGDB_HW_BREAKPOINT))
+					break;
+			}
+
+			if (remcom_in_buffer[0] == 'Z') {
+				if (bpt_type == bp_breakpoint)
+					error = set_break(addr);
+				else
+					error = kgdb_arch_set_break(addr,
+								    bpt_type);
+			} else {
+				if (bpt_type == bp_breakpoint)
+					error = remove_break(addr);
+				else
+					error = kgdb_arch_remove_break(addr,
+								       bpt_type);
+			}
+
+			if (error == 0)
+				strcpy(remcom_out_buffer, "OK");
+			else
+				error_packet(remcom_out_buffer, error);
+
+			break;
+
+		default:
+		      default_handle:
+			error = kgdb_arch_handle_exception(exVector, signo,
+							   err_code,
+							   remcom_in_buffer,
+							   remcom_out_buffer,
+							   linux_regs);
+
+			if (error >= 0 || remcom_in_buffer[0] == 'D' ||
+			    remcom_in_buffer[0] == 'k')
+				goto kgdb_exit;
+
+		}		/* switch */
+
+		/* reply to the request */
+		put_packet(remcom_out_buffer);
+	}
+
+      kgdb_exit:
+	procindebug[smp_processor_id()] = 0;
+
+	for (i = 0; i < num_online_cpus(); i++) {
+		spin_unlock(&slavecpulocks[i]);
+	}
+	/* Wait till all the processors have quit
+	 * from the debugger 
+	 */
+	for (i = 0; i < num_online_cpus(); i++) {
+		while (procindebug[i]) {
+			int j = 10;	/* an arbitrary number */
+
+			while (--j) {
+				asm volatile ("nop":::"memory");
+			}
+			barrier();
+		}
+	}
+
+	/* Free debugger_active */
+	atomic_set(&debugger_active, 0);
+	local_irq_restore(flags);
+
+	return error;
+}
+
+/*
+ * GDB places a breakpoint at this function to know dynamically
+ * loaded objects. It's not defined static so that only one instance with this
+ * name exists in the kernel.
+ */
+
+int module_event(struct notifier_block *self, unsigned long val, void *data)
+{
+	return 0;
+}
+
+static struct notifier_block kgdb_module_load_nb = {
+	.notifier_call = module_event,
+};
+
+/* This function will generate a breakpoint exception.  It is used at the
+   beginning of a program to sync up with a debugger and can be used
+   otherwise as a quick means to stop program execution and "break" into
+   the debugger. */
+
+void breakpoint(void)
+{
+	if (!kgdb_initialized) {
+		kgdb_enter = 1;
+		kgdb_entry();
+		if (!kgdb_initialized) {
+			printk("kgdb not enabled. Cannot do breakpoint\n");
+			return;
+		}
+	}
+
+	atomic_set(&kgdb_setting_breakpoint, 1);
+	wmb();
+	BREAKPOINT();
+	wmb();
+	atomic_set(&kgdb_setting_breakpoint, 0);
+}
+
+void kgdb_nmihook(int cpu, void *regs)
+{
+#ifdef CONFIG_SMP
+	if (!procindebug[cpu] && atomic_read(&debugger_active) != (cpu + 1)) {
+		kgdb_wait((struct pt_regs *)regs);
+	}
+#endif
+}
+
+void kgdb_entry(void)
+{
+	int i;
+
+	if (kgdb_initialized) {
+		/* KGDB was initialized */
+		return;
+	}
+
+	for (i = 0; i < KGDB_MAX_NO_CPUS; i++)
+		spin_lock_init(&slavecpulocks[i]);
+
+	/* Free debugger_active */
+	atomic_set(&debugger_active, 0);
+
+	for (i = 0; i < MAX_BREAKPOINTS; i++)
+		kgdb_break[i].state = bp_disabled;
+
+	linux_debug_hook = kgdb_handle_exception;
+
+	/* Let the arch do any initalization it needs to, including
+	 * pointing to a suitable early output device. */
+	kgdb_arch_init();
+
+	/* We can't do much if this fails */
+	register_module_notifier(&kgdb_module_load_nb);
+
+	atomic_set(&kgdb_setting_breakpoint, 0);
+
+	if (!kgdb_serial || kgdb_serial->hook() < 0) {
+		/* KGDB interface isn't ready yet */
+		return;
+	}
+	kgdb_initialized = 1;
+	if (!kgdb_enter) {
+		return;
+	}
+	/*
+	 * Call the breakpoint() routine in GDB to start the debugging
+	 * session
+	 */
+	printk(KERN_CRIT "Waiting for connection from remote gdb... ");
+	breakpoint();
+	printk("Connected.\n");
+}
+
+/*
+ * Sometimes we need to schedule a breakpoint because we can't break
+ * right where we are.
+ */
+static int kgdb_need_breakpoint[NR_CPUS];
+
+void kgdb_schedule_breakpoint(void)
+{
+	kgdb_need_breakpoint[smp_processor_id()] = 1;
+}
+
+void kgdb_process_breakpoint(void)
+{
+	/*
+	 * Handle a breakpoint queued from inside network driver code
+	  * to avoid reentrancy issues
+	 */
+	if (kgdb_need_breakpoint[smp_processor_id()]) {
+		 kgdb_need_breakpoint[smp_processor_id()] = 0;
+		 breakpoint();
+	}
+}
+
+#ifdef CONFIG_KGDB_CONSOLE
+char kgdbconbuf[BUFMAX];
+
+void kgdb_console_write(struct console *co, const char *s, unsigned count)
+{
+	int i;
+	int wcount;
+	char *bufptr;
+	unsigned long flags;
+
+	if (!kgdb_connected) {
+		return;
+	}
+	local_irq_save(flags);
+
+	kgdbconbuf[0] = 'O';
+	bufptr = kgdbconbuf + 1;
+	while (count > 0) {
+		if ((count << 1) > (BUFMAX - 2)) {
+			wcount = (BUFMAX - 2) >> 1;
+		} else {
+			wcount = count;
+		}
+		count -= wcount;
+		for (i = 0; i < wcount; i++) {
+			bufptr = pack_hex_byte(bufptr, s[i]);
+		}
+		*bufptr = '\0';
+		s += wcount;
+
+		put_packet(kgdbconbuf);
+
+	}
+	local_irq_restore(flags);
+}
+
+/* Always fail so that kgdb console doesn't become the default console */
+static int __init kgdb_console_setup(struct console *co, char *options)
+{
+	return -1;
+}
+
+static struct console kgdbcons = {
+	.name = "kgdb",
+	.write = kgdb_console_write,
+	.setup = kgdb_console_setup,
+	.flags = CON_PRINTBUFFER | CON_ENABLED,
+	.index = -1,
+};
+
+static int __init kgdb_console_init(void)
+{
+	register_console(&kgdbcons);
+	return 0;
+}
+
+console_initcall(kgdb_console_init);
+#endif
+
+EXPORT_SYMBOL(breakpoint);
+#ifdef CONFIG_KGDB_THREAD
+EXPORT_SYMBOL(kern_schedule);
+#endif
+
+static int __init opt_kgdb_enter(char *str)
+{
+	kgdb_enter = 1;
+	return 1;
+}
+
+static int __init opt_gdb(char *str)
+{
+	kgdb_enter = 1;
+	return 1;
+}
+
+/*
+ * These options have been deprecated and are present only to maintain
+ * compatibility with kgdb for 2.4 and earlier kernels.
+ */
+#ifdef CONFIG_KGDB_8250
+extern int kgdb8250_baud;
+extern int kgdb8250_ttyS;
+static int __init opt_gdbttyS(char *str)
+{
+	kgdb8250_ttyS = simple_strtoul(str, NULL, 10);
+	return 1;
+}
+static int __init opt_gdbbaud(char *str)
+{
+	kgdb8250_baud = simple_strtoul(str, NULL, 10);
+	return 1;
+}
+#endif
+
+/*
+ *
+ * Sequence of following lines has to be maintained because gdb option is a
+ * prefix of the other two options
+ */
+
+#ifdef CONFIG_KGDB_8250
+__setup("gdbttyS=", opt_gdbttyS);
+__setup("gdbbaud=", opt_gdbbaud);
+#endif
+__setup("gdb", opt_gdb);
+__setup("kgdbwait", opt_kgdb_enter);
Index: linux-2.6.4-rc2-bk3-kgdb/kernel/sched.c
===================================================================
--- linux-2.6.4-rc2-bk3-kgdb.orig/kernel/sched.c	2004-03-08 14:30:26.958856344 +0530
+++ linux-2.6.4-rc2-bk3-kgdb/kernel/sched.c	2004-03-08 14:31:42.819323800 +0530
@@ -37,6 +37,7 @@
 #include <linux/rcupdate.h>
 #include <linux/cpu.h>
 #include <linux/percpu.h>
+#include <linux/debugger.h>
 
 #ifdef CONFIG_NUMA
 #define cpu_to_node_mask(cpu) node_to_cpumask(cpu_to_node(cpu))
@@ -2961,6 +2962,8 @@
 #if defined(in_atomic)
 	static unsigned long prev_jiffy;	/* ratelimiting */
 
+	if (atomic_read(&debugger_active))
+		return;
 	if ((in_atomic() || irqs_disabled()) && system_running) {
 		if (time_before(jiffies, prev_jiffy + HZ) && prev_jiffy)
 			return;
Index: linux-2.6.4-rc2-bk3-kgdb/kernel/Kconfig.kgdb
===================================================================
--- linux-2.6.4-rc2-bk3-kgdb.orig/kernel/Kconfig.kgdb	2003-01-30 15:54:37.000000000 +0530
+++ linux-2.6.4-rc2-bk3-kgdb/kernel/Kconfig.kgdb	2004-03-08 14:31:42.820323648 +0530
@@ -0,0 +1,13 @@
+config KGDB
+	bool "KGDB: kernel debugging with remote gdb"
+	depends on DEBUG_KERNEL
+	select DEBUG_INFO
+	select FRAME_POINTER
+	help
+	  If you say Y here, it will be possible to remotely debug the
+	  kernel using gdb. This enlarges your kernel image disk size by
+	  several megabytes and requires a machine with more than 128 MB
+	  RAM to avoid excessive linking time. 
+	  Documentation of kernel debugger available at
+	  http://kgdb.sourceforge.net
+	  This is only useful for kernel hackers. If unsure, say N.
Index: linux-2.6.4-rc2-bk3-kgdb/Documentation/kgdb.txt
===================================================================
--- linux-2.6.4-rc2-bk3-kgdb.orig/Documentation/kgdb.txt	2003-01-30 15:54:37.000000000 +0530
+++ linux-2.6.4-rc2-bk3-kgdb/Documentation/kgdb.txt	2004-03-08 14:31:42.820323648 +0530
@@ -0,0 +1,49 @@
+KGDB Linux kernel source level debugger
+
+Amit S. Kale <amitkale@emsyssoft.com>
+Last updated March 2004.
+
+Introduction:
+kgdb is a source level debugger for linux kernel. It is used along with gdb to
+debug a linux kernel. Kernel developers can debug a kernel similar to
+application programs with the use of kgdb. It makes it possible to place
+breakpoints in kernel code, step through the code and observe variables.
+
+Two machines are required for using kgdb. One of these machines is a
+development machine and the other is a test machine. The machines are
+connected through a serial line, a null-modem cable which connects their
+serial ports. The kernel to be debugged runs on the test machine. gdb runs on
+the development machine. The serial line is used by gdb to communicate to the
+kernel being debugged.
+
+This version of kgdb is a lite version. It is available on i386 platform uses
+a serial line for communicating to gdb. Full kgdb containing more features and
+supporting more architecture is available along with plenty of documentation
+at http://kgdb.sourceforge.net/
+
+Compiling a kernel:
+Enable Kernel hacking -> Kernel Debugging -> KGDB: kernel debugging with
+remote gdb
+
+Only generic serial port (8250) is supported in the lite version. Configure
+8250 options.
+
+Booting the kernel:
+Kernel command line option "kgdbwait" makes kgdb wait for gdb connection
+during booting of a kernel. If you have configured simple serial port, the
+port number and speed can be overriden on command line by using option
+"kgdb8250=portnumber,speed", where port numbers are 0-3 for COM1 to COM4
+respectively and supported speeds are 9600, 19200, 38400, 57600, 115200.
+Example: kgdbwait kgdb8250=0,115200
+
+Connecting gdb:
+If you have used "kgdbwait", kgdb prints a message "Waiting for connection
+from remote gdb..." on the console and waits for connection from gdb. At this
+point you connect gdb to kgdb.
+Example: 
+   % gdb ./vmlinux
+   (gdb) set remotebaud 115200
+   (gdb) target remote /dev/ttyS0
+
+Once connected, you can debug a kernel the way you would debug an application
+program.

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: kgdb for mainline kernel: core-lite [patch 1/3]
  2004-03-08  9:39 kgdb for mainline kernel: core-lite [patch 1/3] Amit S. Kale
@ 2004-03-08  9:54 ` Andrew Morton
  2004-03-08 10:15   ` Amit S. Kale
  0 siblings, 1 reply; 27+ messages in thread
From: Andrew Morton @ 2004-03-08  9:54 UTC (permalink / raw)
  To: Amit S. Kale; +Cc: linux-kernel, trini, george, pavel

"Amit S. Kale" <amitkale@emsyssoft.com> wrote:
>
> Here is kgdb for mainline kernel in three patches.

Thanks for working on this.

> This is a lite 
>  version of kgdb available from kgdb.sourceforge.net. I believe that all of us 
>  agree on this lite kgdb.

What is "lite" about it?  As in, what features have been removed?

>  It supports basic debugging of i386 architecture and debugging over a serial 
>  line. Contents of these patches are as follows:
> 
>  [1] core-lite.patch: architecture indepndent code
>  [2] i386-lite.patch: i386 architecture dependent code
>  [3] 8250.patch: support for generic serial driver

What is the story on kgdboe?

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: kgdb for mainline kernel: core-lite [patch 1/3]
  2004-03-08  9:54 ` Andrew Morton
@ 2004-03-08 10:15   ` Amit S. Kale
  2004-03-08 10:26     ` Andrew Morton
  0 siblings, 1 reply; 27+ messages in thread
From: Amit S. Kale @ 2004-03-08 10:15 UTC (permalink / raw)
  To: Andrew Morton; +Cc: linux-kernel, trini, george, pavel

On Monday 08 Mar 2004 3:24 pm, Andrew Morton wrote:
> "Amit S. Kale" <amitkale@emsyssoft.com> wrote:
> > Here is kgdb for mainline kernel in three patches.
>
> Thanks for working on this.

Credits go to all the kgdb developers.

>
> > This is a lite
> >  version of kgdb available from kgdb.sourceforge.net. I believe that all
> > of us agree on this lite kgdb.
>
> What is "lite" about it?  As in, what features have been removed?

Here are features that are present only in full kgdb:
1. Thread support  (aka info threads)
2. console messages through gdb
3. Automatic loading of modules in gdb
4. Support for x86_64
5. Support for powerpc
6. kgdb over ethernet [This isn't ready in the full version as well at this 
point of time]

-Amit

>
> >  It supports basic debugging of i386 architecture and debugging over a
> > serial line. Contents of these patches are as follows:
> >
> >  [1] core-lite.patch: architecture indepndent code
> >  [2] i386-lite.patch: i386 architecture dependent code
> >  [3] 8250.patch: support for generic serial driver
>
> What is the story on kgdboe?


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: kgdb for mainline kernel: core-lite [patch 1/3]
  2004-03-08 10:15   ` Amit S. Kale
@ 2004-03-08 10:26     ` Andrew Morton
  2004-03-08 10:49       ` Amit S. Kale
  0 siblings, 1 reply; 27+ messages in thread
From: Andrew Morton @ 2004-03-08 10:26 UTC (permalink / raw)
  To: Amit S. Kale; +Cc: linux-kernel, trini, george, pavel

"Amit S. Kale" <amitkale@emsyssoft.com> wrote:
>
> Here are features that are present only in full kgdb:
>  1. Thread support  (aka info threads)

argh, disaster.  I discussed this with Tom a week or so ago when it looked
like this it was being chopped out and I recall being told that the
discussion was referring to something else.

Ho-hum, sorry.  Can we please put this back in?

>  2. console messages through gdb

hm, it was occasionally handy.  Is there a lot of code involved?

>  3. Automatic loading of modules in gdb

OK.  I think.  What does this feature actually do?

>  4. Support for x86_64
>  5. Support for powerpc

These are planned, I assume?

>  6. kgdb over ethernet [This isn't ready in the full version as well at this 
>  point of time]

OK.  But the version in -mm and -mpm works OK, does it not?  Is there some
difference in implementation which causes it to be broken in your tree?


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: kgdb for mainline kernel: core-lite [patch 1/3]
  2004-03-08 10:26     ` Andrew Morton
@ 2004-03-08 10:49       ` Amit S. Kale
  2004-03-08 11:07         ` Andrew Morton
                           ` (2 more replies)
  0 siblings, 3 replies; 27+ messages in thread
From: Amit S. Kale @ 2004-03-08 10:49 UTC (permalink / raw)
  To: Andrew Morton; +Cc: linux-kernel, trini, george, pavel

On Monday 08 Mar 2004 3:56 pm, Andrew Morton wrote:
> "Amit S. Kale" <amitkale@emsyssoft.com> wrote:
> > Here are features that are present only in full kgdb:
> >  1. Thread support  (aka info threads)
>
> argh, disaster.  I discussed this with Tom a week or so ago when it looked
> like this it was being chopped out and I recall being told that the
> discussion was referring to something else.
>
> Ho-hum, sorry.  Can we please put this back in?

Err., well this is one of the particularly dirty parts of kgdb. That's why 
it's been kept away. It takes care of correct thread backtraces in some rare 
cases.

If you consider it an absolutely must, we can do something so that the dirty 
part is kept away and info threads almost always works.

>
> >  2. console messages through gdb
>
> hm, it was occasionally handy.  Is there a lot of code involved?

Nope. Code is already in, it's just a matter of adding a config option.

>
> >  3. Automatic loading of modules in gdb
>
> OK.  I think.  What does this feature actually do?

This feature lets gdb hook onto a kernel function to detect loading and 
unloading of modules and preserves module section information for later use 
by gdb. At present this is broken for 2.6 kernels. I am working on this.

>
> >  4. Support for x86_64
> >  5. Support for powerpc
>
> These are planned, I assume?

Yes. As soon as i386 goes in. x86_64 is already very clean. There was another 
opinion about whether x86_64 should be the first one to go in!

ppc might need some work.

> >  6. kgdb over ethernet [This isn't ready in the full version as well at
> > this point of time]
>
> OK.  But the version in -mm and -mpm works OK, does it not?  Is there some
> difference in implementation which causes it to be broken in your tree?

There are some differences. The one in my tree also apparently works to some 
extent. It's being worked on.

-Amit


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: kgdb for mainline kernel: core-lite [patch 1/3]
  2004-03-08 10:49       ` Amit S. Kale
@ 2004-03-08 11:07         ` Andrew Morton
  2004-03-08 11:20           ` Amit S. Kale
  2004-03-08 22:15         ` George Anzinger
  2004-03-09  9:29         ` Amit S. Kale
  2 siblings, 1 reply; 27+ messages in thread
From: Andrew Morton @ 2004-03-08 11:07 UTC (permalink / raw)
  To: Amit S. Kale; +Cc: linux-kernel, trini, george, pavel

"Amit S. Kale" <amitkale@emsyssoft.com> wrote:
>
> On Monday 08 Mar 2004 3:56 pm, Andrew Morton wrote:
>  > "Amit S. Kale" <amitkale@emsyssoft.com> wrote:
>  > > Here are features that are present only in full kgdb:
>  > >  1. Thread support  (aka info threads)
>  >
>  > argh, disaster.  I discussed this with Tom a week or so ago when it looked
>  > like this it was being chopped out and I recall being told that the
>  > discussion was referring to something else.
>  >
>  > Ho-hum, sorry.  Can we please put this back in?
> 
>  Err., well this is one of the particularly dirty parts of kgdb. That's why 
>  it's been kept away. It takes care of correct thread backtraces in some rare 
>  cases.

Let me just make sure we're taking about the same thing here.  Are you
saying that with kgdb-lite, `info threads' is completely missing, or does
it just not work correctly with threads (as opposed to heavyweight
processes)?

>  If you consider it an absolutely must, we can do something so that the dirty 
>  part is kept away and info threads almost always works.

Yes, I'd consider `info threads' support a must-have.  I'm rather surprised
that others do not?


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: kgdb for mainline kernel: core-lite [patch 1/3]
  2004-03-08 11:07         ` Andrew Morton
@ 2004-03-08 11:20           ` Amit S. Kale
  2004-03-08 11:44             ` Amit S. Kale
                               ` (2 more replies)
  0 siblings, 3 replies; 27+ messages in thread
From: Amit S. Kale @ 2004-03-08 11:20 UTC (permalink / raw)
  To: Andrew Morton; +Cc: linux-kernel, trini, george, pavel

On Monday 08 Mar 2004 4:37 pm, Andrew Morton wrote:
> "Amit S. Kale" <amitkale@emsyssoft.com> wrote:
> > On Monday 08 Mar 2004 3:56 pm, Andrew Morton wrote:
> >  > "Amit S. Kale" <amitkale@emsyssoft.com> wrote:
> >  > > Here are features that are present only in full kgdb:
> >  > >  1. Thread support  (aka info threads)
> >  >
> >  > argh, disaster.  I discussed this with Tom a week or so ago when it
> >  > looked like this it was being chopped out and I recall being told that
> >  > the discussion was referring to something else.
> >  >
> >  > Ho-hum, sorry.  Can we please put this back in?
> >
> >  Err., well this is one of the particularly dirty parts of kgdb. That's
> > why it's been kept away. It takes care of correct thread backtraces in
> > some rare cases.
>
> Let me just make sure we're taking about the same thing here.  Are you
> saying that with kgdb-lite, `info threads' is completely missing, or does
> it just not work correctly with threads (as opposed to heavyweight
> processes)?

info threads shows a list of threads. Heavy/light weight processes doesn't 
matter. Thread frame shown is incorrect.

I looked at i386 dependent code again. Following code in it is incorrect. I 
never noticed it because this code is rarely used in full version of kgdb:

+void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct 
*p)
....
+	gdb_regs[_EBP] = *(int *)p->thread.esp;

We can't guss ebp this way. This line should be removed.

+	gdb_regs[_DS] = __KERNEL_DS;
+	gdb_regs[_ES] = __KERNEL_DS;
+	gdb_regs[_PS] = 0;
+	gdb_regs[_CS] = __KERNEL_CS;
+	gdb_regs[_PC] = p->thread.eip;
+	gdb_regs[_ESP] = p->thread.esp;

This should be gdb_regs[_ESP] = &p->thread.esp 

>
> >  If you consider it an absolutely must, we can do something so that the
> > dirty part is kept away and info threads almost always works.
>
> Yes, I'd consider `info threads' support a must-have.  I'm rather surprised
> that others do not?

Present threads support code changes calling convention of do_IRQ. Most 
believe that to be an absolute no.

Since you consider it a must-have, I'll check whether above changes suggested 
by me make info threads listing correct in most cases.

-Amit


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: kgdb for mainline kernel: core-lite [patch 1/3]
  2004-03-08 11:20           ` Amit S. Kale
@ 2004-03-08 11:44             ` Amit S. Kale
  2004-03-08 11:54               ` Andrew Morton
                                 ` (2 more replies)
  2004-03-08 11:48             ` Andrew Morton
  2004-03-08 15:22             ` Tom Rini
  2 siblings, 3 replies; 27+ messages in thread
From: Amit S. Kale @ 2004-03-08 11:44 UTC (permalink / raw)
  To: Andrew Morton; +Cc: linux-kernel, trini, george, pavel

On Monday 08 Mar 2004 4:50 pm, Amit S. Kale wrote:
> On Monday 08 Mar 2004 4:37 pm, Andrew Morton wrote:
> > "Amit S. Kale" <amitkale@emsyssoft.com> wrote:
> > > On Monday 08 Mar 2004 3:56 pm, Andrew Morton wrote:
> > >  > "Amit S. Kale" <amitkale@emsyssoft.com> wrote:
> > >  > > Here are features that are present only in full kgdb:
> > >  > >  1. Thread support  (aka info threads)
> > >  >
> > >  > argh, disaster.  I discussed this with Tom a week or so ago when it
> > >  > looked like this it was being chopped out and I recall being told
> > >  > that the discussion was referring to something else.
> > >  >
> > >  > Ho-hum, sorry.  Can we please put this back in?
> > >
> > >  Err., well this is one of the particularly dirty parts of kgdb. That's
> > > why it's been kept away. It takes care of correct thread backtraces in
> > > some rare cases.
> >
> > Let me just make sure we're taking about the same thing here.  Are you
> > saying that with kgdb-lite, `info threads' is completely missing, or does
> > it just not work correctly with threads (as opposed to heavyweight
> > processes)?
>
> info threads shows a list of threads. Heavy/light weight processes doesn't
> matter. Thread frame shown is incorrect.
>
> I looked at i386 dependent code again. Following code in it is incorrect. I
> never noticed it because this code is rarely used in full version of kgdb:
>
> +void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct
> task_struct *p)
> ....
> +	gdb_regs[_EBP] = *(int *)p->thread.esp;
>
> We can't guss ebp this way. This line should be removed.
>
> +	gdb_regs[_DS] = __KERNEL_DS;
> +	gdb_regs[_ES] = __KERNEL_DS;
> +	gdb_regs[_PS] = 0;
> +	gdb_regs[_CS] = __KERNEL_CS;
> +	gdb_regs[_PC] = p->thread.eip;
> +	gdb_regs[_ESP] = p->thread.esp;
>
> This should be gdb_regs[_ESP] = &p->thread.esp

That's not correct it. It should be gdb_regs[_ESP] = p->thread.esp;
Even with these changes I can't get thread listing correctly.

Here is the intrusive piece of code that helps get thread state correctly. Any 
ideas on cleaning it?

--- linux-2.6.3-kgdb.orig/include/linux/sched.h	2004-02-24 10:44:47.000000000 
+0530
+++ linux-2.6.3-kgdb/include/linux/sched.h	2004-03-04 18:42:56.324188184 +0530
@@ -173,7 +173,9 @@
 
 #define	MAX_SCHEDULE_TIMEOUT	LONG_MAX
 extern signed long FASTCALL(schedule_timeout(signed long timeout));
-asmlinkage void schedule(void);
+asmlinkage void do_schedule(void);
+asmlinkage void kern_schedule(void);
+asmlinkage void kern_do_schedule(struct pt_regs);
 
 struct namespace;
 
@@ -907,6 +909,15 @@
 
 #endif /* CONFIG_SMP */
 
+static inline void schedule(void)
+{
+#ifdef CONFIG_KGDB_THREAD
+	kern_schedule();
+#else
+	do_schedule();
+#endif
+}
+
--- linux-2.6.3-kgdb.orig/kernel/sched.c	2004-03-04 13:38:03.000000000 +0530
+++ linux-2.6.3-kgdb/kernel/sched.c	2004-03-04 18:42:56.327187728 +0530
@@ -1592,7 +1592,7 @@

 /*
  * schedule() is the main scheduler function.
  */
-asmlinkage void schedule(void)
+asmlinkage void do_schedule(void)
 {
 	long *switch_count;
 	task_t *prev, *next;
@@ -1764,6 +1764,23 @@
 
 EXPORT_SYMBOL(default_wake_function);
 
+asmlinkage void user_schedule(void)
+{
+#ifdef CONFIG_KGDB_THREAD
+	current->thread.debuggerinfo = NULL;
+#endif
+	do_schedule();
+}
+
+#ifdef CONFIG_KGDB_THREAD
+asmlinkage void kern_do_schedule(struct pt_regs regs)
+{
+	current->thread.debuggerinfo = &regs;
+	do_schedule();
+	current->thread.debuggerinfo = NULL;
+}
+#endif
+


-Amit

>
> > >  If you consider it an absolutely must, we can do something so that the
> > > dirty part is kept away and info threads almost always works.
> >
> > Yes, I'd consider `info threads' support a must-have.  I'm rather
> > surprised that others do not?
>
> Present threads support code changes calling convention of do_IRQ. Most
> believe that to be an absolute no.
>
> Since you consider it a must-have, I'll check whether above changes
> suggested by me make info threads listing correct in most cases.
>
> -Amit


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: kgdb for mainline kernel: core-lite [patch 1/3]
  2004-03-08 11:20           ` Amit S. Kale
  2004-03-08 11:44             ` Amit S. Kale
@ 2004-03-08 11:48             ` Andrew Morton
  2004-03-08 22:21               ` George Anzinger
  2004-03-08 15:22             ` Tom Rini
  2 siblings, 1 reply; 27+ messages in thread
From: Andrew Morton @ 2004-03-08 11:48 UTC (permalink / raw)
  To: Amit S. Kale; +Cc: linux-kernel, trini, george, pavel

"Amit S. Kale" <amitkale@emsyssoft.com> wrote:
>
> > Let me just make sure we're taking about the same thing here.  Are you
> > saying that with kgdb-lite, `info threads' is completely missing, or does
> > it just not work correctly with threads (as opposed to heavyweight
> > processes)?
> 
> info threads shows a list of threads. Heavy/light weight processes doesn't 
> matter. Thread frame shown is incorrect.

It is?  I haven't noticed any problems with it here.  George recently
changed it to also display the process name in the gdb output, which is
valuable.

> I looked at i386 dependent code again. Following code in it is incorrect. I 
> never noticed it because this code is rarely used in full version of kgdb:
> 
> +void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct 
> *p)

There is no such function in the stub in -mm kernels.

> 
> Present threads support code changes calling convention of do_IRQ. Most 
> believe that to be an absolute no.

I see no such change in George's stub, unless I'm missing something again.

> Since you consider it a must-have, I'll check whether above changes suggested 
> by me make info threads listing correct in most cases.

The only problem I have with it is that sometimes after listing all threads
the debugger can lose control of the target and will start complaining
about communication errors.  I assume the target has died.  This happens
very rarely.  Usually when you're about to find the bug ;)

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: kgdb for mainline kernel: core-lite [patch 1/3]
  2004-03-08 11:44             ` Amit S. Kale
@ 2004-03-08 11:54               ` Andrew Morton
  2004-03-08 12:00                 ` Amit S. Kale
  2004-03-08 15:19               ` Tom Rini
  2004-03-08 22:19               ` George Anzinger
  2 siblings, 1 reply; 27+ messages in thread
From: Andrew Morton @ 2004-03-08 11:54 UTC (permalink / raw)
  To: Amit S. Kale; +Cc: linux-kernel, trini, george, pavel

"Amit S. Kale" <amitkale@emsyssoft.com> wrote:
>
> Here is the intrusive piece of code that helps get thread state correctly. Any 
>  ideas on cleaning it?

I think George's stub has diverged rather a lot from yours.  Much more than
I was aware.


>  --- linux-2.6.3-kgdb.orig/include/linux/sched.h	2004-02-24 10:44:47.000000000 
>  +0530
>  +++ linux-2.6.3-kgdb/include/linux/sched.h	2004-03-04 18:42:56.324188184 +0530
>  @@ -173,7 +173,9 @@
>   
>   #define	MAX_SCHEDULE_TIMEOUT	LONG_MAX
>   extern signed long FASTCALL(schedule_timeout(signed long timeout));
>  -asmlinkage void schedule(void);
>  +asmlinkage void do_schedule(void);
>  +asmlinkage void kern_schedule(void);
>  +asmlinkage void kern_do_schedule(struct pt_regs);

The stub in -mm has only a single change to sched.c:

diff -puN kernel/sched.c~kgdb-ga kernel/sched.c
--- 25/kernel/sched.c~kgdb-ga	2004-03-07 01:57:48.000000000 -0800
+++ 25-akpm/kernel/sched.c	2004-03-07 01:57:48.000000000 -0800
@@ -2015,6 +2015,13 @@ out_unlock:
 
 EXPORT_SYMBOL(set_user_nice);
 
+#if defined( CONFIG_KGDB)
+struct task_struct * kgdb_get_idle(int this_cpu)
+{
+        return cpu_rq(this_cpu)->idle;
+}
+#endif
+
 #ifndef __alpha__
 
 /*


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: kgdb for mainline kernel: core-lite [patch 1/3]
  2004-03-08 11:54               ` Andrew Morton
@ 2004-03-08 12:00                 ` Amit S. Kale
  0 siblings, 0 replies; 27+ messages in thread
From: Amit S. Kale @ 2004-03-08 12:00 UTC (permalink / raw)
  To: Andrew Morton; +Cc: linux-kernel, trini, george, pavel

On Monday 08 Mar 2004 5:24 pm, Andrew Morton wrote:
> "Amit S. Kale" <amitkale@emsyssoft.com> wrote:
> > Here is the intrusive piece of code that helps get thread state
> > correctly. Any ideas on cleaning it?
>
> I think George's stub has diverged rather a lot from yours.  Much more than
> I was aware.

Yes. It has.
At this point of time no one knows precisely where all they differ and 
how/whether they could be merged.

The threads code in my version saves all registers during a context switch. 
This provides two benefits:
1. GDB doesn't lose track of registers when going up a stack trace starting 
with switch_to.
2. If a thread calls schedule, the thread backtrace starts from caller of 
schedule rather than schedule itself. So info threads command shows a more 
meaningful output.

-Amit

>
> >  --- linux-2.6.3-kgdb.orig/include/linux/sched.h	2004-02-24
> > 10:44:47.000000000 +0530
> >  +++ linux-2.6.3-kgdb/include/linux/sched.h	2004-03-04 18:42:56.324188184
> > +0530 @@ -173,7 +173,9 @@
> >
> >   #define	MAX_SCHEDULE_TIMEOUT	LONG_MAX
> >   extern signed long FASTCALL(schedule_timeout(signed long timeout));
> >  -asmlinkage void schedule(void);
> >  +asmlinkage void do_schedule(void);
> >  +asmlinkage void kern_schedule(void);
> >  +asmlinkage void kern_do_schedule(struct pt_regs);
>
> The stub in -mm has only a single change to sched.c:
>
> diff -puN kernel/sched.c~kgdb-ga kernel/sched.c
> --- 25/kernel/sched.c~kgdb-ga	2004-03-07 01:57:48.000000000 -0800
> +++ 25-akpm/kernel/sched.c	2004-03-07 01:57:48.000000000 -0800
> @@ -2015,6 +2015,13 @@ out_unlock:
>
>  EXPORT_SYMBOL(set_user_nice);
>
> +#if defined( CONFIG_KGDB)
> +struct task_struct * kgdb_get_idle(int this_cpu)
> +{
> +        return cpu_rq(this_cpu)->idle;
> +}
> +#endif
> +
>  #ifndef __alpha__
>
>  /*


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: kgdb for mainline kernel: core-lite [patch 1/3]
  2004-03-08 11:44             ` Amit S. Kale
  2004-03-08 11:54               ` Andrew Morton
@ 2004-03-08 15:19               ` Tom Rini
  2004-03-08 22:26                 ` George Anzinger
  2004-03-09  8:58                 ` Amit S. Kale
  2004-03-08 22:19               ` George Anzinger
  2 siblings, 2 replies; 27+ messages in thread
From: Tom Rini @ 2004-03-08 15:19 UTC (permalink / raw)
  To: Amit S. Kale; +Cc: Andrew Morton, linux-kernel, george, pavel

On Mon, Mar 08, 2004 at 05:14:05PM +0530, Amit S. Kale wrote:
> On Monday 08 Mar 2004 4:50 pm, Amit S. Kale wrote:
> > On Monday 08 Mar 2004 4:37 pm, Andrew Morton wrote:
> > > "Amit S. Kale" <amitkale@emsyssoft.com> wrote:
> > > > On Monday 08 Mar 2004 3:56 pm, Andrew Morton wrote:
> > > >  > "Amit S. Kale" <amitkale@emsyssoft.com> wrote:
> > > >  > > Here are features that are present only in full kgdb:
> > > >  > >  1. Thread support  (aka info threads)
> > > >  >
> > > >  > argh, disaster.  I discussed this with Tom a week or so ago when it
> > > >  > looked like this it was being chopped out and I recall being told
> > > >  > that the discussion was referring to something else.
> > > >  >
> > > >  > Ho-hum, sorry.  Can we please put this back in?
> > > >
> > > >  Err., well this is one of the particularly dirty parts of kgdb. That's
> > > > why it's been kept away. It takes care of correct thread backtraces in
> > > > some rare cases.
> > >
> > > Let me just make sure we're taking about the same thing here.  Are you
> > > saying that with kgdb-lite, `info threads' is completely missing, or does
> > > it just not work correctly with threads (as opposed to heavyweight
> > > processes)?
> >
> > info threads shows a list of threads. Heavy/light weight processes doesn't
> > matter. Thread frame shown is incorrect.
> >
> > I looked at i386 dependent code again. Following code in it is incorrect. I
> > never noticed it because this code is rarely used in full version of kgdb:
> >
> > +void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct
> > task_struct *p)
> > ....
> > +	gdb_regs[_EBP] = *(int *)p->thread.esp;
> >
> > We can't guss ebp this way. This line should be removed.
> >
> > +	gdb_regs[_DS] = __KERNEL_DS;
> > +	gdb_regs[_ES] = __KERNEL_DS;
> > +	gdb_regs[_PS] = 0;
> > +	gdb_regs[_CS] = __KERNEL_CS;
> > +	gdb_regs[_PC] = p->thread.eip;
> > +	gdb_regs[_ESP] = p->thread.esp;
> >
> > This should be gdb_regs[_ESP] = &p->thread.esp
> 
> That's not correct it. It should be gdb_regs[_ESP] = p->thread.esp;
> Even with these changes I can't get thread listing correctly.
> 
> Here is the intrusive piece of code that helps get thread state correctly. Any 
> ideas on cleaning it?

Here's where what Andi said about being able to get the pt_regs stuff
off the stack (I think that's what he said at least) started to confuse
me slightly.  But if I understand it right (and I never got around to
testing this) we can replace the do_schedule() stuffs at least with
something like kgdb_get_pt_regs(), since (and I lost my notes on this,
so it's probably not quite right) (thread_info->esp0)-1

-- 
Tom Rini
http://gate.crashing.org/~trini/

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: kgdb for mainline kernel: core-lite [patch 1/3]
  2004-03-08 11:20           ` Amit S. Kale
  2004-03-08 11:44             ` Amit S. Kale
  2004-03-08 11:48             ` Andrew Morton
@ 2004-03-08 15:22             ` Tom Rini
  2004-03-08 16:32               ` Amit S. Kale
  2004-03-08 22:29               ` George Anzinger
  2 siblings, 2 replies; 27+ messages in thread
From: Tom Rini @ 2004-03-08 15:22 UTC (permalink / raw)
  To: Amit S. Kale; +Cc: Andrew Morton, linux-kernel, george, pavel

On Mon, Mar 08, 2004 at 04:50:18PM +0530, Amit S. Kale wrote:
> On Monday 08 Mar 2004 4:37 pm, Andrew Morton wrote:
> > "Amit S. Kale" <amitkale@emsyssoft.com> wrote:
[snip]
> > >  If you consider it an absolutely must, we can do something so that the
> > > dirty part is kept away and info threads almost always works.
> >
> > Yes, I'd consider `info threads' support a must-have.  I'm rather surprised
> > that others do not?
> 
> Present threads support code changes calling convention of do_IRQ. Most 
> believe that to be an absolute no.

I believe that George's version does something totally different, with
some macros at compile time (and binutils support, I _think_) to not
have to change do_IRQ.

-- 
Tom Rini
http://gate.crashing.org/~trini/

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: kgdb for mainline kernel: core-lite [patch 1/3]
  2004-03-08 15:22             ` Tom Rini
@ 2004-03-08 16:32               ` Amit S. Kale
  2004-03-08 22:29               ` George Anzinger
  1 sibling, 0 replies; 27+ messages in thread
From: Amit S. Kale @ 2004-03-08 16:32 UTC (permalink / raw)
  To: Tom Rini; +Cc: Andrew Morton, linux-kernel, george, pavel

On Monday 08 Mar 2004 8:52 pm, Tom Rini wrote:
> On Mon, Mar 08, 2004 at 04:50:18PM +0530, Amit S. Kale wrote:
> > On Monday 08 Mar 2004 4:37 pm, Andrew Morton wrote:
> > > "Amit S. Kale" <amitkale@emsyssoft.com> wrote:
>
> [snip]
>
> > > >  If you consider it an absolutely must, we can do something so that
> > > > the dirty part is kept away and info threads almost always works.
> > >
> > > Yes, I'd consider `info threads' support a must-have.  I'm rather
> > > surprised that others do not?
> >
> > Present threads support code changes calling convention of do_IRQ. Most
> > believe that to be an absolute no.
>
> I believe that George's version does something totally different, with
> some macros at compile time (and binutils support, I _think_) to not
> have to change do_IRQ.

OOPS! Present code doesn't change calling convention of do_IRQ. I changed that 
some time ago.

-Amit


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: kgdb for mainline kernel: core-lite [patch 1/3]
  2004-03-08 10:49       ` Amit S. Kale
  2004-03-08 11:07         ` Andrew Morton
@ 2004-03-08 22:15         ` George Anzinger
  2004-03-09  4:46           ` Amit S. Kale
  2004-03-09  9:29         ` Amit S. Kale
  2 siblings, 1 reply; 27+ messages in thread
From: George Anzinger @ 2004-03-08 22:15 UTC (permalink / raw)
  To: Amit S. Kale; +Cc: Andrew Morton, linux-kernel, trini, pavel

Amit S. Kale wrote:
> On Monday 08 Mar 2004 3:56 pm, Andrew Morton wrote:
> 
>>"Amit S. Kale" <amitkale@emsyssoft.com> wrote:
>>
>>>Here are features that are present only in full kgdb:
>>> 1. Thread support  (aka info threads)
>>
>>argh, disaster.  I discussed this with Tom a week or so ago when it looked
>>like this it was being chopped out and I recall being told that the
>>discussion was referring to something else.
>>
>>Ho-hum, sorry.  Can we please put this back in?
> 
> 
> Err., well this is one of the particularly dirty parts of kgdb. That's why 
> it's been kept away. It takes care of correct thread backtraces in some rare 
> cases.
> 
> If you consider it an absolutely must, we can do something so that the dirty 
> part is kept away and info threads almost always works.
> 

Amit,

I think we should just put the info threads in the core.  No attempt to do any 
trace back from kgdb.  Let them all show up in the switch code.  I have a script 
(gdb macro) that will give a rather decent "info threads" display.  Oh, we need 
to add one other responce to kgdb for the process info gdb command.

  * This query allows the target stub to return an arbitrary string
  * (or strings) giving arbitrary information about the target process.
  * This is optional; the target stub isn't required to implement it.
  *
  * Syntax: qfProcessInfo        request first string
  *         qsProcessInfo        request subsequent string
  * reply:  'O'<hex-encoded-string>
  *         'l'                  last reply (empty)
  */
What we want here is the thread name.

Here is the macro set:

set var $low_sched=0

define do_threads
   if (void)$low_sched==(void)0
	set_b
   end
   thread apply all do_th_lines
end

define do_th_lines
   set var $do_th_co=0
   while ($pc > $low_sched) && ($pc < $high_sched)
     up-silent
     set var $do_th_co=$do_th_co+1
   end
   if $do_th_co==0
     info remote-process
     bt
   else
     up-silent
     info remote-process
     down
   end
end

define set_b
   set var $low_sched=scheduling_functions_start_here
   set var $high_sched=scheduling_functions_end_here
end


~

-- 
George Anzinger   george@mvista.com
High-res-timers:  http://sourceforge.net/projects/high-res-timers/
Preemption patch: http://www.kernel.org/pub/linux/kernel/people/rml


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: kgdb for mainline kernel: core-lite [patch 1/3]
  2004-03-08 11:44             ` Amit S. Kale
  2004-03-08 11:54               ` Andrew Morton
  2004-03-08 15:19               ` Tom Rini
@ 2004-03-08 22:19               ` George Anzinger
  2004-03-09  5:08                 ` Amit S. Kale
  2 siblings, 1 reply; 27+ messages in thread
From: George Anzinger @ 2004-03-08 22:19 UTC (permalink / raw)
  To: Amit S. Kale; +Cc: Andrew Morton, linux-kernel, trini, pavel

Amit S. Kale wrote:
> On Monday 08 Mar 2004 4:50 pm, Amit S. Kale wrote:
> 
>>On Monday 08 Mar 2004 4:37 pm, Andrew Morton wrote:
>>
>>>"Amit S. Kale" <amitkale@emsyssoft.com> wrote:
>>>
>>>>On Monday 08 Mar 2004 3:56 pm, Andrew Morton wrote:
>>>> > "Amit S. Kale" <amitkale@emsyssoft.com> wrote:
>>>> > > Here are features that are present only in full kgdb:
>>>> > >  1. Thread support  (aka info threads)
>>>> >
>>>> > argh, disaster.  I discussed this with Tom a week or so ago when it
>>>> > looked like this it was being chopped out and I recall being told
>>>> > that the discussion was referring to something else.
>>>> >
>>>> > Ho-hum, sorry.  Can we please put this back in?
>>>>
>>>> Err., well this is one of the particularly dirty parts of kgdb. That's
>>>>why it's been kept away. It takes care of correct thread backtraces in
>>>>some rare cases.
>>>
>>>Let me just make sure we're taking about the same thing here.  Are you
>>>saying that with kgdb-lite, `info threads' is completely missing, or does
>>>it just not work correctly with threads (as opposed to heavyweight
>>>processes)?
>>
>>info threads shows a list of threads. Heavy/light weight processes doesn't
>>matter. Thread frame shown is incorrect.
>>
>>I looked at i386 dependent code again. Following code in it is incorrect. I
>>never noticed it because this code is rarely used in full version of kgdb:
>>
>>+void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct
>>task_struct *p)
>>....
>>+	gdb_regs[_EBP] = *(int *)p->thread.esp;
>>
>>We can't guss ebp this way. This line should be removed.
>>
>>+	gdb_regs[_DS] = __KERNEL_DS;
>>+	gdb_regs[_ES] = __KERNEL_DS;
>>+	gdb_regs[_PS] = 0;
>>+	gdb_regs[_CS] = __KERNEL_CS;
>>+	gdb_regs[_PC] = p->thread.eip;
>>+	gdb_regs[_ESP] = p->thread.esp;
>>
>>This should be gdb_regs[_ESP] = &p->thread.esp
> 
> 
> That's not correct it. It should be gdb_regs[_ESP] = p->thread.esp;
> Even with these changes I can't get thread listing correctly.
> 
> Here is the intrusive piece of code that helps get thread state correctly. Any 
> ideas on cleaning it?

I wonder what version of gdb you are using.  What is it that you see?

You really do need a gdb that handles the dwarft2 frames.  This is a rather new 
gdb (I use the CVS version).

-g
~

-- 
George Anzinger   george@mvista.com
High-res-timers:  http://sourceforge.net/projects/high-res-timers/
Preemption patch: http://www.kernel.org/pub/linux/kernel/people/rml


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: kgdb for mainline kernel: core-lite [patch 1/3]
  2004-03-08 11:48             ` Andrew Morton
@ 2004-03-08 22:21               ` George Anzinger
  0 siblings, 0 replies; 27+ messages in thread
From: George Anzinger @ 2004-03-08 22:21 UTC (permalink / raw)
  To: Andrew Morton; +Cc: Amit S. Kale, linux-kernel, trini, pavel

Andrew Morton wrote:
> "Amit S. Kale" <amitkale@emsyssoft.com> wrote:
> 
>>>Let me just make sure we're taking about the same thing here.  Are you
>>>saying that with kgdb-lite, `info threads' is completely missing, or does
>>>it just not work correctly with threads (as opposed to heavyweight
>>>processes)?
>>
>>info threads shows a list of threads. Heavy/light weight processes doesn't 
>>matter. Thread frame shown is incorrect.
> 
> 
> It is?  I haven't noticed any problems with it here.  George recently
> changed it to also display the process name in the gdb output, which is
> valuable.
> 
> 
>>I looked at i386 dependent code again. Following code in it is incorrect. I 
>>never noticed it because this code is rarely used in full version of kgdb:
>>
>>+void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct 
>>*p)
> 
> 
> There is no such function in the stub in -mm kernels.
> 
> 
>>Present threads support code changes calling convention of do_IRQ. Most 
>>believe that to be an absolute no.
> 
> 
> I see no such change in George's stub, unless I'm missing something again.

Amit and I went after the problem in rather different ways...
> 
> 
>>Since you consider it a must-have, I'll check whether above changes suggested 
>>by me make info threads listing correct in most cases.
> 
> 
> The only problem I have with it is that sometimes after listing all threads
> the debugger can lose control of the target and will start complaining
> about communication errors.  I assume the target has died.  This happens
> very rarely.  Usually when you're about to find the bug ;)

Yeah, you won't believe how much work it took to detect that ;)

-- 
George Anzinger   george@mvista.com
High-res-timers:  http://sourceforge.net/projects/high-res-timers/
Preemption patch: http://www.kernel.org/pub/linux/kernel/people/rml


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: kgdb for mainline kernel: core-lite [patch 1/3]
  2004-03-08 15:19               ` Tom Rini
@ 2004-03-08 22:26                 ` George Anzinger
  2004-03-09  8:58                 ` Amit S. Kale
  1 sibling, 0 replies; 27+ messages in thread
From: George Anzinger @ 2004-03-08 22:26 UTC (permalink / raw)
  To: Tom Rini; +Cc: Amit S. Kale, Andrew Morton, linux-kernel, pavel

Tom Rini wrote:
> On Mon, Mar 08, 2004 at 05:14:05PM +0530, Amit S. Kale wrote:
> 
>>On Monday 08 Mar 2004 4:50 pm, Amit S. Kale wrote:
>>
>>>On Monday 08 Mar 2004 4:37 pm, Andrew Morton wrote:
>>>
>>>>"Amit S. Kale" <amitkale@emsyssoft.com> wrote:
>>>>
>>>>>On Monday 08 Mar 2004 3:56 pm, Andrew Morton wrote:
>>>>> > "Amit S. Kale" <amitkale@emsyssoft.com> wrote:
>>>>> > > Here are features that are present only in full kgdb:
>>>>> > >  1. Thread support  (aka info threads)
>>>>> >
>>>>> > argh, disaster.  I discussed this with Tom a week or so ago when it
>>>>> > looked like this it was being chopped out and I recall being told
>>>>> > that the discussion was referring to something else.
>>>>> >
>>>>> > Ho-hum, sorry.  Can we please put this back in?
>>>>>
>>>>> Err., well this is one of the particularly dirty parts of kgdb. That's
>>>>>why it's been kept away. It takes care of correct thread backtraces in
>>>>>some rare cases.
>>>>
>>>>Let me just make sure we're taking about the same thing here.  Are you
>>>>saying that with kgdb-lite, `info threads' is completely missing, or does
>>>>it just not work correctly with threads (as opposed to heavyweight
>>>>processes)?
>>>
>>>info threads shows a list of threads. Heavy/light weight processes doesn't
>>>matter. Thread frame shown is incorrect.
>>>
>>>I looked at i386 dependent code again. Following code in it is incorrect. I
>>>never noticed it because this code is rarely used in full version of kgdb:
>>>
>>>+void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct
>>>task_struct *p)
>>>....
>>>+	gdb_regs[_EBP] = *(int *)p->thread.esp;
>>>
>>>We can't guss ebp this way. This line should be removed.
>>>
>>>+	gdb_regs[_DS] = __KERNEL_DS;
>>>+	gdb_regs[_ES] = __KERNEL_DS;
>>>+	gdb_regs[_PS] = 0;
>>>+	gdb_regs[_CS] = __KERNEL_CS;
>>>+	gdb_regs[_PC] = p->thread.eip;
>>>+	gdb_regs[_ESP] = p->thread.esp;
>>>
>>>This should be gdb_regs[_ESP] = &p->thread.esp
>>
>>That's not correct it. It should be gdb_regs[_ESP] = p->thread.esp;
>>Even with these changes I can't get thread listing correctly.
>>
>>Here is the intrusive piece of code that helps get thread state correctly. Any 
>>ideas on cleaning it?
> 
> 
> Here's where what Andi said about being able to get the pt_regs stuff
> off the stack (I think that's what he said at least) started to confuse
> me slightly.  But if I understand it right (and I never got around to
> testing this) we can replace the do_schedule() stuffs at least with
> something like kgdb_get_pt_regs(), since (and I lost my notes on this,
> so it's probably not quite right) (thread_info->esp0)-1

I don't see any problem here.  All I do is to detect that the thread is not 
current on ANY cpu and send up the regs that switch to saved in the task struct. 
  GDB can then figure out the rest from the dwarft2 frames.  At this time it 
helps to have the compile option to do frames turned on.  This is so that gdb 
will use the frame register to back out of switch to.  It all works well in my kgdb.
> 

-- 
George Anzinger   george@mvista.com
High-res-timers:  http://sourceforge.net/projects/high-res-timers/
Preemption patch: http://www.kernel.org/pub/linux/kernel/people/rml


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: kgdb for mainline kernel: core-lite [patch 1/3]
  2004-03-08 15:22             ` Tom Rini
  2004-03-08 16:32               ` Amit S. Kale
@ 2004-03-08 22:29               ` George Anzinger
  1 sibling, 0 replies; 27+ messages in thread
From: George Anzinger @ 2004-03-08 22:29 UTC (permalink / raw)
  To: Tom Rini; +Cc: Amit S. Kale, Andrew Morton, linux-kernel, pavel

Tom Rini wrote:
> On Mon, Mar 08, 2004 at 04:50:18PM +0530, Amit S. Kale wrote:
> 
>>On Monday 08 Mar 2004 4:37 pm, Andrew Morton wrote:
>>
>>>"Amit S. Kale" <amitkale@emsyssoft.com> wrote:
> 
> [snip]
> 
>>>> If you consider it an absolutely must, we can do something so that the
>>>>dirty part is kept away and info threads almost always works.
>>>
>>>Yes, I'd consider `info threads' support a must-have.  I'm rather surprised
>>>that others do not?
>>
>>Present threads support code changes calling convention of do_IRQ. Most 
>>believe that to be an absolute no.
> 
> 
> I believe that George's version does something totally different, with
> some macros at compile time (and binutils support, I _think_) to not
> have to change do_IRQ.

No, nothing at compile time, at least WRT the threads issue.  There is a 
completely different problem with backtracing through an interrupt or trap.  I 
have sent the patch for that which makes only minimal changes to code (one line 
I think, and that an asm line).  The rest is a dwarft2 set of code to build the 
frame description for the trap/interrupt frame.

> 

-- 
George Anzinger   george@mvista.com
High-res-timers:  http://sourceforge.net/projects/high-res-timers/
Preemption patch: http://www.kernel.org/pub/linux/kernel/people/rml


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: kgdb for mainline kernel: core-lite [patch 1/3]
  2004-03-08 22:15         ` George Anzinger
@ 2004-03-09  4:46           ` Amit S. Kale
  0 siblings, 0 replies; 27+ messages in thread
From: Amit S. Kale @ 2004-03-09  4:46 UTC (permalink / raw)
  To: George Anzinger; +Cc: Andrew Morton, linux-kernel, trini, pavel

On Tuesday 09 Mar 2004 3:45 am, George Anzinger wrote:
> Amit S. Kale wrote:
> > On Monday 08 Mar 2004 3:56 pm, Andrew Morton wrote:
> >>"Amit S. Kale" <amitkale@emsyssoft.com> wrote:
> >>>Here are features that are present only in full kgdb:
> >>> 1. Thread support  (aka info threads)
> >>
> >>argh, disaster.  I discussed this with Tom a week or so ago when it
> >> looked like this it was being chopped out and I recall being told that
> >> the discussion was referring to something else.
> >>
> >>Ho-hum, sorry.  Can we please put this back in?
> >
> > Err., well this is one of the particularly dirty parts of kgdb. That's
> > why it's been kept away. It takes care of correct thread backtraces in
> > some rare cases.
> >
> > If you consider it an absolutely must, we can do something so that the
> > dirty part is kept away and info threads almost always works.
>
> Amit,
>
> I think we should just put the info threads in the core.  No attempt to do
> any trace back from kgdb.  Let them all show up in the switch code.  I have
> a script (gdb macro) that will give a rather decent "info threads" display.
>  Oh, we need to add one other responce to kgdb for the process info gdb
> command.

qfProcessInfo looks like a very useful command.

This is still a hack. These kinds of hacks are difficult to maintain over a 
long time because they are based on undocumented information.

While setting up kgdb for the first time isn't easy, macros add to that 
complexity.

Have you experienced "shakyness" of macros? I have used process information 
macros at kgdb.sourceforge.net to display a "ps" command like output since 
the days of 2.4.0. I had to change them 3-4 times till now because of kernel 
structure changes. The "changing" part is typically a 2-3 hour regorous 
exercise :-)

-Amit

>   * This query allows the target stub to return an arbitrary string
>   * (or strings) giving arbitrary information about the target process.
>   * This is optional; the target stub isn't required to implement it.
>   *
>   * Syntax: qfProcessInfo        request first string
>   *         qsProcessInfo        request subsequent string
>   * reply:  'O'<hex-encoded-string>
>   *         'l'                  last reply (empty)
>   */
> What we want here is the thread name.
>
> Here is the macro set:
>
> set var $low_sched=0
>
> define do_threads
>    if (void)$low_sched==(void)0
> 	set_b
>    end
>    thread apply all do_th_lines
> end
>
> define do_th_lines
>    set var $do_th_co=0
>    while ($pc > $low_sched) && ($pc < $high_sched)
>      up-silent
>      set var $do_th_co=$do_th_co+1
>    end
>    if $do_th_co==0
>      info remote-process
>      bt
>    else
>      up-silent
>      info remote-process
>      down
>    end
> end
>
> define set_b
>    set var $low_sched=scheduling_functions_start_here
>    set var $high_sched=scheduling_functions_end_here
> end
>
>
> ~


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: kgdb for mainline kernel: core-lite [patch 1/3]
  2004-03-08 22:19               ` George Anzinger
@ 2004-03-09  5:08                 ` Amit S. Kale
  2004-03-09 15:37                   ` Tom Rini
  0 siblings, 1 reply; 27+ messages in thread
From: Amit S. Kale @ 2004-03-09  5:08 UTC (permalink / raw)
  To: George Anzinger; +Cc: Andrew Morton, linux-kernel, trini, pavel

On Tuesday 09 Mar 2004 3:49 am, George Anzinger wrote:
> Amit S. Kale wrote:
> > On Monday 08 Mar 2004 4:50 pm, Amit S. Kale wrote:
> >>On Monday 08 Mar 2004 4:37 pm, Andrew Morton wrote:
> >>>"Amit S. Kale" <amitkale@emsyssoft.com> wrote:
> >>>>On Monday 08 Mar 2004 3:56 pm, Andrew Morton wrote:
> >>>> > "Amit S. Kale" <amitkale@emsyssoft.com> wrote:
> >>>> > > Here are features that are present only in full kgdb:
> >>>> > >  1. Thread support  (aka info threads)
> >>>> >
> >>>> > argh, disaster.  I discussed this with Tom a week or so ago when it
> >>>> > looked like this it was being chopped out and I recall being told
> >>>> > that the discussion was referring to something else.
> >>>> >
> >>>> > Ho-hum, sorry.  Can we please put this back in?
> >>>>
> >>>> Err., well this is one of the particularly dirty parts of kgdb. That's
> >>>>why it's been kept away. It takes care of correct thread backtraces in
> >>>>some rare cases.
> >>>
> >>>Let me just make sure we're taking about the same thing here.  Are you
> >>>saying that with kgdb-lite, `info threads' is completely missing, or
> >>> does it just not work correctly with threads (as opposed to heavyweight
> >>> processes)?
> >>
> >>info threads shows a list of threads. Heavy/light weight processes
> >> doesn't matter. Thread frame shown is incorrect.
> >>
> >>I looked at i386 dependent code again. Following code in it is incorrect.
> >> I never noticed it because this code is rarely used in full version of
> >> kgdb:
> >>
> >>+void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct
> >>task_struct *p)
> >>....
> >>+	gdb_regs[_EBP] = *(int *)p->thread.esp;
> >>
> >>We can't guss ebp this way. This line should be removed.
> >>
> >>+	gdb_regs[_DS] = __KERNEL_DS;
> >>+	gdb_regs[_ES] = __KERNEL_DS;
> >>+	gdb_regs[_PS] = 0;
> >>+	gdb_regs[_CS] = __KERNEL_CS;
> >>+	gdb_regs[_PC] = p->thread.eip;
> >>+	gdb_regs[_ESP] = p->thread.esp;
> >>
> >>This should be gdb_regs[_ESP] = &p->thread.esp
> >
> > That's not correct it. It should be gdb_regs[_ESP] = p->thread.esp;
> > Even with these changes I can't get thread listing correctly.
> >
> > Here is the intrusive piece of code that helps get thread state
> > correctly. Any ideas on cleaning it?
>
> I wonder what version of gdb you are using.  What is it that you see?

I am pasting below the output I see with 
gdb_regs[_PC] = p->thread.eip;
gdb_regs[_ESP] = p->thread.esp;
providing thread state information.

>
> You really do need a gdb that handles the dwarft2 frames.  This is a rather
> new gdb (I use the CVS version).

Let's just stick to gdb 6.0 and binutils 2.14. CVS versions of gdb and 
binutils are too risky for someone who is trying to learn linux kernel by 
using kgdb.

Let's face it, more people use kgdb to _learn_ some part of the kernel than 
kernel gurus :-)

-Amit

(gdb) info thr
  42 Thread 32768 (Shadow task 0 for pid 0)  0xc011a27f in schedule ()
    at /home/amitkale/work/linux-2.6.4-rc2-bk3-kgdb/kernel/sched.c:920
  41 Thread 1129 (cupsd)  0xc1146000 in ?? ()
  40 Thread 1128 (initlog)  0xc1146000 in ?? ()
  39 Thread 1123 (S90cups)  0xc1146000 in ?? ()
  38 Thread 1119 (crond)  0xc1146000 in ?? ()
  37 Thread 1110 (gpm)  0xc1146000 in ?? ()
  36 Thread 1100 (sendmail)  0xc1146000 in ?? ()
  35 Thread 1090 (sendmail)  0xc1146000 in ?? ()
  34 Thread 1068 (rpc.mountd)  0xc1146000 in ?? ()
  33 Thread 1062 (rpciod)  0xc1146000 in ?? ()
  32 Thread 1061 (lockd)  0xc1146000 in ?? ()
  31 Thread 1060 (nfsd)  0xc1146000 in ?? ()
  30 Thread 1059 (nfsd)  0xc1146000 in ?? ()
  29 Thread 1058 (nfsd)  0xc1146000 in ?? ()
  28 Thread 1057 (nfsd)  0xc1146000 in ?? ()
  27 Thread 1056 (nfsd)  0xc1146000 in ?? ()
  26 Thread 1055 (nfsd)  0xc1146000 in ?? ()
  25 Thread 1054 (nfsd)  0xc1146000 in ?? ()
  24 Thread 1053 (nfsd)  0xc1146000 in ?? ()
  23 Thread 1049 (rpc.rquotad)  0xc1146000 in ?? ()
  22 Thread 1036 (xinetd)  0xc1146000 in ?? ()
  21 Thread 1021 (sshd)  0xc1146000 in ?? ()
---Type <return> to continue, or q <return> to quit---
  20 Thread 925 (rpc.statd)  0xc1146000 in ?? ()
  19 Thread 906 (portmap)  0xc1146000 in ?? ()
  18 Thread 888 (klogd)  0xc1146000 in ?? ()
  17 Thread 884 (syslogd)  0xc1146000 in ?? ()
  16 Thread 706 (rc)  0xc1146000 in ?? ()
  15 Thread 626 (kjournald)  0xc1146000 in ?? ()
  14 Thread 625 (kjournald)  0xc1146000 in ?? ()
  13 Thread 624 (kjournald)  0xc1146000 in ?? ()
  12 Thread 11 (kjournald)  0xc1146000 in ?? ()
  11 Thread 10 (kseriod)  0xc011a27f in schedule ()
    at /home/amitkale/work/linux-2.6.4-rc2-bk3-kgdb/kernel/sched.c:920
  10 Thread 9 (aio/0)  0xc011a27f in schedule ()
    at /home/amitkale/work/linux-2.6.4-rc2-bk3-kgdb/kernel/sched.c:920
  9 Thread 8 (kswapd0)  0xc011a27f in schedule ()
    at /home/amitkale/work/linux-2.6.4-rc2-bk3-kgdb/kernel/sched.c:920
  8 Thread 7 (pdflush)  0xc011a27f in schedule ()
    at /home/amitkale/work/linux-2.6.4-rc2-bk3-kgdb/kernel/sched.c:920
  7 Thread 6 (pdflush)  0xc011a27f in schedule ()
    at /home/amitkale/work/linux-2.6.4-rc2-bk3-kgdb/kernel/sched.c:920
  6 Thread 5 (khubd)  0xc011a27f in schedule ()
    at /home/amitkale/work/linux-2.6.4-rc2-bk3-kgdb/kernel/sched.c:920
  5 Thread 4 (kblockd/0)  0xc011a27f in schedule ()
    at /home/amitkale/work/linux-2.6.4-rc2-bk3-kgdb/kernel/sched.c:920
---Type <return> to continue, or q <return> to quit---
  4 Thread 3 (events/0)  0xc011a27f in schedule ()
    at /home/amitkale/work/linux-2.6.4-rc2-bk3-kgdb/kernel/sched.c:920
  3 Thread 2 (ksoftirqd/0)  0xc011a27f in schedule ()
    at /home/amitkale/work/linux-2.6.4-rc2-bk3-kgdb/kernel/sched.c:920
  2 Thread 1 (init)  0xc1146000 in ?? ()
* 1 Thread 1130 (cupsd)  breakpoint ()
    at /home/amitkale/work/linux-2.6.4-rc2-bk3-kgdb/kernel/kgdb.c:1088
(gdb) thr 11
[Switching to thread 11 (Thread 10)]#0  0xc011a27f in schedule ()
    at /home/amitkale/work/linux-2.6.4-rc2-bk3-kgdb/kernel/sched.c:920
920             switch_to(prev, next, prev);
(gdb) bt
#0  0xc011a27f in schedule ()
    at /home/amitkale/work/linux-2.6.4-rc2-bk3-kgdb/kernel/sched.c:920
Cannot access memory at address 0x4
(gdb) info fr
Stack level 0, frame at 0x8:
 eip = 0xc011a27f in schedule
    (/home/amitkale/work/linux-2.6.4-rc2-bk3-kgdb/kernel/sched.c:920);
    saved eip Cannot access memory at address 0x4
(gdb) info regi
eax            0x0      0
ecx            0x0      0
edx            0x0      0
ebx            0x0      0
esp            0xc7da3f5c       0xc7da3f5c
ebp            0x0      0x0
esi            0x0      0
edi            0x0      0
eip            0xc011a27f       0xc011a27f
eflags         0x0      0
cs             0x60     96
ss             0x68     104
ds             0x68     104
es             0x68     104
fs             0xffff   65535
gs             0xffff   65535
(gdb) disas 0xc011a270 0xc011a288
Dump of assembler code from 0xc011a270 to 0xc011a288:
0xc011a270 <schedule+784>:      jg     0xc011a214 <schedule+692>
0xc011a272 <schedule+786>:      adc    %eax,%eax
0xc011a274 <schedule+788>:      pushl  0x350(%esi)
0xc011a27a <schedule+794>:      jmp    0xc01079d0 <__switch_to>
0xc011a27f <schedule+799>:      pop    %ebp
0xc011a280 <schedule+800>:      popf
0xc011a281 <schedule+801>:      mov    %eax,0xffffffd0(%ebp)
0xc011a284 <schedule+804>:      xor    %edx,%edx
0xc011a286 <schedule+806>:      mov    0xc04b8edc,%esi
End of assembler dump.
(gdb)


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: kgdb for mainline kernel: core-lite [patch 1/3]
  2004-03-08 15:19               ` Tom Rini
  2004-03-08 22:26                 ` George Anzinger
@ 2004-03-09  8:58                 ` Amit S. Kale
  1 sibling, 0 replies; 27+ messages in thread
From: Amit S. Kale @ 2004-03-09  8:58 UTC (permalink / raw)
  To: Tom Rini; +Cc: Andrew Morton, linux-kernel, george, pavel

On Monday 08 Mar 2004 8:49 pm, Tom Rini wrote:
> On Mon, Mar 08, 2004 at 05:14:05PM +0530, Amit S. Kale wrote:
> > On Monday 08 Mar 2004 4:50 pm, Amit S. Kale wrote:
> > > On Monday 08 Mar 2004 4:37 pm, Andrew Morton wrote:
> > > > "Amit S. Kale" <amitkale@emsyssoft.com> wrote:
> > > > > On Monday 08 Mar 2004 3:56 pm, Andrew Morton wrote:
> > > > >  > "Amit S. Kale" <amitkale@emsyssoft.com> wrote:
> > > > >  > > Here are features that are present only in full kgdb:
> > > > >  > >  1. Thread support  (aka info threads)
> > > > >  >
> > > > >  > argh, disaster.  I discussed this with Tom a week or so ago when
> > > > >  > it looked like this it was being chopped out and I recall being
> > > > >  > told that the discussion was referring to something else.
> > > > >  >
> > > > >  > Ho-hum, sorry.  Can we please put this back in?
> > > > >
> > > > >  Err., well this is one of the particularly dirty parts of kgdb.
> > > > > That's why it's been kept away. It takes care of correct thread
> > > > > backtraces in some rare cases.
> > > >
> > > > Let me just make sure we're taking about the same thing here.  Are
> > > > you saying that with kgdb-lite, `info threads' is completely missing,
> > > > or does it just not work correctly with threads (as opposed to
> > > > heavyweight processes)?
> > >
> > > info threads shows a list of threads. Heavy/light weight processes
> > > doesn't matter. Thread frame shown is incorrect.
> > >
> > > I looked at i386 dependent code again. Following code in it is
> > > incorrect. I never noticed it because this code is rarely used in full
> > > version of kgdb:
> > >
> > > +void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct
> > > task_struct *p)
> > > ....
> > > +	gdb_regs[_EBP] = *(int *)p->thread.esp;
> > >
> > > We can't guss ebp this way. This line should be removed.
> > >
> > > +	gdb_regs[_DS] = __KERNEL_DS;
> > > +	gdb_regs[_ES] = __KERNEL_DS;
> > > +	gdb_regs[_PS] = 0;
> > > +	gdb_regs[_CS] = __KERNEL_CS;
> > > +	gdb_regs[_PC] = p->thread.eip;
> > > +	gdb_regs[_ESP] = p->thread.esp;
> > >
> > > This should be gdb_regs[_ESP] = &p->thread.esp
> >
> > That's not correct it. It should be gdb_regs[_ESP] = p->thread.esp;
> > Even with these changes I can't get thread listing correctly.
> >
> > Here is the intrusive piece of code that helps get thread state
> > correctly. Any ideas on cleaning it?
>
> Here's where what Andi said about being able to get the pt_regs stuff
> off the stack (I think that's what he said at least) started to confuse
> me slightly.  But if I understand it right (and I never got around to

That's an in interesting idea. We can at least get first pt_regs from the 
stack. That way we can get to user space eip in case a thread is in user 
space.

The do_schedule and save all regs is definitely required if we want _exact_ 
state of all kernel threads. [exact state: all registers]

Finding function frames below pt_regs becomes difficult or impossible, as 
exact dept of stack for each function in a stack is not known. EBP chains 
allow walking "up" but not "down".
-Amit


> testing this) we can replace the do_schedule() stuffs at least with
> something like kgdb_get_pt_regs(), since (and I lost my notes on this,
> so it's probably not quite right) (thread_info->esp0)-1


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: kgdb for mainline kernel: core-lite [patch 1/3]
  2004-03-08 10:49       ` Amit S. Kale
  2004-03-08 11:07         ` Andrew Morton
  2004-03-08 22:15         ` George Anzinger
@ 2004-03-09  9:29         ` Amit S. Kale
  2004-03-09  9:32           ` i386-lite [patch 2/3] [Re: kgdb for mainline kernel: core-lite [patch 1/3]] Amit S. Kale
  2004-03-09 15:06           ` kgdb for mainline kernel: core-lite [patch 1/3] Tom Rini
  2 siblings, 2 replies; 27+ messages in thread
From: Amit S. Kale @ 2004-03-09  9:29 UTC (permalink / raw)
  To: Andrew Morton; +Cc: linux-kernel, trini, george, pavel

[-- Attachment #1: Type: text/plain, Size: 2628 bytes --]

On Monday 08 Mar 2004 4:19 pm, Amit S. Kale wrote:
> On Monday 08 Mar 2004 3:56 pm, Andrew Morton wrote:
> > "Amit S. Kale" <amitkale@emsyssoft.com> wrote:
> > > Here are features that are present only in full kgdb:
> > >  1. Thread support  (aka info threads)
> >
> > argh, disaster.  I discussed this with Tom a week or so ago when it
> > looked like this it was being chopped out and I recall being told that
> > the discussion was referring to something else.
> >
> > Ho-hum, sorry.  Can we please put this back in?
>
> Err., well this is one of the particularly dirty parts of kgdb. That's why
> it's been kept away. It takes care of correct thread backtraces in some
> rare cases.
>
> If you consider it an absolutely must, we can do something so that the
> dirty part is kept away and info threads almost always works.

I attempted it and found that it works better than my expectation! I am 
attaching revised core-lite.patch with this email and sending i386-lite.patch 
as a reply.

Here is the code that extract registers of a sleeping thread:
/*
 * Extracts ebp, esp and eip values understandable by gdb from the values
 * saved by switch_to.
 * thread.esp points to ebp. flags and ebp are pushed in switch_to hence esp
 * prior to entering switch_to is 8 greater then the value that is saved.
 * If switch_to changes, change following code appropriately.
 */
void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct 
*p)
{
	gdb_regs[_EAX] = 0;
	gdb_regs[_EBX] = 0;
	gdb_regs[_ECX] = 0;
	gdb_regs[_EDX] = 0;
	gdb_regs[_ESI] = 0;
	gdb_regs[_EDI] = 0;
	gdb_regs[_EBP] = *(unsigned long *)p->thread.esp;
	gdb_regs[_DS] = __KERNEL_DS;
	gdb_regs[_ES] = __KERNEL_DS;
	gdb_regs[_PS] = 0;
	gdb_regs[_CS] = __KERNEL_CS;
	gdb_regs[_PC] = p->thread.eip;
	gdb_regs[_ESP] = p->thread.esp + 8;
	gdb_regs[_SS] = __KERNEL_DS;
	gdb_regs[_FS] = 0xFFFF;
	gdb_regs[_GS] = 0xFFFF;
}

Here is the prologue for schedule
0xc0119f70 <schedule+0>:        push   %ebp
0xc0119f71 <schedule+1>:        mov    %esp,%ebp
0xc0119f73 <schedule+3>:        mov    $0xffffe000,%edx
0xc0119f78 <schedule+8>:        push   %edi
0xc0119f79 <schedule+9>:        push   %esi
0xc0119f7a <schedule+10>:       push   %ebx
0xc0119f7b <schedule+11>:       sub    $0x3c,%esp

gdb is capable of parsing this prolog and figure out saved registers even in 
absence of dwarf debugging information. edi, esi, ebx and ebp are saved in 
standard pattern. eax, ecx and edx are call clobbered, hence not used to 
store locals in a function calling schedule. Hence gdb can print correct 
backtraces with _all_ locals even in callers of schedule!!

-Amit

[-- Attachment #2: core-lite.patch --]
[-- Type: text/x-diff, Size: 41886 bytes --]

Index: linux-2.6.4-rc2-bk3-kgdb/Makefile
===================================================================
--- linux-2.6.4-rc2-bk3-kgdb.orig/Makefile	2004-03-08 14:30:27.000000000 +0530
+++ linux-2.6.4-rc2-bk3-kgdb/Makefile	2004-03-08 14:31:42.000000000 +0530
@@ -440,6 +440,8 @@
 
 ifndef CONFIG_FRAME_POINTER
 CFLAGS		+= -fomit-frame-pointer
+else
+CFLAGS		+= -fno-omit-frame-pointer
 endif
 
 ifdef CONFIG_DEBUG_INFO
Index: linux-2.6.4-rc2-bk3-kgdb/include/linux/debugger.h
===================================================================
--- linux-2.6.4-rc2-bk3-kgdb.orig/include/linux/debugger.h	2003-01-30 15:54:37.000000000 +0530
+++ linux-2.6.4-rc2-bk3-kgdb/include/linux/debugger.h	2004-03-08 14:31:42.000000000 +0530
@@ -0,0 +1,70 @@
+#ifndef _DEBUGGER_H_
+#define _DEBUGGER_H_
+
+/*
+ * Copyright (C) 2003-2004 Amit S. Kale
+ *
+ * Definition switchout for debuggers
+ */
+
+/*
+ * KGDB
+ */
+#ifdef CONFIG_KGDB
+
+typedef int gdb_debug_hook(int exVector, int signo, int err_code,
+			   struct pt_regs *regs);
+extern gdb_debug_hook *linux_debug_hook;
+#define CHK_DEBUGGER(trapnr,signr,error_code,regs,after)			\
+    {									\
+	if (linux_debug_hook != (gdb_debug_hook *) NULL && !user_mode(regs)) \
+	{								\
+		(*linux_debug_hook)(trapnr, signr, error_code, regs) ;	\
+		after;							\
+	}								\
+    }
+
+void kgdb_nmihook(int cpu, void *regs);
+static inline void debugger_nmihook(int cpu, void *regs)
+{
+	kgdb_nmihook(cpu, regs);
+}
+
+void kgdb_entry(void);
+static inline void debugger_entry(void)
+{
+	kgdb_entry();
+}
+
+extern int debugger_step;
+extern atomic_t debugger_active;
+
+/*
+ * No debugger in the kernel
+ */
+#else
+
+#define CHK_DEBUGGER(trapnr,signr,error_code,regs,after)	\
+{									\
+	if (0)								\
+		after;							\
+}
+
+static inline void debugger_nmihook(int cpu, void *regs)
+{
+	/* Do nothing */
+}
+
+static inline void debugger_entry(void)
+{
+	/* Do nothing */
+}
+
+#define debugger_step 0
+static const atomic_t debugger_active = { 0 };
+
+#define debugger_memerr_expected 0
+
+#endif
+
+#endif				/* _DEBUGGER_H_ */
Index: linux-2.6.4-rc2-bk3-kgdb/include/linux/kgdb.h
===================================================================
--- linux-2.6.4-rc2-bk3-kgdb.orig/include/linux/kgdb.h	2003-01-30 15:54:37.000000000 +0530
+++ linux-2.6.4-rc2-bk3-kgdb/include/linux/kgdb.h	2004-03-08 14:31:42.000000000 +0530
@@ -0,0 +1,128 @@
+#ifndef _KGDB_H_
+#define _KGDB_H_
+
+/*
+ * Copyright (C) 2001-2004 Amit S. Kale
+ */
+
+#include <linux/ptrace.h>
+#include <asm/kgdb.h>
+#include <linux/spinlock.h>
+#include <asm/atomic.h>
+#include <linux/debugger.h>
+
+/*
+ * This file should not include ANY others.  This makes it usable
+ * most anywhere without the fear of include order or inclusion.
+ * TODO: Make it so!
+ *
+ * This file may be included all the time.  It is only active if
+ * CONFIG_KGDB is defined, otherwise it stubs out all the macros
+ * and entry points.
+ */
+
+#if defined(CONFIG_KGDB) && !defined(__ASSEMBLY__)
+/* To enter the debugger explicitly. */
+extern void breakpoint(void);
+extern void kgdb_schedule_breakpoint(void);
+extern void kgdb_process_breakpoint(void);
+extern volatile int kgdb_connected;
+
+#ifndef KGDB_MAX_NO_CPUS
+#if CONFIG_NR_CPUS > 8
+#error KGDB can handle max 8 CPUs
+#endif
+#define KGDB_MAX_NO_CPUS 8
+#endif
+
+extern atomic_t kgdb_setting_breakpoint;
+
+extern struct task_struct *kgdb_usethread, *kgdb_contthread;
+
+enum kgdb_bptype {
+	bp_breakpoint = '0',
+	bp_hardware_breakpoint,
+	bp_write_watchpoint,
+	bp_read_watchpoint,
+	bp_access_watchpoint
+};
+
+enum kgdb_bpstate {
+	bp_disabled,
+	bp_enabled
+};
+
+struct kgdb_bkpt {
+	unsigned long bpt_addr;
+	unsigned char saved_instr[BREAK_INSTR_SIZE];
+	enum kgdb_bptype type;
+	enum kgdb_bpstate state;
+};
+
+#ifndef BREAK_INSTR_SIZE
+#error BREAK_INSTR_SIZE  needed by kgdb
+#endif
+
+#ifndef MAX_BREAKPOINTS
+#define MAX_BREAKPOINTS        16
+#endif
+
+#define KGDB_HW_BREAKPOINT          1
+
+/* These are functions that the arch specific code can, and in some cases
+ * must, provide. */
+extern int kgdb_arch_init(void);
+extern void regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs);
+extern void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs,
+					struct task_struct *p);
+extern void gdb_regs_to_regs(unsigned long *gdb_regs, struct pt_regs *regs);
+extern void kgdb_printexceptioninfo(int exceptionNo, int errorcode,
+				    char *buffer);
+extern void kgdb_disable_hw_debug(struct pt_regs *regs);
+extern void kgdb_post_master_code(struct pt_regs *regs, int eVector,
+				  int err_code);
+extern int kgdb_arch_handle_exception(int vector, int signo, int err_code,
+				      char *InBuffer, char *outBuffer,
+				      struct pt_regs *regs);
+extern int kgdb_arch_set_break(unsigned long addr, int type);
+extern int kgdb_arch_remove_break(unsigned long addr, int type);
+extern void kgdb_correct_hw_break(void);
+extern void kgdb_shadowinfo(struct pt_regs *regs, char *buffer,
+			    unsigned threadid);
+extern struct task_struct *kgdb_get_shadow_thread(struct pt_regs *regs,
+						  int threadid);
+extern struct pt_regs *kgdb_shadow_regs(struct pt_regs *regs, int threadid);
+
+struct kgdb_arch {
+	unsigned char gdb_bpt_instr[BREAK_INSTR_SIZE];
+	unsigned long flags;
+	unsigned shadowth;
+};
+
+/* Thread reference */
+typedef unsigned char threadref[8];
+
+struct kgdb_serial {
+	int (*read_char) (void);
+	void (*write_char) (int);
+	void (*flush) (void);
+	int (*hook) (void);
+};
+
+extern struct kgdb_serial *kgdb_serial;
+extern struct kgdb_arch arch_kgdb_ops;
+extern int kgdb_initialized;
+
+struct uart_port;
+
+extern void kgdb8250_add_port(int i, struct uart_port *serial_req);
+
+int kgdb_hex2long(char **ptr, long *longValue);
+char *kgdb_mem2hex(char *mem, char *buf, int count);
+char *kgdb_hex2mem(char *buf, char *mem, int count);
+int kgdb_get_mem(char *addr, unsigned char *buf, int count);
+
+#else
+#define kgdb_process_breakpoint()      do {} while(0)
+#endif /* KGDB && !__ASSEMBLY__ */
+#endif				/* _KGDB_H_ */
Index: linux-2.6.4-rc2-bk3-kgdb/init/main.c
===================================================================
--- linux-2.6.4-rc2-bk3-kgdb.orig/init/main.c	2004-03-08 14:30:27.000000000 +0530
+++ linux-2.6.4-rc2-bk3-kgdb/init/main.c	2004-03-08 14:31:42.000000000 +0530
@@ -39,6 +39,7 @@
 #include <linux/writeback.h>
 #include <linux/cpu.h>
 #include <linux/efi.h>
+#include <linux/debugger.h>
 
 #include <asm/io.h>
 #include <asm/bugs.h>
@@ -581,6 +582,7 @@
 
 	smp_init();
 	do_basic_setup();
+	debugger_entry();
 
 	prepare_namespace();
 
Index: linux-2.6.4-rc2-bk3-kgdb/kernel/Makefile
===================================================================
--- linux-2.6.4-rc2-bk3-kgdb.orig/kernel/Makefile	2004-03-08 14:30:26.000000000 +0530
+++ linux-2.6.4-rc2-bk3-kgdb/kernel/Makefile	2004-03-08 14:31:42.000000000 +0530
@@ -19,6 +19,7 @@
 obj-$(CONFIG_COMPAT) += compat.o
 obj-$(CONFIG_IKCONFIG) += configs.o
 obj-$(CONFIG_IKCONFIG_PROC) += configs.o
+obj-$(CONFIG_KGDB) += kgdb.o
 
 ifneq ($(CONFIG_IA64),y)
 # According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
Index: linux-2.6.4-rc2-bk3-kgdb/kernel/kgdb.c
===================================================================
--- linux-2.6.4-rc2-bk3-kgdb.orig/kernel/kgdb.c	2003-01-30 15:54:37.000000000 +0530
+++ linux-2.6.4-rc2-bk3-kgdb/kernel/kgdb.c	2004-03-09 14:16:45.250879088 +0530
@@ -0,0 +1,1278 @@
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+/*
+ * Copyright (C) 2000-2001 VERITAS Software Corporation.
+ * Copyright (C) 2002-2004 Timesys Corporation
+ * Copyright (C) 2003-2004 Amit S. Kale
+ * Copyright (C) 2004 Pavel Machek <pavel@suse.cz>
+ * Copyright (C) 2004 Tom Rini <trini@kernel.crashing.org>
+ *
+ * Restructured KGDB for 2.6 kernels.
+ * thread support, support for multiple processors,support for ia-32(x86) 
+ * hardware debugging, Console support, handling nmi watchdog
+ * - Amit S. Kale ( amitkale@emsyssoft.com )
+ *
+ * Several enhancements by George Anzinger <george@mvista.com>
+ * Generic KGDB Support
+ * Implemented by Anurekh Saxena (anurekh.saxena@timesys.com)
+ * 
+ * Contributor:     Lake Stevens Instrument Division
+ * Written by:      Glenn Engel
+ *  
+ * Modified for 386 by Jim Kingdon, Cygnus Support.
+ * Origianl kgdb, compatibility with 2.1.xx kernel by David Grothe <dave@gcom.com>
+ * Integrated into 2.2.5 kernel by Tigran Aivazian <tigran@sco.com>
+ */
+
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <asm/system.h>
+#include <asm/ptrace.h>
+#include <asm/uaccess.h>
+#include <linux/kgdb.h>
+#include <asm/atomic.h>
+#include <linux/notifier.h>
+#include <linux/module.h>
+#include <asm/cacheflush.h>
+#ifdef CONFIG_KGDB_CONSOLE
+#include <linux/console.h>
+#endif
+#include <linux/init.h>
+
+extern int pid_max;
+
+#define BUF_THREAD_ID_SIZE 16
+
+/*
+ * kgdb_initialized indicates that kgdb is setup and is all ready to serve
+ * breakpoints and other kernel exceptions. kgdb_connected indicates that kgdb
+ * has connected to kgdb.
+ */
+int kgdb_initialized = 0;
+volatile int kgdb_connected;
+
+/* If non-zero, wait for a gdb connection when kgdb_entry is called */
+int kgdb_enter = 0;
+
+/* Set to 1 to make kgdb allow access to user addresses. Can be set from gdb
+ * also at runtime. */
+int kgdb_useraccess = 0;
+
+struct kgdb_serial *kgdb_serial;
+
+/*
+ * Holds information about breakpoints in a kernel. These breakpoints are
+ * added and removed by gdb.
+ */
+struct kgdb_bkpt kgdb_break[MAX_BREAKPOINTS];
+
+struct kgdb_arch *kgdb_ops = &arch_kgdb_ops;
+
+static const char hexchars[] = "0123456789abcdef";
+
+static spinlock_t slavecpulocks[KGDB_MAX_NO_CPUS];
+static volatile int procindebug[KGDB_MAX_NO_CPUS];
+atomic_t kgdb_setting_breakpoint;
+struct task_struct *kgdb_usethread, *kgdb_contthread;
+
+int debugger_step;
+atomic_t debugger_active;
+
+/* This will point to kgdb_handle_exception by default.
+ * The architecture code can override this in its init function
+ */
+gdb_debug_hook *linux_debug_hook;
+
+static char remcom_in_buffer[BUFMAX];
+static char remcom_out_buffer[BUFMAX];
+
+/*
+ * The following are the stub functions for code which is arch specific
+ * and can be omitted on some arches
+ * This function will handle the initalization of any architecture specific
+ * hooks.  If there is a suitable early output driver, kgdb_serial
+ * can be pointed at it now.
+ */
+int __attribute__ ((weak))
+    kgdb_arch_init(void)
+{
+	return 0;
+}
+
+void __attribute__ ((weak))
+    regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+{
+}
+
+void __attribute__ ((weak))
+    sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
+{
+}
+
+void __attribute__ ((weak))
+    gdb_regs_to_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+{
+}
+
+void __attribute__ ((weak))
+    kgdb_printexceptioninfo(int exceptionNo, int errorcode, char *buffer)
+{
+}
+
+void __attribute__ ((weak))
+    kgdb_disable_hw_debug(struct pt_regs *regs)
+{
+}
+
+void __attribute__ ((weak))
+    kgdb_post_master_code(struct pt_regs *regs, int eVector, int err_code)
+{
+}
+
+/*
+ * Handle any additional commands.  This must handle the 'c' and 's'
+ * command packets.
+ * Return -1 to loop over other commands, and 0 to exit from KGDB
+ */
+int __attribute__ ((weak))
+    kgdb_arch_handle_exception(int vector, int signo, int err_code, char *InBuffer,
+			   char *outBuffer, struct pt_regs *regs)
+{
+	return 0;
+}
+
+int __attribute__ ((weak))
+    kgdb_arch_set_break(unsigned long addr, int type)
+{
+	return 0;
+}
+
+int __attribute__ ((weak))
+    kgdb_arch_remove_break(unsigned long addr, int type)
+{
+	return 0;
+}
+
+void __attribute__ ((weak))
+    kgdb_correct_hw_break(void)
+{
+}
+
+void __attribute__ ((weak))
+    kgdb_shadowinfo(struct pt_regs *regs, char *buffer, unsigned threadid)
+{
+}
+
+struct task_struct __attribute__ ((weak))
+    * kgdb_get_shadow_thread(struct pt_regs *regs, int threadid)
+{
+	return NULL;
+}
+
+struct pt_regs __attribute__ ((weak))
+    * kgdb_shadow_regs(struct pt_regs *regs, int threadid)
+{
+	return NULL;
+}
+
+static int hex(char ch)
+{
+	if ((ch >= 'a') && (ch <= 'f'))
+		return (ch - 'a' + 10);
+	if ((ch >= '0') && (ch <= '9'))
+		return (ch - '0');
+	if ((ch >= 'A') && (ch <= 'F'))
+		return (ch - 'A' + 10);
+	return (-1);
+}
+
+/* scan for the sequence $<data>#<checksum>	*/
+static void get_packet(char *buffer)
+{
+	unsigned char checksum;
+	unsigned char xmitcsum;
+	int i;
+	int count;
+	char ch;
+
+	do {
+		/* wait around for the start character, ignore all other
+		 * characters */
+		while ((ch = (kgdb_serial->read_char() & 0x7f)) != '$')
+			;	/* Spin. */
+		kgdb_connected = 1;
+		checksum = 0;
+		xmitcsum = -1;
+
+		count = 0;
+
+		/* now, read until a # or end of buffer is found */
+		while (count < (BUFMAX - 1)) {
+			ch = kgdb_serial->read_char() & 0x7f;
+			if (ch == '#')
+				break;
+			checksum = checksum + ch;
+			buffer[count] = ch;
+			count = count + 1;
+		}
+		buffer[count] = 0;
+
+		if (ch == '#') {
+			xmitcsum = hex(kgdb_serial->read_char() & 0x7f) << 4;
+			xmitcsum += hex(kgdb_serial->read_char() & 0x7f);
+
+			if (checksum != xmitcsum)
+				kgdb_serial->write_char('-');	/* failed checksum */
+			else
+				kgdb_serial->write_char('+');	/* successful transfer */
+			if (kgdb_serial->flush)
+				kgdb_serial->flush();
+		}
+	} while (checksum != xmitcsum);
+}
+
+/*
+ * Send the packet in buffer.
+ * Check for gdb connection if asked for.
+ */
+static void put_packet(char *buffer)
+{
+	unsigned char checksum;
+	int count;
+	char ch;
+
+	/*  $<packet info>#<checksum>. */
+	while (1) {
+		kgdb_serial->write_char('$');
+		checksum = 0;
+		count = 0;
+
+		while ((ch = buffer[count])) {
+			kgdb_serial->write_char(ch);
+			checksum += ch;
+			count++;
+		}
+
+		kgdb_serial->write_char('#');
+		kgdb_serial->write_char(hexchars[checksum >> 4]);
+		kgdb_serial->write_char(hexchars[checksum % 16]);
+		if (kgdb_serial->flush)
+			kgdb_serial->flush();
+
+		/* Now see what we get in reply. */
+		ch = kgdb_serial->read_char();
+
+		if (ch == 3)
+			ch = kgdb_serial->read_char();
+
+		/* If we get an ACK, we are done. */
+		if (ch == '+')
+			return;
+
+		/* If we get the start of another packet, this means
+		 * that GDB is attempting to reconnect.  We will NAK
+		 * the packet being sent, and stop trying to send this
+		 * packet. */
+		if (ch == '$') {
+			kgdb_serial->write_char('-');
+			if (kgdb_serial->flush)
+				kgdb_serial->flush();
+			return;
+		}
+	}
+}
+
+static int get_char(char *addr, unsigned char *data)
+{
+	mm_segment_t fs;
+	int ret = 0;
+
+	if (!kgdb_useraccess && (unsigned long)addr < TASK_SIZE) {
+		return -EINVAL;
+	}
+	wmb();
+	fs = get_fs();
+	set_fs(KERNEL_DS);
+
+	if (get_user(*data, addr) != 0) {
+		ret = -EFAULT;
+	}
+
+	set_fs(fs);
+	return ret;
+}
+
+static int set_char(char *addr, int data)
+{
+	mm_segment_t fs;
+	int ret = 0;
+
+	if (!kgdb_useraccess && (unsigned long)addr < TASK_SIZE) {
+		return -EINVAL;
+	}
+	wmb();
+	fs = get_fs();
+	set_fs(KERNEL_DS);
+
+	if (put_user(data, addr) != 0) {
+		ret = -EFAULT;
+	}
+
+	set_fs(fs);
+	return ret;
+}
+
+/*
+ * convert the memory pointed to by mem into hex, placing result in buf
+ * return a pointer to the last char put in buf (null). May return an error.
+ */
+char *kgdb_mem2hex(char *mem, char *buf, int count)
+{
+	int i;
+	unsigned char ch;
+	int error;
+
+	for (i = 0; i < count; i++) {
+
+		if ((error = get_char(mem++, &ch)) < 0)
+			return ERR_PTR(error);
+
+		*buf++ = hexchars[ch >> 4];
+		*buf++ = hexchars[ch % 16];
+	}
+	*buf = 0;
+	return (buf);
+}
+
+/*
+ * convert the hex array pointed to by buf into binary to be placed in mem
+ * return a pointer to the character AFTER the last byte written
+ * May return an error.
+ */
+char *kgdb_hex2mem(char *buf, char *mem, int count)
+{
+	int i;
+	unsigned char ch;
+	int error;
+
+	for (i = 0; i < count; i++) {
+		ch = hex(*buf++) << 4;
+		ch = ch + hex(*buf++);
+		if ((error = set_char(mem++, ch)) < 0)
+			return ERR_PTR(error);
+	}
+	return (mem);
+}
+
+/*
+ * While we find nice hex chars, build a longValue.
+ * Return number of chars processed.
+ */
+int kgdb_hex2long(char **ptr, long *longValue)
+{
+	int numChars = 0;
+	int hexValue;
+
+	*longValue = 0;
+
+	while (**ptr) {
+		hexValue = hex(**ptr);
+		if (hexValue >= 0) {
+			*longValue = (*longValue << 4) | hexValue;
+			numChars++;
+		} else
+			break;
+
+		(*ptr)++;
+	}
+
+	return (numChars);
+}
+
+static inline char *pack_hex_byte(char *pkt, int byte)
+{
+	*pkt++ = hexchars[(byte >> 4) & 0xf];
+	*pkt++ = hexchars[(byte & 0xf)];
+	return pkt;
+}
+
+static inline void error_packet(char *pkt, int error)
+{
+	error = -error;
+	pkt[0] = 'E';
+	pkt[1] = hexchars[(error / 10)];
+	pkt[2] = hexchars[(error % 10)];
+	pkt[3] = '\0';
+}
+
+static char *pack_threadid(char *pkt, threadref * id)
+{
+	char *limit;
+	unsigned char *altid;
+
+	altid = (unsigned char *)id;
+	limit = pkt + BUF_THREAD_ID_SIZE;
+	while (pkt < limit)
+		pkt = pack_hex_byte(pkt, *altid++);
+
+	return pkt;
+}
+
+void int_to_threadref(threadref * id, int value)
+{
+	unsigned char *scan;
+
+	scan = (unsigned char *)id;
+	{
+		int i = 4;
+		while (i--)
+			*scan++ = 0;
+	}
+	*scan++ = (value >> 24) & 0xff;
+	*scan++ = (value >> 16) & 0xff;
+	*scan++ = (value >> 8) & 0xff;
+	*scan++ = (value & 0xff);
+}
+
+static struct task_struct *getthread(struct pt_regs *regs, int tid)
+{
+	int i;
+	struct list_head *l;
+	struct task_struct *p;
+	struct pid *pid;
+
+	if (tid >= pid_max + num_online_cpus() + kgdb_ops->shadowth) {
+		return NULL;
+	}
+	if (tid >= pid_max + num_online_cpus()) {
+		return kgdb_get_shadow_thread(regs, tid - pid_max -
+					      num_online_cpus());
+	}
+	if (tid >= pid_max) {
+		i = 0;
+		for_each_task_pid(0, PIDTYPE_PID, p, l, pid) {
+			if (tid == pid_max + i) {
+				return p;
+			}
+			i++;
+		}
+		return NULL;
+	}
+	if (!tid) {
+		return NULL;
+	}
+	return find_task_by_pid(tid);
+}
+
+#ifdef CONFIG_SMP
+void kgdb_wait(struct pt_regs *regs)
+{
+	unsigned long flags;
+	int processor;
+
+	local_irq_save(flags);
+	processor = smp_processor_id();
+	procindebug[processor] = 1;
+	current->thread.debuggerinfo = regs;
+
+	/* Wait till master processor goes completely into the debugger.
+	 * FIXME: this looks racy */
+	while (!procindebug[atomic_read(&debugger_active) - 1]) {
+		int i = 10;	/* an arbitrary number */
+
+		while (--i)
+			asm volatile ("nop":::"memory");
+		barrier();
+	}
+
+	/* Wait till master processor is done with debugging */
+	spin_lock(slavecpulocks + processor);
+
+	/* This has been taken from x86 kgdb implementation and
+	 * will be needed by architectures that have SMP support
+	 */
+	kgdb_correct_hw_break();
+
+	current->thread.debuggerinfo = NULL;
+
+	/* Signal the master processor that we are done */
+	procindebug[processor] = 0;
+	spin_unlock(slavecpulocks + processor);
+	local_irq_restore(flags);
+}
+#endif
+
+int kgdb_get_mem(char *addr, unsigned char *buf, int count)
+{
+	int error;
+	while (count) {
+		if ((error = get_char(addr++, buf)) < 0)
+			return error;
+		buf++;
+		count--;
+	}
+	return 0;
+}
+
+static int set_mem(char *addr, unsigned char *buf, int count)
+{
+	int error;
+	while (count) {
+		if ((error = set_char(addr++, *buf++)) < 0)
+			return error;
+		count--;
+	}
+	return 0;
+}
+
+static int set_break(unsigned long addr)
+{
+	int i, breakno = -1;
+	int error;
+
+	for (i = 0; i < MAX_BREAKPOINTS; i++) {
+		if ((kgdb_break[i].state == bp_enabled) &&
+		    (kgdb_break[i].bpt_addr == addr)) {
+			return -EEXIST;
+		}
+
+		if (kgdb_break[i].state == bp_disabled) {
+			if ((breakno == -1) || (kgdb_break[i].bpt_addr == addr))
+				breakno = i;
+		}
+	}
+	if (breakno == -1)
+		return -E2BIG;
+
+	if ((error = kgdb_get_mem((char *)addr, kgdb_break[breakno].saved_instr,
+				  BREAK_INSTR_SIZE)) < 0)
+		return error;
+
+	if ((error = set_mem((char *)addr, kgdb_ops->gdb_bpt_instr,
+			     BREAK_INSTR_SIZE)) < 0)
+		return error;
+	flush_cache_range(current->mm, addr, addr + BREAK_INSTR_SIZE);
+	flush_icache_range(addr, addr + BREAK_INSTR_SIZE);
+
+	kgdb_break[breakno].state = bp_enabled;
+	kgdb_break[breakno].type = bp_breakpoint;
+	kgdb_break[breakno].bpt_addr = addr;
+
+	return 0;
+}
+
+static int remove_break(unsigned long addr)
+{
+	int i;
+	int error;
+
+	for (i = 0; i < MAX_BREAKPOINTS; i++) {
+		if ((kgdb_break[i].state == bp_enabled) &&
+		    (kgdb_break[i].bpt_addr == addr)) {
+			if ((error =
+			     set_mem((char *)addr, kgdb_break[i].saved_instr,
+				     BREAK_INSTR_SIZE)) < 0)
+				return error;
+			flush_cache_range(current->mm, addr,
+					  addr + BREAK_INSTR_SIZE);
+			flush_icache_range(addr, addr + BREAK_INSTR_SIZE);
+			kgdb_break[i].state = bp_disabled;
+			return 0;
+		}
+	}
+	return -ENOENT;
+}
+
+int remove_all_break(void)
+{
+	int i;
+	int error;
+	for (i = 0; i < MAX_BREAKPOINTS; i++) {
+		if (kgdb_break[i].state == bp_enabled) {
+			unsigned long addr = kgdb_break[i].bpt_addr;
+			if ((error =
+			     set_mem((char *)addr, kgdb_break[i].saved_instr,
+				     BREAK_INSTR_SIZE)) < 0)
+				return error;
+			flush_cache_range(current->mm, addr,
+					  addr + BREAK_INSTR_SIZE);
+			flush_icache_range(addr, addr + BREAK_INSTR_SIZE);
+		}
+		kgdb_break[i].state = bp_disabled;
+	}
+	return 0;
+}
+
+static inline int shadow_pid(int realpid)
+{
+	if (realpid) {
+		return realpid;
+	}
+	return pid_max + smp_processor_id();
+}
+
+/*
+ * This function does all command procesing for interfacing to gdb.
+ *
+ * Locking hierarchy:
+ *	interface locks, if any (begin_session)
+ *	kgdb lock (debugger_active)
+ *
+ */
+int kgdb_handle_exception(int exVector, int signo, int err_code,
+			  struct pt_regs *linux_regs)
+{
+	unsigned long length, addr;
+	char *ptr;
+	unsigned long flags;
+	unsigned long gdb_regs[NUMREGBYTES / sizeof(unsigned long)];
+	int i;
+	long threadid;
+	threadref thref;
+	struct task_struct *thread = NULL;
+	unsigned procid;
+	static char tmpstr[256];
+	int numshadowth = num_online_cpus() + kgdb_ops->shadowth;
+	long kgdb_usethreadid = 0;
+	int error = 0;
+	struct pt_regs *shadowregs;
+
+	/* Panic on recursive debugger calls. */
+	if (atomic_read(&debugger_active) == smp_processor_id() + 1) {
+		return 0;
+	}
+
+	/* 
+	 * Interrupts will be restored by the 'trap return' code, except when
+	 * single stepping.
+	 */
+	local_irq_save(flags);
+
+	/* Hold debugger_active */
+	procid = smp_processor_id();
+	while (cmpxchg(&atomic_read(&debugger_active), 0, (procid + 1)) != 0) {
+		int i = 25;	/* an arbitrary number */
+
+		while (--i)
+			asm volatile ("nop":::"memory");
+	}
+
+	debugger_step = 0;
+
+	current->thread.debuggerinfo = linux_regs;
+
+	kgdb_disable_hw_debug(linux_regs);
+
+	for (i = 0; i < num_online_cpus(); i++) {
+		spin_lock(&slavecpulocks[i]);
+	}
+
+	/* spin_lock code is good enough as a barrier so we don't
+	 * need one here */
+	procindebug[smp_processor_id()] = 1;
+
+	/* Clear the out buffer. */
+	memset(remcom_out_buffer, 0, sizeof(remcom_out_buffer));
+
+	/* Master processor is completely in the debugger */
+	kgdb_post_master_code(linux_regs, exVector, err_code);
+
+	if (kgdb_connected) {
+		/* reply to host that an exception has occurred */
+		ptr = remcom_out_buffer;
+		*ptr++ = 'T';
+		*ptr++ = hexchars[(signo >> 4) % 16];
+		*ptr++ = hexchars[signo % 16];
+		ptr += strlen(strcpy(ptr, "thread:"));
+		int_to_threadref(&thref, shadow_pid(current->pid));
+		ptr = pack_threadid(ptr, &thref);
+		*ptr++ = ';';
+
+		put_packet(remcom_out_buffer);
+	}
+
+	kgdb_usethread = current;
+	kgdb_usethreadid = shadow_pid(current->pid);
+
+	while (1) {
+		int bpt_type = 0;
+		error = 0;
+
+		/* Clear the out buffer. */
+		memset(remcom_out_buffer, 0, sizeof(remcom_out_buffer));
+
+		get_packet(remcom_in_buffer);
+
+		switch (remcom_in_buffer[0]) {
+		case '?':
+			/* We know that this packet is only sent
+			 * during initial connect.  So to be safe,
+			 * we clear out our breakpoints now incase
+			 * GDB is reconnecting. */
+			remove_all_break();
+			remcom_out_buffer[0] = 'S';
+			remcom_out_buffer[1] = hexchars[signo >> 4];
+			remcom_out_buffer[2] = hexchars[signo % 16];
+			break;
+
+		case 'g':	/* return the value of the CPU registers */
+			thread = kgdb_usethread;
+
+			if (!thread)
+				thread = current;
+
+			/* All threads that don't have debuggerinfo should be
+			   in __schedule() sleeping, since all other CPUs
+			   are in kgdb_wait, and thus have debuggerinfo. */
+
+			if (kgdb_usethreadid >= pid_max + num_online_cpus()) {
+				shadowregs = kgdb_shadow_regs(linux_regs,
+							      kgdb_usethreadid -
+							      pid_max -
+							      num_online_cpus
+							      ());
+				if (!shadowregs) {
+					error_packet(remcom_out_buffer,
+						     -EINVAL);
+					break;
+				}
+				regs_to_gdb_regs(gdb_regs, shadowregs);
+			} else if (thread->thread.debuggerinfo) {
+				if ((error =
+				     get_char(thread->thread.debuggerinfo,
+					      (unsigned char *)gdb_regs)) < 0) {
+					error_packet(remcom_out_buffer, error);
+					break;
+				}
+				regs_to_gdb_regs(gdb_regs, (struct pt_regs *)
+						 thread->thread.debuggerinfo);
+			} else {
+				/* Pull stuff saved during 
+				 * switch_to; nothing else is
+				 * accessible (or even particularly relevant).
+				 * This should be enough for a stack trace. */
+				sleeping_thread_to_gdb_regs(gdb_regs, thread);
+			}
+
+			kgdb_mem2hex((char *)gdb_regs, remcom_out_buffer,
+				     NUMREGBYTES);
+			break;
+
+		case 'G':	/* set the value of the CPU registers - return OK */
+			kgdb_hex2mem(&remcom_in_buffer[1], (char *)gdb_regs,
+				     NUMREGBYTES);
+
+			if (kgdb_usethread && kgdb_usethread != current)
+				error_packet(remcom_out_buffer, -EINVAL);
+			else {
+				gdb_regs_to_regs(gdb_regs, (struct pt_regs *)
+						 current->thread.debuggerinfo);
+				strcpy(remcom_out_buffer, "OK");
+			}
+
+			break;
+
+			/* mAA..AA,LLLL  Read LLLL bytes at address AA..AA */
+		case 'm':
+			ptr = &remcom_in_buffer[1];
+			if (kgdb_hex2long(&ptr, &addr) > 0 && *ptr++ == ',' &&
+			    kgdb_hex2long(&ptr, &length) > 0) {
+				if (IS_ERR(ptr = kgdb_mem2hex((char *)addr,
+							      remcom_out_buffer,
+							      length)))
+					error_packet(remcom_out_buffer,
+						     PTR_ERR(ptr));
+			} else
+				error_packet(remcom_out_buffer, -EINVAL);
+			break;
+
+			/* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
+		case 'M':
+			ptr = &remcom_in_buffer[1];
+			if (kgdb_hex2long(&ptr, &addr) > 0 && *(ptr++) == ','
+			    && kgdb_hex2long(&ptr, &length) > 0 &&
+			    *(ptr++) == ':') {
+				if (IS_ERR(ptr = kgdb_hex2mem(ptr, (char *)addr,
+							      length)))
+					error_packet(remcom_out_buffer,
+						     PTR_ERR(ptr));
+			} else
+				error_packet(remcom_out_buffer, -EINVAL);
+			break;
+
+			/* kill or detach. KGDB should treat this like a 
+			 * continue.
+			 */
+		case 'D':
+			if ((error = remove_all_break()) < 0) {
+				error_packet(remcom_out_buffer, error);
+			} else {
+				strcpy(remcom_out_buffer, "OK");
+				kgdb_connected = 0;
+			}
+			put_packet(remcom_out_buffer);
+			goto default_handle;
+
+		case 'k':
+			/* Don't care about error from remove_all_break */
+			remove_all_break();
+			kgdb_connected = 0;
+			goto default_handle;
+
+			/* query */
+		case 'q':
+			switch (remcom_in_buffer[1]) {
+			case 's':
+			case 'f':
+				if (memcmp
+				    (remcom_in_buffer + 2, "ThreadInfo", 10)) {
+					error_packet(remcom_out_buffer,
+						     -EINVAL);
+					break;
+				}
+				if (remcom_in_buffer[1] == 'f') {
+					threadid = 1;
+				}
+				remcom_out_buffer[0] = 'm';
+				ptr = remcom_out_buffer + 1;
+				for (i = 0; i < 32 && threadid < pid_max +
+				     numshadowth; threadid++) {
+					thread = getthread(linux_regs,
+							   threadid);
+					if (thread) {
+						int_to_threadref(&thref,
+								 threadid);
+						pack_threadid(ptr, &thref);
+						ptr += 16;
+						*(ptr++) = ',';
+						i++;
+					}
+				}
+				*(--ptr) = '\0';
+				break;
+
+			case 'C':
+				/* Current thread id */
+				strcpy(remcom_out_buffer, "QC");
+
+				threadid = shadow_pid(current->pid);
+
+				int_to_threadref(&thref, threadid);
+				pack_threadid(remcom_out_buffer + 2, &thref);
+				break;
+
+			case 'E':
+				/* Print exception info */
+				kgdb_printexceptioninfo(exVector, err_code,
+							remcom_out_buffer);
+				break;
+			case 'T':
+				if (memcmp(remcom_in_buffer + 1,
+					   "ThreadExtraInfo,", 16)) {
+					error_packet(remcom_out_buffer,
+						     -EINVAL);
+					break;
+				}
+				threadid = 0;
+				ptr = remcom_in_buffer + 17;
+				kgdb_hex2long(&ptr, &threadid);
+				if (!getthread(linux_regs, threadid)) {
+					error_packet(remcom_out_buffer,
+						     -EINVAL);
+					break;
+				}
+				if (threadid < pid_max) {
+					kgdb_mem2hex(getthread(linux_regs,
+							       threadid)->comm,
+						     remcom_out_buffer, 16);
+				} else if (threadid >= pid_max +
+					   num_online_cpus()) {
+					kgdb_shadowinfo(linux_regs,
+							remcom_out_buffer,
+							threadid - pid_max -
+							num_online_cpus());
+				} else {
+					sprintf(tmpstr, "Shadow task %d"
+						" for pid 0",
+						(int)(threadid - pid_max));
+					kgdb_mem2hex(tmpstr, remcom_out_buffer,
+						     strlen(tmpstr));
+				}
+				break;
+			}
+			break;
+
+			/* task related */
+		case 'H':
+			switch (remcom_in_buffer[1]) {
+			case 'g':
+				ptr = &remcom_in_buffer[2];
+				kgdb_hex2long(&ptr, &threadid);
+				thread = getthread(linux_regs, threadid);
+				if (!thread && threadid > 0) {
+					error_packet(remcom_out_buffer,
+						     -EINVAL);
+					break;
+				}
+				kgdb_usethread = thread;
+				kgdb_usethreadid = threadid;
+				strcpy(remcom_out_buffer, "OK");
+				break;
+
+			case 'c':
+				ptr = &remcom_in_buffer[2];
+				kgdb_hex2long(&ptr, &threadid);
+				if (!threadid) {
+					kgdb_contthread = 0;
+				} else {
+					thread =
+					    getthread(linux_regs, threadid);
+					if (!thread && threadid > 0) {
+						error_packet(remcom_out_buffer,
+							     -EINVAL);
+						break;
+					}
+					kgdb_contthread = thread;
+				}
+				strcpy(remcom_out_buffer, "OK");
+				break;
+			}
+			break;
+
+			/* Query thread status */
+		case 'T':
+			ptr = &remcom_in_buffer[1];
+			kgdb_hex2long(&ptr, &threadid);
+			thread = getthread(linux_regs, threadid);
+			if (thread)
+				strcpy(remcom_out_buffer, "OK");
+			else
+				error_packet(remcom_out_buffer, -EINVAL);
+			break;
+		case 'z':
+		case 'Z':
+			ptr = &remcom_in_buffer[2];
+			if (*(ptr++) != ',') {
+				error_packet(remcom_out_buffer, -EINVAL);
+				break;
+			}
+			kgdb_hex2long(&ptr, &addr);
+
+			bpt_type = remcom_in_buffer[1];
+			if (bpt_type != bp_breakpoint) {
+				if (bpt_type == bp_hardware_breakpoint &&
+				    !(kgdb_ops->flags & KGDB_HW_BREAKPOINT))
+					break;
+
+				/* if set_break is not defined, then
+				 * remove_break does not matter
+				 */
+				if (!(kgdb_ops->flags & KGDB_HW_BREAKPOINT))
+					break;
+			}
+
+			if (remcom_in_buffer[0] == 'Z') {
+				if (bpt_type == bp_breakpoint)
+					error = set_break(addr);
+				else
+					error = kgdb_arch_set_break(addr,
+								    bpt_type);
+			} else {
+				if (bpt_type == bp_breakpoint)
+					error = remove_break(addr);
+				else
+					error = kgdb_arch_remove_break(addr,
+								       bpt_type);
+			}
+
+			if (error == 0)
+				strcpy(remcom_out_buffer, "OK");
+			else
+				error_packet(remcom_out_buffer, error);
+
+			break;
+
+		default:
+		      default_handle:
+			error = kgdb_arch_handle_exception(exVector, signo,
+							   err_code,
+							   remcom_in_buffer,
+							   remcom_out_buffer,
+							   linux_regs);
+
+			if (error >= 0 || remcom_in_buffer[0] == 'D' ||
+			    remcom_in_buffer[0] == 'k')
+				goto kgdb_exit;
+
+		}		/* switch */
+
+		/* reply to the request */
+		put_packet(remcom_out_buffer);
+	}
+
+      kgdb_exit:
+	current->thread.debuggerinfo = NULL;
+	procindebug[smp_processor_id()] = 0;
+
+	for (i = 0; i < num_online_cpus(); i++) {
+		spin_unlock(&slavecpulocks[i]);
+	}
+	/* Wait till all the processors have quit
+	 * from the debugger 
+	 */
+	for (i = 0; i < num_online_cpus(); i++) {
+		while (procindebug[i]) {
+			int j = 10;	/* an arbitrary number */
+
+			while (--j) {
+				asm volatile ("nop":::"memory");
+			}
+			barrier();
+		}
+	}
+
+	/* Free debugger_active */
+	atomic_set(&debugger_active, 0);
+	local_irq_restore(flags);
+
+	return error;
+}
+
+/*
+ * GDB places a breakpoint at this function to know dynamically
+ * loaded objects. It's not defined static so that only one instance with this
+ * name exists in the kernel.
+ */
+
+int module_event(struct notifier_block *self, unsigned long val, void *data)
+{
+	return 0;
+}
+
+static struct notifier_block kgdb_module_load_nb = {
+	.notifier_call = module_event,
+};
+
+/* This function will generate a breakpoint exception.  It is used at the
+   beginning of a program to sync up with a debugger and can be used
+   otherwise as a quick means to stop program execution and "break" into
+   the debugger. */
+
+void breakpoint(void)
+{
+	if (!kgdb_initialized) {
+		kgdb_enter = 1;
+		kgdb_entry();
+		if (!kgdb_initialized) {
+			printk("kgdb not enabled. Cannot do breakpoint\n");
+			return;
+		}
+	}
+
+	atomic_set(&kgdb_setting_breakpoint, 1);
+	wmb();
+	BREAKPOINT();
+	wmb();
+	atomic_set(&kgdb_setting_breakpoint, 0);
+}
+
+void kgdb_nmihook(int cpu, void *regs)
+{
+#ifdef CONFIG_SMP
+	if (!procindebug[cpu] && atomic_read(&debugger_active) != (cpu + 1)) {
+		kgdb_wait((struct pt_regs *)regs);
+	}
+#endif
+}
+
+void kgdb_entry(void)
+{
+	int i;
+
+	if (kgdb_initialized) {
+		/* KGDB was initialized */
+		return;
+	}
+
+	for (i = 0; i < KGDB_MAX_NO_CPUS; i++)
+		spin_lock_init(&slavecpulocks[i]);
+
+	/* Free debugger_active */
+	atomic_set(&debugger_active, 0);
+
+	for (i = 0; i < MAX_BREAKPOINTS; i++)
+		kgdb_break[i].state = bp_disabled;
+
+	linux_debug_hook = kgdb_handle_exception;
+
+	/* Let the arch do any initalization it needs to, including
+	 * pointing to a suitable early output device. */
+	kgdb_arch_init();
+
+	/* We can't do much if this fails */
+	register_module_notifier(&kgdb_module_load_nb);
+
+	atomic_set(&kgdb_setting_breakpoint, 0);
+
+	if (!kgdb_serial || kgdb_serial->hook() < 0) {
+		/* KGDB interface isn't ready yet */
+		return;
+	}
+	kgdb_initialized = 1;
+	if (!kgdb_enter) {
+		return;
+	}
+	/*
+	 * Call the breakpoint() routine in GDB to start the debugging
+	 * session
+	 */
+	printk(KERN_CRIT "Waiting for connection from remote gdb... ");
+	breakpoint();
+	printk("Connected.\n");
+}
+
+/*
+ * Sometimes we need to schedule a breakpoint because we can't break
+ * right where we are.
+ */
+static int kgdb_need_breakpoint[NR_CPUS];
+
+void kgdb_schedule_breakpoint(void)
+{
+	kgdb_need_breakpoint[smp_processor_id()] = 1;
+}
+
+void kgdb_process_breakpoint(void)
+{
+	/*
+	 * Handle a breakpoint queued from inside network driver code
+	  * to avoid reentrancy issues
+	 */
+	if (kgdb_need_breakpoint[smp_processor_id()]) {
+		 kgdb_need_breakpoint[smp_processor_id()] = 0;
+		 breakpoint();
+	}
+}
+
+#ifdef CONFIG_KGDB_CONSOLE
+char kgdbconbuf[BUFMAX];
+
+void kgdb_console_write(struct console *co, const char *s, unsigned count)
+{
+	int i;
+	int wcount;
+	char *bufptr;
+	unsigned long flags;
+
+	if (!kgdb_connected) {
+		return;
+	}
+	local_irq_save(flags);
+
+	kgdbconbuf[0] = 'O';
+	bufptr = kgdbconbuf + 1;
+	while (count > 0) {
+		if ((count << 1) > (BUFMAX - 2)) {
+			wcount = (BUFMAX - 2) >> 1;
+		} else {
+			wcount = count;
+		}
+		count -= wcount;
+		for (i = 0; i < wcount; i++) {
+			bufptr = pack_hex_byte(bufptr, s[i]);
+		}
+		*bufptr = '\0';
+		s += wcount;
+
+		put_packet(kgdbconbuf);
+
+	}
+	local_irq_restore(flags);
+}
+
+/* Always fail so that kgdb console doesn't become the default console */
+static int __init kgdb_console_setup(struct console *co, char *options)
+{
+	return -1;
+}
+
+static struct console kgdbcons = {
+	.name = "kgdb",
+	.write = kgdb_console_write,
+	.setup = kgdb_console_setup,
+	.flags = CON_PRINTBUFFER | CON_ENABLED,
+	.index = -1,
+};
+
+static int __init kgdb_console_init(void)
+{
+	register_console(&kgdbcons);
+	return 0;
+}
+
+console_initcall(kgdb_console_init);
+#endif
+
+EXPORT_SYMBOL(breakpoint);
+#ifdef CONFIG_KGDB_THREAD
+EXPORT_SYMBOL(kern_schedule);
+#endif
+
+static int __init opt_kgdb_enter(char *str)
+{
+	kgdb_enter = 1;
+	return 1;
+}
+
+static int __init opt_gdb(char *str)
+{
+	kgdb_enter = 1;
+	return 1;
+}
+
+/*
+ * These options have been deprecated and are present only to maintain
+ * compatibility with kgdb for 2.4 and earlier kernels.
+ */
+#ifdef CONFIG_KGDB_8250
+extern int kgdb8250_baud;
+extern int kgdb8250_ttyS;
+static int __init opt_gdbttyS(char *str)
+{
+	kgdb8250_ttyS = simple_strtoul(str, NULL, 10);
+	return 1;
+}
+static int __init opt_gdbbaud(char *str)
+{
+	kgdb8250_baud = simple_strtoul(str, NULL, 10);
+	return 1;
+}
+#endif
+
+/*
+ *
+ * Sequence of following lines has to be maintained because gdb option is a
+ * prefix of the other two options
+ */
+
+#ifdef CONFIG_KGDB_8250
+__setup("gdbttyS=", opt_gdbttyS);
+__setup("gdbbaud=", opt_gdbbaud);
+#endif
+__setup("gdb", opt_gdb);
+__setup("kgdbwait", opt_kgdb_enter);
Index: linux-2.6.4-rc2-bk3-kgdb/kernel/sched.c
===================================================================
--- linux-2.6.4-rc2-bk3-kgdb.orig/kernel/sched.c	2004-03-08 14:30:26.000000000 +0530
+++ linux-2.6.4-rc2-bk3-kgdb/kernel/sched.c	2004-03-08 14:31:42.000000000 +0530
@@ -37,6 +37,7 @@
 #include <linux/rcupdate.h>
 #include <linux/cpu.h>
 #include <linux/percpu.h>
+#include <linux/debugger.h>
 
 #ifdef CONFIG_NUMA
 #define cpu_to_node_mask(cpu) node_to_cpumask(cpu_to_node(cpu))
@@ -2961,6 +2962,8 @@
 #if defined(in_atomic)
 	static unsigned long prev_jiffy;	/* ratelimiting */
 
+	if (atomic_read(&debugger_active))
+		return;
 	if ((in_atomic() || irqs_disabled()) && system_running) {
 		if (time_before(jiffies, prev_jiffy + HZ) && prev_jiffy)
 			return;
Index: linux-2.6.4-rc2-bk3-kgdb/kernel/Kconfig.kgdb
===================================================================
--- linux-2.6.4-rc2-bk3-kgdb.orig/kernel/Kconfig.kgdb	2003-01-30 15:54:37.000000000 +0530
+++ linux-2.6.4-rc2-bk3-kgdb/kernel/Kconfig.kgdb	2004-03-08 14:31:42.000000000 +0530
@@ -0,0 +1,13 @@
+config KGDB
+	bool "KGDB: kernel debugging with remote gdb"
+	depends on DEBUG_KERNEL
+	select DEBUG_INFO
+	select FRAME_POINTER
+	help
+	  If you say Y here, it will be possible to remotely debug the
+	  kernel using gdb. This enlarges your kernel image disk size by
+	  several megabytes and requires a machine with more than 128 MB
+	  RAM to avoid excessive linking time. 
+	  Documentation of kernel debugger available at
+	  http://kgdb.sourceforge.net
+	  This is only useful for kernel hackers. If unsure, say N.
Index: linux-2.6.4-rc2-bk3-kgdb/Documentation/kgdb.txt
===================================================================
--- linux-2.6.4-rc2-bk3-kgdb.orig/Documentation/kgdb.txt	2003-01-30 15:54:37.000000000 +0530
+++ linux-2.6.4-rc2-bk3-kgdb/Documentation/kgdb.txt	2004-03-08 14:31:42.000000000 +0530
@@ -0,0 +1,49 @@
+KGDB Linux kernel source level debugger
+
+Amit S. Kale <amitkale@emsyssoft.com>
+Last updated March 2004.
+
+Introduction:
+kgdb is a source level debugger for linux kernel. It is used along with gdb to
+debug a linux kernel. Kernel developers can debug a kernel similar to
+application programs with the use of kgdb. It makes it possible to place
+breakpoints in kernel code, step through the code and observe variables.
+
+Two machines are required for using kgdb. One of these machines is a
+development machine and the other is a test machine. The machines are
+connected through a serial line, a null-modem cable which connects their
+serial ports. The kernel to be debugged runs on the test machine. gdb runs on
+the development machine. The serial line is used by gdb to communicate to the
+kernel being debugged.
+
+This version of kgdb is a lite version. It is available on i386 platform uses
+a serial line for communicating to gdb. Full kgdb containing more features and
+supporting more architecture is available along with plenty of documentation
+at http://kgdb.sourceforge.net/
+
+Compiling a kernel:
+Enable Kernel hacking -> Kernel Debugging -> KGDB: kernel debugging with
+remote gdb
+
+Only generic serial port (8250) is supported in the lite version. Configure
+8250 options.
+
+Booting the kernel:
+Kernel command line option "kgdbwait" makes kgdb wait for gdb connection
+during booting of a kernel. If you have configured simple serial port, the
+port number and speed can be overriden on command line by using option
+"kgdb8250=portnumber,speed", where port numbers are 0-3 for COM1 to COM4
+respectively and supported speeds are 9600, 19200, 38400, 57600, 115200.
+Example: kgdbwait kgdb8250=0,115200
+
+Connecting gdb:
+If you have used "kgdbwait", kgdb prints a message "Waiting for connection
+from remote gdb..." on the console and waits for connection from gdb. At this
+point you connect gdb to kgdb.
+Example: 
+   % gdb ./vmlinux
+   (gdb) set remotebaud 115200
+   (gdb) target remote /dev/ttyS0
+
+Once connected, you can debug a kernel the way you would debug an application
+program.

^ permalink raw reply	[flat|nested] 27+ messages in thread

* i386-lite [patch 2/3] [Re: kgdb for mainline kernel: core-lite [patch 1/3]]
  2004-03-09  9:29         ` Amit S. Kale
@ 2004-03-09  9:32           ` Amit S. Kale
  2004-03-09 15:06           ` kgdb for mainline kernel: core-lite [patch 1/3] Tom Rini
  1 sibling, 0 replies; 27+ messages in thread
From: Amit S. Kale @ 2004-03-09  9:32 UTC (permalink / raw)
  To: Andrew Morton; +Cc: linux-kernel, trini, george, pavel

i386 part with this email
-Amit

On Tuesday 09 Mar 2004 2:59 pm, Amit S. Kale wrote:
> I attempted it and found that it works better than my expectation! I am
> attaching revised core-lite.patch with this email and sending
> i386-lite.patch as a reply.

Index: linux-2.6.4-rc2-bk3-kgdb/arch/i386/Kconfig
===================================================================
--- linux-2.6.4-rc2-bk3-kgdb.orig/arch/i386/Kconfig	2004-03-08 
14:30:07.000000000 +0530
+++ linux-2.6.4-rc2-bk3-kgdb/arch/i386/Kconfig	2004-03-09 14:16:55.226362584 
+0530
@@ -1253,6 +1253,8 @@
 	  If you say Y here, various routines which may sleep will become very
 	  noisy if they are called with a spinlock held.	
 
+source "kernel/Kconfig.kgdb"
+
 config FRAME_POINTER
 	bool "Compile the kernel with frame pointers"
 	help
Index: linux-2.6.4-rc2-bk3-kgdb/arch/i386/kernel/Makefile
===================================================================
--- linux-2.6.4-rc2-bk3-kgdb.orig/arch/i386/kernel/Makefile	2004-03-08 
14:30:06.000000000 +0530
+++ linux-2.6.4-rc2-bk3-kgdb/arch/i386/kernel/Makefile	2004-03-09 
14:16:55.241360304 +0530
@@ -31,6 +31,7 @@
 obj-$(CONFIG_ACPI_SRAT) 	+= srat.o
 obj-$(CONFIG_HPET_TIMER) 	+= time_hpet.o
 obj-$(CONFIG_EFI) 		+= efi.o efi_stub.o
+obj-$(CONFIG_KGDB)		+= kgdb.o
 
 EXTRA_AFLAGS   := -traditional
 
Index: linux-2.6.4-rc2-bk3-kgdb/arch/i386/kernel/irq.c
===================================================================
--- linux-2.6.4-rc2-bk3-kgdb.orig/arch/i386/kernel/irq.c	2004-03-08 
14:30:06.000000000 +0530
+++ linux-2.6.4-rc2-bk3-kgdb/arch/i386/kernel/irq.c	2004-03-09 
14:16:55.242360152 +0530
@@ -34,6 +34,7 @@
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
 #include <linux/kallsyms.h>
+#include <linux/kgdb.h>
 
 #include <asm/atomic.h>
 #include <asm/io.h>
@@ -508,6 +509,8 @@
 
 	irq_exit();
 
+	kgdb_process_breakpoint();
+
 	return 1;
 }
 
Index: linux-2.6.4-rc2-bk3-kgdb/arch/i386/kernel/kgdb.c
===================================================================
--- linux-2.6.4-rc2-bk3-kgdb.orig/arch/i386/kernel/kgdb.c	2003-01-30 
15:54:37.000000000 +0530
+++ linux-2.6.4-rc2-bk3-kgdb/arch/i386/kernel/kgdb.c	2004-03-09 
14:19:34.200194888 +0530
@@ -0,0 +1,380 @@
+/*
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ */
+
+/*
+ * Copyright (C) 2000-2001 VERITAS Software Corporation.
+ */
+/*
+ *  Contributor:     Lake Stevens Instrument Division$
+ *  Written by:      Glenn Engel $
+ *  Updated by:	     Amit Kale<akale@veritas.com>
+ *  Modified for 386 by Jim Kingdon, Cygnus Support.
+ *  Origianl kgdb, compatibility with 2.1.xx kernel by David Grothe 
<dave@gcom.com>
+ */
+
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <asm/vm86.h>
+#include <asm/system.h>
+#include <asm/ptrace.h>		/* for linux pt_regs struct */
+#include <linux/kgdb.h>
+#ifdef CONFIG_GDB_CONSOLE
+#include <linux/console.h>
+#endif
+#include <linux/init.h>
+#include <linux/debugger.h>
+
+/* Put the error code here just in case the user cares.  */
+int gdb_i386errcode;
+/* Likewise, the vector number here (since GDB only gets the signal
+   number through the usual means, and that's not very specific).  */
+int gdb_i386vector = -1;
+
+#if KGDB_MAX_NO_CPUS != 8
+#error change the definition of slavecpulocks
+#endif
+
+void regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+{
+	gdb_regs[_EAX] = regs->eax;
+	gdb_regs[_EBX] = regs->ebx;
+	gdb_regs[_ECX] = regs->ecx;
+	gdb_regs[_EDX] = regs->edx;
+	gdb_regs[_ESI] = regs->esi;
+	gdb_regs[_EDI] = regs->edi;
+	gdb_regs[_EBP] = regs->ebp;
+	gdb_regs[_DS] = regs->xds;
+	gdb_regs[_ES] = regs->xes;
+	gdb_regs[_PS] = regs->eflags;
+	gdb_regs[_CS] = regs->xcs;
+	gdb_regs[_PC] = regs->eip;
+	gdb_regs[_ESP] = (int)(&regs->esp);
+	gdb_regs[_SS] = __KERNEL_DS;
+	gdb_regs[_FS] = 0xFFFF;
+	gdb_regs[_GS] = 0xFFFF;
+}
+
+/*
+ * Extracts ebp, esp and eip values understandable by gdb from the values
+ * saved by switch_to.
+ * thread.esp points to ebp. flags and ebp are pushed in switch_to hence esp
+ * prior to entering switch_to is 8 greater then the value that is saved.
+ * If switch_to changes, change following code appropriately.
+ */
+void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct 
*p)
+{
+	gdb_regs[_EAX] = 0;
+	gdb_regs[_EBX] = 0;
+	gdb_regs[_ECX] = 0;
+	gdb_regs[_EDX] = 0;
+	gdb_regs[_ESI] = 0;
+	gdb_regs[_EDI] = 0;
+	gdb_regs[_EBP] = *(unsigned long *)p->thread.esp;
+	gdb_regs[_DS] = __KERNEL_DS;
+	gdb_regs[_ES] = __KERNEL_DS;
+	gdb_regs[_PS] = 0;
+	gdb_regs[_CS] = __KERNEL_CS;
+	gdb_regs[_PC] = p->thread.eip;
+	gdb_regs[_ESP] = p->thread.esp + 8;
+	gdb_regs[_SS] = __KERNEL_DS;
+	gdb_regs[_FS] = 0xFFFF;
+	gdb_regs[_GS] = 0xFFFF;
+}
+
+void gdb_regs_to_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+{
+	regs->eax = gdb_regs[_EAX];
+	regs->ebx = gdb_regs[_EBX];
+	regs->ecx = gdb_regs[_ECX];
+	regs->edx = gdb_regs[_EDX];
+	regs->esi = gdb_regs[_ESI];
+	regs->edi = gdb_regs[_EDI];
+	regs->ebp = gdb_regs[_EBP];
+	regs->xds = gdb_regs[_DS];
+	regs->xes = gdb_regs[_ES];
+	regs->eflags = gdb_regs[_PS];
+	regs->xcs = gdb_regs[_CS];
+	regs->eip = gdb_regs[_PC];
+#if 0				/* can't change these */
+	regs->esp = gdb_regs[_ESP];
+	regs->xss = gdb_regs[_SS];
+	regs->fs = gdb_regs[_FS];
+	regs->gs = gdb_regs[_GS];
+#endif
+
+}
+
+struct hw_breakpoint {
+	unsigned enabled;
+	unsigned type;
+	unsigned len;
+	unsigned addr;
+} breakinfo[4] = { {
+enabled:0}, {
+enabled:0}, {
+enabled:0}, {
+enabled:0}};
+
+void kgdb_correct_hw_break(void)
+{
+	int breakno;
+	int correctit;
+	int breakbit;
+	unsigned dr7;
+
+	asm volatile ("movl %%db7, %0\n":"=r" (dr7)
+		      :);
+	do {
+		unsigned addr0, addr1, addr2, addr3;
+		asm volatile ("movl %%db0, %0\n"
+			      "movl %%db1, %1\n"
+			      "movl %%db2, %2\n"
+			      "movl %%db3, %3\n":"=r" (addr0), "=r"(addr1),
+			      "=r"(addr2), "=r"(addr3):);
+	} while (0);
+	correctit = 0;
+	for (breakno = 0; breakno < 3; breakno++) {
+		breakbit = 2 << (breakno << 1);
+		if (!(dr7 & breakbit) && breakinfo[breakno].enabled) {
+			correctit = 1;
+			dr7 |= breakbit;
+			dr7 &= ~(0xf0000 << (breakno << 2));
+			dr7 |= (((breakinfo[breakno].len << 2) |
+				 breakinfo[breakno].type) << 16) <<
+			    (breakno << 2);
+			switch (breakno) {
+			case 0:
+				asm volatile ("movl %0, %%dr0\n"::"r"
+					      (breakinfo[breakno].addr));
+				break;
+
+			case 1:
+				asm volatile ("movl %0, %%dr1\n"::"r"
+					      (breakinfo[breakno].addr));
+				break;
+
+			case 2:
+				asm volatile ("movl %0, %%dr2\n"::"r"
+					      (breakinfo[breakno].addr));
+				break;
+
+			case 3:
+				asm volatile ("movl %0, %%dr3\n"::"r"
+					      (breakinfo[breakno].addr));
+				break;
+			}
+		} else if ((dr7 & breakbit) && !breakinfo[breakno].enabled) {
+			correctit = 1;
+			dr7 &= ~breakbit;
+			dr7 &= ~(0xf0000 << (breakno << 2));
+		}
+	}
+	if (correctit) {
+		asm volatile ("movl %0, %%db7\n"::"r" (dr7));
+	}
+}
+
+int kgdb_remove_hw_break(unsigned long addr, int type)
+{
+	int i, idx = -1;
+	for (i = 0; i < 4; i++) {
+		if (breakinfo[i].addr == addr && breakinfo[i].enabled) {
+			idx = i;
+			break;
+		}
+	}
+	if (idx == -1)
+		return -1;
+
+	breakinfo[idx].enabled = 0;
+	return 0;
+}
+
+int kgdb_set_hw_break(unsigned long addr, int type)
+{
+	int i, idx = -1;
+	for (i = 0; i < 4; i++) {
+		if (!breakinfo[i].enabled) {
+			idx = i;
+			break;
+		}
+	}
+	if (idx == -1)
+		return -1;
+
+	breakinfo[idx].enabled = 1;
+	breakinfo[idx].type = type;
+	breakinfo[idx].len = 1;
+	breakinfo[idx].addr = addr;
+	return 0;
+}
+
+int remove_hw_break(unsigned breakno)
+{
+	if (!breakinfo[breakno].enabled) {
+		return -1;
+	}
+	breakinfo[breakno].enabled = 0;
+	return 0;
+}
+
+int set_hw_break(unsigned breakno, unsigned type, unsigned len, unsigned 
addr)
+{
+	if (breakinfo[breakno].enabled) {
+		return -1;
+	}
+	breakinfo[breakno].enabled = 1;
+	breakinfo[breakno].type = type;
+	breakinfo[breakno].len = len;
+	breakinfo[breakno].addr = addr;
+	return 0;
+}
+
+void kgdb_printexceptioninfo(int exceptionNo, int errorcode, char *buffer)
+{
+	unsigned dr6;
+	int i;
+	switch (exceptionNo) {
+	case 1:		/* debug exception */
+		break;
+	case 3:		/* breakpoint */
+		sprintf(buffer, "Software breakpoint");
+		return;
+	default:
+		sprintf(buffer, "Details not available");
+		return;
+	}
+	asm volatile ("movl %%db6, %0\n":"=r" (dr6)
+		      :);
+	if (dr6 & 0x4000) {
+		sprintf(buffer, "Single step");
+		return;
+	}
+	for (i = 0; i < 4; ++i) {
+		if (dr6 & (1 << i)) {
+			sprintf(buffer, "Hardware breakpoint %d", i);
+			return;
+		}
+	}
+	sprintf(buffer, "Unknown trap");
+	return;
+}
+
+void kgdb_disable_hw_debug(struct pt_regs *regs)
+{
+	/* Disable hardware debugging while we are in kgdb */
+	asm volatile ("movl %0,%%db7": /* no output */ :"r" (0));
+}
+
+void kgdb_post_master_code(struct pt_regs *regs, int eVector, int err_code)
+{
+	/* Master processor is completely in the debugger */
+	gdb_i386vector = eVector;
+	gdb_i386errcode = err_code;
+}
+
+int kgdb_arch_handle_exception(int exceptionVector, int signo,
+			       int err_code, char *remcom_in_buffer,
+			       char *remcom_out_buffer,
+			       struct pt_regs *linux_regs)
+{
+	long addr, length;
+	long breakno, breaktype;
+	char *ptr;
+	int newPC;
+	int dr6;
+
+	switch (remcom_in_buffer[0]) {
+	case 'c':
+	case 's':
+		if (kgdb_contthread && kgdb_contthread != current) {
+			strcpy(remcom_out_buffer, "E00");
+			break;
+		}
+
+		kgdb_contthread = NULL;
+
+		/* try to read optional parameter, pc unchanged if no parm */
+		ptr = &remcom_in_buffer[1];
+		if (kgdb_hex2long(&ptr, &addr)) {
+			linux_regs->eip = addr;
+		}
+		newPC = linux_regs->eip;
+
+		/* clear the trace bit */
+		linux_regs->eflags &= 0xfffffeff;
+
+		/* set the trace bit if we're stepping */
+		if (remcom_in_buffer[0] == 's') {
+			linux_regs->eflags |= 0x100;
+			debugger_step = 1;
+		}
+
+		asm volatile ("movl %%db6, %0\n":"=r" (dr6));
+		if (!(dr6 & 0x4000)) {
+			for (breakno = 0; breakno < 4; ++breakno) {
+				if (dr6 & (1 << breakno)) {
+					if (breakinfo[breakno].type == 0) {
+						/* Set restore flag */
+						linux_regs->eflags |= 0x10000;
+						break;
+					}
+				}
+			}
+		}
+		kgdb_correct_hw_break();
+		asm volatile ("movl %0, %%db6\n"::"r" (0));
+
+		return (0);
+
+	case 'Y':
+		ptr = &remcom_in_buffer[1];
+		kgdb_hex2long(&ptr, &breakno);
+		ptr++;
+		kgdb_hex2long(&ptr, &breaktype);
+		ptr++;
+		kgdb_hex2long(&ptr, &length);
+		ptr++;
+		kgdb_hex2long(&ptr, &addr);
+		if (set_hw_break(breakno & 0x3, breaktype & 0x3,
+				 length & 0x3, addr) == 0) {
+			strcpy(remcom_out_buffer, "OK");
+		} else {
+			strcpy(remcom_out_buffer, "ERROR");
+		}
+		break;
+
+		/* Remove hardware breakpoint */
+	case 'y':
+		ptr = &remcom_in_buffer[1];
+		kgdb_hex2long(&ptr, &breakno);
+		if (remove_hw_break(breakno & 0x3) == 0) {
+			strcpy(remcom_out_buffer, "OK");
+		} else {
+			strcpy(remcom_out_buffer, "ERROR");
+		}
+		break;
+
+	}			/* switch */
+	return -1;		/* this means that we do not want to exit from the handler */
+}
+
+struct kgdb_arch arch_kgdb_ops = {
+	.gdb_bpt_instr = {0xcc},
+	.flags = KGDB_HW_BREAKPOINT,
+};
Index: linux-2.6.4-rc2-bk3-kgdb/arch/i386/kernel/nmi.c
===================================================================
--- linux-2.6.4-rc2-bk3-kgdb.orig/arch/i386/kernel/nmi.c	2004-03-08 
14:30:06.000000000 +0530
+++ linux-2.6.4-rc2-bk3-kgdb/arch/i386/kernel/nmi.c	2004-03-09 
14:16:55.260357416 +0530
@@ -25,6 +25,7 @@
 #include <linux/module.h>
 #include <linux/nmi.h>
 #include <linux/sysdev.h>
+#include <linux/debugger.h>
 
 #include <asm/smp.h>
 #include <asm/mtrr.h>
@@ -420,14 +421,25 @@
 	int sum, cpu = smp_processor_id();
 
 	sum = irq_stat[cpu].apic_timer_irqs;
+	if (atomic_read(&debugger_active)) {
 
-	if (last_irq_sums[cpu] == sum) {
+		/*
+		 * The machine is in debugger, hold this cpu if already
+		 * not held.
+		 */
+		debugger_nmihook(cpu, regs);
+		alert_counter[cpu] = 0;
+
+	} else if (last_irq_sums[cpu] == sum) {
 		/*
 		 * Ayiee, looks like this CPU is stuck ...
 		 * wait a few IRQs (5 seconds) before doing the oops ...
 		 */
 		alert_counter[cpu]++;
 		if (alert_counter[cpu] == 5*nmi_hz) {
+
+			CHK_DEBUGGER(2,SIGSEGV,0,regs,)
+
 			spin_lock(&nmi_print_lock);
 			/*
 			 * We are in trouble anyway, lets at least try
Index: linux-2.6.4-rc2-bk3-kgdb/arch/i386/kernel/signal.c
===================================================================
--- linux-2.6.4-rc2-bk3-kgdb.orig/arch/i386/kernel/signal.c	2004-03-08 
14:30:06.000000000 +0530
+++ linux-2.6.4-rc2-bk3-kgdb/arch/i386/kernel/signal.c	2004-03-09 
14:16:55.274355288 +0530
@@ -580,7 +580,8 @@
 		 * have been cleared if the watchpoint triggered
 		 * inside the kernel.
 		 */
-		__asm__("movl %0,%%db7"	: : "r" (current->thread.debugreg[7]));
+		if (current->thread.debugreg[7])
+			__asm__("movl %0,%%db7"	: : "r" (current->thread.debugreg[7]));
 
 		/* Whee!  Actually deliver the signal.  */
 		handle_signal(signr, &info, oldset, regs);
Index: linux-2.6.4-rc2-bk3-kgdb/arch/i386/kernel/traps.c
===================================================================
--- linux-2.6.4-rc2-bk3-kgdb.orig/arch/i386/kernel/traps.c	2004-03-08 
14:30:06.000000000 +0530
+++ linux-2.6.4-rc2-bk3-kgdb/arch/i386/kernel/traps.c	2004-03-09 
14:16:55.275355136 +0530
@@ -51,6 +51,7 @@
 
 #include <linux/irq.h>
 #include <linux/module.h>
+#include <linux/debugger.h>
 
 #include "mach_traps.h"
 
@@ -256,6 +257,7 @@
 {
 	static int die_counter;
 
+	CHK_DEBUGGER(1,SIGTRAP,err,regs,)
 	console_verbose();
 	spin_lock_irq(&die_lock);
 	bust_spinlocks(1);
@@ -330,6 +332,7 @@
 #define DO_ERROR(trapnr, signr, str, name) \
 asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
 { \
+	CHK_DEBUGGER(trapnr,signr,error_code,regs,)\
 	do_trap(trapnr, signr, str, 0, regs, error_code, NULL); \
 }
 
@@ -347,7 +350,10 @@
 #define DO_VM86_ERROR(trapnr, signr, str, name) \
 asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
 { \
+	CHK_DEBUGGER(trapnr,signr,error_code,regs,goto skip_trap)\
 	do_trap(trapnr, signr, str, 1, regs, error_code, NULL); \
+skip_trap: \
+	return; \
 }
 
 #define DO_VM86_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \
@@ -547,7 +553,7 @@
 	tsk->thread.debugreg[6] = condition;
 
 	/* Mask out spurious TF errors due to lazy TF clearing */
-	if (condition & DR_STEP) {
+	if (condition & DR_STEP && !debugger_step) {
 		/*
 		 * The TF error should be masked out only if the current
 		 * process is not traced and if the TRAP flag has been set
@@ -570,11 +576,13 @@
 	info.si_errno = 0;
 	info.si_code = TRAP_BRKPT;
 	
-	/* If this is a kernel mode trap, save the user PC on entry to 
-	 * the kernel, that's what the debugger can make sense of.
-	 */
-	info.si_addr = ((regs->xcs & 3) == 0) ? (void *)tsk->thread.eip : 
-	                                        (void *)regs->eip;
+
+	/* If this is a kernel mode trap, we need to reset db7 to allow us
+	 * to continue sanely */
+	if ((regs->xcs & 3) == 0)
+		goto clear_dr7;
+
+	info.si_addr = (void *)regs->eip;
 	force_sig_info(SIGTRAP, &info, tsk);
 
 	/* Disable additional traps. They'll be re-enabled when
@@ -584,6 +592,7 @@
 	__asm__("movl %0,%%db7"
 		: /* no output */
 		: "r" (0));
+	CHK_DEBUGGER(1,SIGTRAP,error_code,regs,)
 	return;
 
 debug_vm86:
Index: linux-2.6.4-rc2-bk3-kgdb/arch/i386/mm/fault.c
===================================================================
--- linux-2.6.4-rc2-bk3-kgdb.orig/arch/i386/mm/fault.c	2004-03-08 
14:30:06.000000000 +0530
+++ linux-2.6.4-rc2-bk3-kgdb/arch/i386/mm/fault.c	2004-03-09 
14:16:55.284353768 +0530
@@ -2,6 +2,11 @@
  *  linux/arch/i386/mm/fault.c
  *
  *  Copyright (C) 1995  Linus Torvalds
+ *
+ *  Change History
+ *
+ *	Tigran Aivazian <tigran@sco.com>	Remote debugging support.
+ *
  */
 
 #include <linux/signal.h>
@@ -21,6 +26,7 @@
 #include <linux/vt_kern.h>		/* For unblank_screen() */
 #include <linux/highmem.h>
 #include <linux/module.h>
+#include <linux/debugger.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -399,6 +405,8 @@
  	if (is_prefetch(regs, address))
  		return;
 
+	CHK_DEBUGGER(14, SIGSEGV,error_code, regs,)
+
 /*
  * Oops. The kernel tried to access some bad page. We'll have to
  * terminate things with extreme prejudice.
@@ -406,6 +414,7 @@
 
 	bust_spinlocks(1);
 
+
 	if (address < PAGE_SIZE)
 		printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
 	else
Index: linux-2.6.4-rc2-bk3-kgdb/include/asm-i386/kgdb.h
===================================================================
--- linux-2.6.4-rc2-bk3-kgdb.orig/include/asm-i386/kgdb.h	2003-01-30 
15:54:37.000000000 +0530
+++ linux-2.6.4-rc2-bk3-kgdb/include/asm-i386/kgdb.h	2004-03-09 
14:16:55.284353768 +0530
@@ -0,0 +1,49 @@
+#ifndef _ASM_KGDB_H_
+#define _ASM_KGDB_H_
+
+/*
+ * Copyright (C) 2001-2004 Amit S. Kale
+ */
+
+#include <linux/ptrace.h>
+
+/* gdb locks */
+#define KGDB_MAX_NO_CPUS 8
+
+/************************************************************************/
+/* BUFMAX defines the maximum number of characters in inbound/outbound 
buffers*/
+/* at least NUMREGBYTES*2 are needed for register packets */
+/* Longer buffer is needed to list all threads */
+#define BUFMAX 1024
+
+/* Number of bytes of registers.  */
+#define NUMREGBYTES 64
+/*
+ *  Note that this register image is in a different order than
+ *  the register image that Linux produces at interrupt time.
+ *  
+ *  Linux's register image is defined by struct pt_regs in ptrace.h.
+ *  Just why GDB uses a different order is a historical mystery.
+ */
+enum regnames { _EAX,		/* 0 */
+	_ECX,			/* 1 */
+	_EDX,			/* 2 */
+	_EBX,			/* 3 */
+	_ESP,			/* 4 */
+	_EBP,			/* 5 */
+	_ESI,			/* 6 */
+	_EDI,			/* 7 */
+	_PC,			/* 8 also known as eip */
+	_PS,			/* 9 also known as eflags */
+	_CS,			/* 10 */
+	_SS,			/* 11 */
+	_DS,			/* 12 */
+	_ES,			/* 13 */
+	_FS,			/* 14 */
+	_GS			/* 15 */
+};
+
+#define BREAKPOINT() asm("   int $3");
+#define BREAK_INSTR_SIZE       1
+
+#endif				/* _ASM_KGDB_H_ */
Index: linux-2.6.4-rc2-bk3-kgdb/include/asm-i386/processor.h
===================================================================
--- linux-2.6.4-rc2-bk3-kgdb.orig/include/asm-i386/processor.h	2004-03-08 
14:30:19.000000000 +0530
+++ linux-2.6.4-rc2-bk3-kgdb/include/asm-i386/processor.h	2004-03-09 
14:16:55.290352856 +0530
@@ -425,6 +425,8 @@
 	unsigned int		saved_fs, saved_gs;
 /* IO permissions */
 	unsigned long	*io_bitmap_ptr;
+	void *		debuggerinfo;
+
 };
 
 #define INIT_THREAD  {							\
Index: linux-2.6.4-rc2-bk3-kgdb/include/asm-i386/system.h
===================================================================
--- linux-2.6.4-rc2-bk3-kgdb.orig/include/asm-i386/system.h	2004-03-08 
14:30:19.000000000 +0530
+++ linux-2.6.4-rc2-bk3-kgdb/include/asm-i386/system.h	2004-03-09 
14:16:55.297351792 +0530
@@ -12,6 +12,8 @@
 struct task_struct;	/* one of the stranger aspects of C forward 
declarations.. */
 extern struct task_struct * FASTCALL(__switch_to(struct task_struct *prev, 
struct task_struct *next));
 
+/* sleeping_thread_to_gdb_regs depends on this code. Correct it if you change
+ * any of the following */
 #define switch_to(prev,next,last) do {					\
 	unsigned long esi,edi;						\
 	asm volatile("pushfl\n\t"					\


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: kgdb for mainline kernel: core-lite [patch 1/3]
  2004-03-09  9:29         ` Amit S. Kale
  2004-03-09  9:32           ` i386-lite [patch 2/3] [Re: kgdb for mainline kernel: core-lite [patch 1/3]] Amit S. Kale
@ 2004-03-09 15:06           ` Tom Rini
  2004-03-10  4:05             ` Amit S. Kale
  1 sibling, 1 reply; 27+ messages in thread
From: Tom Rini @ 2004-03-09 15:06 UTC (permalink / raw)
  To: Amit S. Kale; +Cc: Andrew Morton, linux-kernel, george, pavel

On Tue, Mar 09, 2004 at 02:59:54PM +0530, Amit S. Kale wrote:
[snip]
> I attempted it and found that it works better than my expectation! I am 
> attaching revised core-lite.patch with this email and sending i386-lite.patch 
> as a reply.
[snip]
> Index: linux-2.6.4-rc2-bk3-kgdb/include/linux/kgdb.h
[snip]
> +#ifndef KGDB_MAX_NO_CPUS
> +#if CONFIG_NR_CPUS > 8
> +#error KGDB can handle max 8 CPUs
> +#endif
> +#define KGDB_MAX_NO_CPUS 8
> +#endif

We need to remove all of that in favor of s/KGDB_MAX_NO_CPUS/NR_CPUS/g,
and remove the check on 8.

-- 
Tom Rini
http://gate.crashing.org/~trini/

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: kgdb for mainline kernel: core-lite [patch 1/3]
  2004-03-09  5:08                 ` Amit S. Kale
@ 2004-03-09 15:37                   ` Tom Rini
  0 siblings, 0 replies; 27+ messages in thread
From: Tom Rini @ 2004-03-09 15:37 UTC (permalink / raw)
  To: Amit S. Kale; +Cc: George Anzinger, Andrew Morton, linux-kernel, pavel

On Tue, Mar 09, 2004 at 10:38:55AM +0530, Amit S. Kale wrote:
> On Tuesday 09 Mar 2004 3:49 am, George Anzinger wrote:
[snip]
> > You really do need a gdb that handles the dwarft2 frames.  This is a rather
> > new gdb (I use the CVS version).
> 
> Let's just stick to gdb 6.0 and binutils 2.14. CVS versions of gdb and 
> binutils are too risky for someone who is trying to learn linux kernel by 
> using kgdb.

I think that depends on the level of crap we have to do compared to how
it would be done with a newer version of gdb or binutils.  GDB 6.1 for
example should be out soon.

-- 
Tom Rini
http://gate.crashing.org/~trini/

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: kgdb for mainline kernel: core-lite [patch 1/3]
  2004-03-09 15:06           ` kgdb for mainline kernel: core-lite [patch 1/3] Tom Rini
@ 2004-03-10  4:05             ` Amit S. Kale
  0 siblings, 0 replies; 27+ messages in thread
From: Amit S. Kale @ 2004-03-10  4:05 UTC (permalink / raw)
  To: Tom Rini; +Cc: Andrew Morton, linux-kernel, george, pavel

On Tuesday 09 Mar 2004 8:36 pm, Tom Rini wrote:
> On Tue, Mar 09, 2004 at 02:59:54PM +0530, Amit S. Kale wrote:
> [snip]
>
> > I attempted it and found that it works better than my expectation! I am
> > attaching revised core-lite.patch with this email and sending
> > i386-lite.patch as a reply.
>
> [snip]
>
> > Index: linux-2.6.4-rc2-bk3-kgdb/include/linux/kgdb.h
>
> [snip]
>
> > +#ifndef KGDB_MAX_NO_CPUS
> > +#if CONFIG_NR_CPUS > 8
> > +#error KGDB can handle max 8 CPUs
> > +#endif
> > +#define KGDB_MAX_NO_CPUS 8
> > +#endif
>
> We need to remove all of that in favor of s/KGDB_MAX_NO_CPUS/NR_CPUS/g,
> and remove the check on 8.

Yes. I'll do that.
-Amit



^ permalink raw reply	[flat|nested] 27+ messages in thread

end of thread, other threads:[~2004-03-10  4:07 UTC | newest]

Thread overview: 27+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2004-03-08  9:39 kgdb for mainline kernel: core-lite [patch 1/3] Amit S. Kale
2004-03-08  9:54 ` Andrew Morton
2004-03-08 10:15   ` Amit S. Kale
2004-03-08 10:26     ` Andrew Morton
2004-03-08 10:49       ` Amit S. Kale
2004-03-08 11:07         ` Andrew Morton
2004-03-08 11:20           ` Amit S. Kale
2004-03-08 11:44             ` Amit S. Kale
2004-03-08 11:54               ` Andrew Morton
2004-03-08 12:00                 ` Amit S. Kale
2004-03-08 15:19               ` Tom Rini
2004-03-08 22:26                 ` George Anzinger
2004-03-09  8:58                 ` Amit S. Kale
2004-03-08 22:19               ` George Anzinger
2004-03-09  5:08                 ` Amit S. Kale
2004-03-09 15:37                   ` Tom Rini
2004-03-08 11:48             ` Andrew Morton
2004-03-08 22:21               ` George Anzinger
2004-03-08 15:22             ` Tom Rini
2004-03-08 16:32               ` Amit S. Kale
2004-03-08 22:29               ` George Anzinger
2004-03-08 22:15         ` George Anzinger
2004-03-09  4:46           ` Amit S. Kale
2004-03-09  9:29         ` Amit S. Kale
2004-03-09  9:32           ` i386-lite [patch 2/3] [Re: kgdb for mainline kernel: core-lite [patch 1/3]] Amit S. Kale
2004-03-09 15:06           ` kgdb for mainline kernel: core-lite [patch 1/3] Tom Rini
2004-03-10  4:05             ` Amit S. Kale

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox