kgdb
--- diff/Documentation/Configure.help	2002-11-05 12:12:09.000000000 +0000
+++ source/Documentation/Configure.help	2002-11-05 15:20:24.000000000 +0000
@@ -19615,6 +19615,39 @@
   If you have a Western Digital WD93 SCSI controller on
   an SGI MIPS system, say Y.  Otherwise, say N.
 
+KGDB: Remote (serial) kernel debugging with gdb
+CONFIG_X86_REMOTE_DEBUG
+  If you say Y here, it will be possible to remotely debug the x86
+  kernel using gdb. This enlarges your kernel image disk size by
+  several megabytes and requires a machine with more than 16 MB,
+  better 32 MB RAM to avoid excessive linking time. 
+  To use this feature you need to perform some basic setup described
+  briefly in Documentation/i386/gdb-serial.txt.
+  This is only useful for kernel hackers. If unsure, say N.
+
+KGDB: Thread analysis
+CONFIG_KGDB_THREAD
+  With thread analysis enabled, gdb can talk to kgdb stub to list
+  threads and to get stack trace for a thread. This option also enables
+  some code which helps gdb get exact status of thread. Thread analysis
+  adds some overhead to schedule and down functions. You can disable this
+  option if you do not want to compromise on speed.
+
+KGDB: Console messagegs through gdb
+CONFIG_GDB_CONSOLE
+  If you say Y here, console messages will appear through gdb.
+  Other consoles such as tty or ttyS will continue to work as usual.
+  
+KGDB: Enable kernel asserts
+CONFIG_KERNEL_ASSERTS
+  This option enables kernel asserts. A kernel assert is a condition,
+  which if turnes out to be false during an execution path, then kgdb
+  is called. Kernel assertions help in modifying the kernel or writing
+  drivers. Bugs can be traced sooner with kernel asserts because invalid
+  conditions caused by bugs are checked at various places. Kernel asserts
+  add the overhead of checking asserted conditions. You can disable this
+  option if you do not want the overhead.
+
 Magic System Request Key support
 CONFIG_MAGIC_SYSRQ
   If you say Y here, you will have some control over the system even
--- diff/Makefile	2002-08-05 14:57:25.000000000 +0100
+++ source/Makefile	2002-11-05 15:21:31.000000000 +0000
@@ -90,9 +90,12 @@
 
 CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes -Wno-trigraphs -O2 \
 	  -fno-strict-aliasing -fno-common
-ifndef CONFIG_FRAME_POINTER
+ifeq ($(CONFIG_X86_REMOTE_DEBUG),y)
+CFLAGS += -g
+else
 CFLAGS += -fomit-frame-pointer
 endif
+
 AFLAGS := -D__ASSEMBLY__ $(CPPFLAGS)
 
 #
--- diff/arch/i386/Makefile	2001-04-30 08:17:39.000000000 +0100
+++ source/arch/i386/Makefile	2002-11-05 15:20:24.000000000 +0000
@@ -19,7 +19,7 @@
 LD=$(CROSS_COMPILE)ld -m elf_i386
 OBJCOPY=$(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S
 LDFLAGS=-e stext
-LINKFLAGS =-T $(TOPDIR)/arch/i386/vmlinux.lds $(LDFLAGS)
+LINKFLAGS =-T $(TOPDIR)/arch/i386/vmlinux.lds $(LDFLAGS) --warn-common
 
 CFLAGS += -pipe
 
@@ -105,6 +105,11 @@
 	$(MAKE) linuxsubdirs SUBDIRS=arch/i386/mm
 
 MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
+ifeq ($(CONFIG_X86_REMOTE_DEBUG),y)
+CLEANKERNEL = $(MAKE) -C arch/$(ARCH)/kernel kernelclean
+else
+CLEANKERNEL =
+endif
 
 vmlinux: arch/i386/vmlinux.lds
 
@@ -140,6 +145,7 @@
 
 archclean:
 	@$(MAKEBOOT) clean
+	@$(CLEANKERNEL)
 
 archmrproper:
 
--- diff/arch/i386/config.in	2002-08-05 14:57:26.000000000 +0100
+++ source/arch/i386/config.in	2002-11-05 15:20:24.000000000 +0000
@@ -424,5 +424,10 @@
    bool '  Spinlock debugging' CONFIG_DEBUG_SPINLOCK
    bool '  Compile the kernel with frame pointers' CONFIG_FRAME_POINTER
 fi
-
+bool 'KGDB: Remote (serial) kernel debugging with gdb' CONFIG_X86_REMOTE_DEBUG
+if [ "$CONFIG_X86_REMOTE_DEBUG" != "n" ]; then
+   bool 'KGDB: Thread analysis' CONFIG_KGDB_THREAD
+   bool 'KGDB: Console messages through gdb' CONFIG_GDB_CONSOLE
+   bool 'KGDB: Enable kernel asserts' CONFIG_KERNEL_ASSERTS
+fi
 endmenu
--- diff/arch/i386/kernel/Makefile	2002-01-17 10:07:51.000000000 +0000
+++ source/arch/i386/kernel/Makefile	2002-11-05 15:29:41.000000000 +0000
@@ -31,6 +31,7 @@
 endif
 
 obj-$(CONFIG_MCA)		+= mca.o
+obj-$(CONFIG_X86_REMOTE_DEBUG)	+= gdbstub.o
 obj-$(CONFIG_MTRR)		+= mtrr.o
 obj-$(CONFIG_X86_MSR)		+= msr.o
 obj-$(CONFIG_X86_CPUID)		+= cpuid.o
@@ -41,4 +42,6 @@
 obj-$(CONFIG_X86_IO_APIC)	+= io_apic.o acpitable.o
 obj-$(CONFIG_X86_VISWS_APIC)	+= visws_apic.o
 
+kernelclean:	dummy
+
 include $(TOPDIR)/Rules.make
--- diff/arch/i386/kernel/entry.S	2002-08-05 14:57:26.000000000 +0100
+++ source/arch/i386/kernel/entry.S	2002-11-05 15:20:24.000000000 +0000
@@ -256,7 +256,7 @@
 
 	ALIGN
 reschedule:
-	call SYMBOL_NAME(schedule)    # test
+	call SYMBOL_NAME(user_schedule)    # test
 	jmp ret_from_sys_call
 
 ENTRY(divide_error)
@@ -394,6 +394,31 @@
 	pushl $ SYMBOL_NAME(do_spurious_interrupt_bug)
 	jmp error_code
 
+#ifdef CONFIG_KGDB_THREAD
+ENTRY(kern_schedule)
+	pushl	%ebp
+	movl	%esp, %ebp
+	pushl	%ss		
+	pushl	%ebp
+	pushfl
+	pushl	%cs
+	pushl	4(%ebp)
+	pushl	%eax		
+	pushl	%es
+	pushl	%ds
+	pushl	%eax
+	pushl	(%ebp)
+	pushl	%edi
+	pushl	%esi
+	pushl	%edx
+	pushl	%ecx
+	pushl	%ebx
+	call	kern_do_schedule
+	movl	%ebp, %esp
+	pop	%ebp
+	ret
+#endif
+
 .data
 ENTRY(sys_call_table)
 	.long SYMBOL_NAME(sys_ni_syscall)	/* 0  -  old "setup()" system call*/
--- diff/arch/i386/kernel/nmi.c	2002-08-05 14:57:26.000000000 +0100
+++ source/arch/i386/kernel/nmi.c	2002-11-05 15:20:24.000000000 +0000
@@ -25,6 +25,20 @@
 #include <asm/mtrr.h>
 #include <asm/mpspec.h>
 
+#ifdef CONFIG_X86_REMOTE_DEBUG
+extern gdb_debug_hook * linux_debug_hook;
+#define	CHK_REMOTE_DEBUG(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;							\
+	}								\
+    }
+#else
+#define	CHK_REMOTE_DEBUG(trapnr,signr,error_code,regs,after)	
+#endif
+
 unsigned int nmi_watchdog = NMI_NONE;
 static unsigned int nmi_hz = HZ;
 unsigned int nmi_perfctr_msr;	/* the MSR to reset in NMI handler */
@@ -346,12 +360,59 @@
 	sum = apic_timer_irqs[cpu];
 
 	if (last_irq_sums[cpu] == sum) {
+#ifdef CONFIG_X86_REMOTE_DEBUG
+#ifdef CONFIG_SMP
+		if (spin_is_locked(&kgdb_spinlock))
+#else
+		if (kgdb_spinlock) 
+#endif
+		{
+			/* We are inside kgdb, this isn't a stuck cpu */
+			alert_counter[cpu] = 0;
+		} else {
+#ifdef CONFIG_SMP
+			if (spin_is_locked(&kgdb_nmispinlock))
+#else
+			if (kgdb_nmispinlock) 
+#endif
+			{
+				if (!procindebug[cpu]) {
+					procindebug[cpu] = 1;
+					current->thread.kgdbregs = regs;
+					while (1) {
+						/* nothing */
+					}
+				}
+				return;
+			}
+		}
+#endif
 		/*
 		 * 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) {
+#ifdef CONFIG_X86_REMOTE_DEBUG
+#ifdef CONFIG_SMP
+			if (spin_trylock(&kgdb_nmispinlock))
+#else
+			kgdb_nmispinlock = 1;
+#endif
+			{
+				procindebug[cpu] = 1;
+				CHK_REMOTE_DEBUG(2,SIGSEGV,0,regs,)
+			} 
+#ifdef CONFIG_SMP
+			else {
+				procindebug[cpu] = 1;
+				current->thread.kgdbregs = regs;
+				while (1) {
+					/* nothing */
+				}
+			}
+#endif
+#endif
 			spin_lock(&nmi_print_lock);
 			/*
 			 * We are in trouble anyway, lets at least try
--- diff/arch/i386/kernel/smp.c	2002-08-05 14:57:26.000000000 +0100
+++ source/arch/i386/kernel/smp.c	2002-11-05 15:20:24.000000000 +0000
@@ -603,9 +603,9 @@
 	ack_APIC_irq();
 }
 
-asmlinkage void smp_call_function_interrupt(void)
+asmlinkage void smp_call_function_interrupt(struct pt_regs regs)
 {
-	void (*func) (void *info) = call_data->func;
+	void (*func) (void *info, struct pt_regs *) = (void (*)(void *, struct pt_regs*))call_data->func;
 	void *info = call_data->info;
 	int wait = call_data->wait;
 
@@ -619,7 +619,7 @@
 	/*
 	 * At this point the info structure may be out of scope unless wait==1
 	 */
-	(*func)(info);
+	(*func)(info, &regs);
 	if (wait) {
 		mb();
 		atomic_inc(&call_data->finished);
--- diff/arch/i386/kernel/traps.c	2002-08-05 14:57:26.000000000 +0100
+++ source/arch/i386/kernel/traps.c	2002-11-05 15:20:24.000000000 +0000
@@ -50,6 +50,24 @@
 #include <linux/irq.h>
 #include <linux/module.h>
 
+#ifdef CONFIG_X86_REMOTE_DEBUG
+#include <linux/gdb.h>
+#endif
+
+#ifdef CONFIG_X86_REMOTE_DEBUG
+gdb_debug_hook * linux_debug_hook;
+#define	CHK_REMOTE_DEBUG(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;							\
+	}								\
+    }
+#else
+#define	CHK_REMOTE_DEBUG(trapnr,signr,error_code,regs,after)	
+#endif
+ 
 asmlinkage int system_call(void);
 asmlinkage void lcall7(void);
 asmlinkage void lcall27(void);
@@ -281,6 +299,7 @@
 	bust_spinlocks(1);
 	handle_BUG(regs);
 	printk("%s: %04lx\n", str, err & 0xffff);
+	CHK_REMOTE_DEBUG(1,SIGTRAP,err,regs,)
 	show_registers(regs);
 	bust_spinlocks(0);
 	spin_unlock_irq(&die_lock);
@@ -340,6 +359,7 @@
 #define DO_ERROR(trapnr, signr, str, name) \
 asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
 { \
+	CHK_REMOTE_DEBUG(trapnr,signr,error_code,regs,)\
 	do_trap(trapnr, signr, str, 0, regs, error_code, NULL); \
 }
 
@@ -357,7 +377,10 @@
 #define DO_VM86_ERROR(trapnr, signr, str, name) \
 asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
 { \
+	CHK_REMOTE_DEBUG(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) \
@@ -409,6 +432,7 @@
 			regs->eip = fixup;
 			return;
 		}
+		CHK_REMOTE_DEBUG(13,SIGSEGV,error_code,regs,)
 		die("general protection fault", regs, error_code);
 	}
 }
@@ -541,8 +565,10 @@
 		 * allowing programs to debug themselves without the ptrace()
 		 * interface.
 		 */
+#ifndef CONFIG_X86_REMOTE_DEBUG
 		if ((regs->xcs & 3) == 0)
 			goto clear_TF;
+#endif
 		if ((tsk->ptrace & (PT_DTRACE|PT_PTRACED)) == PT_DTRACE)
 			goto clear_TF;
 	}
@@ -554,11 +580,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
@@ -568,6 +596,7 @@
 	__asm__("movl %0,%%db7"
 		: /* no output */
 		: "r" (0));
+	CHK_REMOTE_DEBUG(1,SIGTRAP,error_code,regs,)
 	return;
 
 debug_vm86:
--- diff/arch/i386/mm/fault.c	2002-08-05 14:57:26.000000000 +0100
+++ source/arch/i386/mm/fault.c	2002-11-05 15:20:24.000000000 +0000
@@ -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>
@@ -19,6 +24,9 @@
 #include <linux/init.h>
 #include <linux/tty.h>
 #include <linux/vt_kern.h>		/* For unblank_screen() */
+#ifdef CONFIG_X86_REMOTE_DEBUG
+#include <linux/gdb.h>
+#endif
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -184,6 +192,15 @@
 	if (in_interrupt() || !mm)
 		goto no_context;
 
+#ifdef CONFIG_X86_REMOTE_DEBUG
+	if (kgdb_memerr_expected) {
+		if (linux_debug_hook != (gdb_debug_hook *) NULL) {
+			(*linux_debug_hook)(14, SIGSEGV, error_code, regs) ;
+			return;            /* return w/modified regs */
+		}
+	}
+#endif
+
 	down_read(&mm->mmap_sem);
 
 	vma = find_vma(mm, address);
@@ -302,6 +319,19 @@
 		return;
 	}
 
+#ifdef CONFIG_X86_REMOTE_DEBUG
+	if (kgdb_memerr_expected) {
+		if (linux_debug_hook != (gdb_debug_hook *) NULL) {
+			(*linux_debug_hook)(14, SIGSEGV, error_code, regs);
+			return; /* Return with modified registers */
+		}
+	} else {
+		if (linux_debug_hook != (gdb_debug_hook *) NULL) {
+			(*linux_debug_hook)(14, SIGSEGV, error_code, regs);
+		}
+	}
+#endif
+
 /*
  * Oops. The kernel tried to access some bad page. We'll have to
  * terminate things with extreme prejudice.
--- diff/drivers/char/Makefile	2002-08-05 14:57:30.000000000 +0100
+++ source/drivers/char/Makefile	2002-11-05 15:20:24.000000000 +0000
@@ -136,6 +136,7 @@
   KEYBD = dummy_keyb.o
 endif
 
+obj-$(CONFIG_X86_REMOTE_DEBUG) += gdbserial.o
 obj-$(CONFIG_VT) += vt.o vc_screen.o consolemap.o consolemap_deftbl.o $(CONSOLE) selection.o
 obj-$(CONFIG_SERIAL) += $(SERIAL)
 obj-$(CONFIG_SERIAL_HCDP) += hcdp_serial.o
--- diff/drivers/char/serial.c	2002-08-05 14:57:30.000000000 +0100
+++ source/drivers/char/serial.c	2002-11-05 15:33:39.000000000 +0000
@@ -4,6 +4,7 @@
  *  Copyright (C) 1991, 1992  Linus Torvalds
  *  Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 
  * 		1998, 1999  Theodore Ts'o
+ *  Copyright (C) 2000 VERITAS Software Corporation.
  *
  *  Extensively rewritten by Theodore Ts'o, 8/16/92 -- 9/14/92.  Now
  *  much more extensible to support other serial cards based on the
@@ -34,6 +35,10 @@
  *  4/98: Added changes to support the ARM architecture proposed by
  * 	  Russell King
  *
+ *  3/99: Added TIOCGDB for remote debugging with gdb if compiled with
+ *        CONFIG_X86_REMOTE_DEBUG
+ * 	  Tigran Aivazian
+ *
  *  5/99: Updated to include support for the XR16C850 and ST16C654
  *        uarts.  Stuart MacDonald <stuartm@connecttech.com>
  *
@@ -210,7 +215,7 @@
 #include <asm/uaccess.h>
 #endif
 #include <linux/delay.h>
-#ifdef CONFIG_SERIAL_CONSOLE
+#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_GDB_CONSOLE)
 #include <linux/console.h>
 #endif
 #ifdef ENABLE_SERIAL_PCI
@@ -1581,6 +1586,13 @@
 	restore_flags(flags);
 }
 
+#ifdef CONFIG_X86_REMOTE_DEBUG
+void shutdown_for_gdb(struct async_struct * info)
+{
+    shutdown(info) ;
+}
+#endif
+
 #if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
 static int baud_table[] = {
 	0, 50, 75, 110, 134, 150, 200, 300,
@@ -2692,6 +2704,12 @@
 			printk ("TIOCSER?WILD ioctl obsolete, ignored.\n");
 			return 0;
 
+#ifdef CONFIG_X86_REMOTE_DEBUG
+		case TIOCGDB:
+			gdb_ttyS = MINOR(tty->device) & 0x03F ;
+			gdb_baud = tty_get_baud_rate(tty) ;
+			return gdb_hook();
+#endif
 		default:
 			return -ENOIOCTLCMD;
 		}
@@ -4936,12 +4954,17 @@
  *
  * Accept a maximum of eight boards
  *
+ * 10/00: added console support for kgdb. Amit Kale <akale@veritas.com>
+ *
  */
 static void __devinit probe_serial_pci(void) 
 {
 #ifdef SERIAL_DEBUG_PCI
 	printk(KERN_DEBUG "Entered probe_serial_pci()\n");
 #endif
+#ifdef CONFIG_X86_REMOTE_DEBUG
+#include <linux/gdb.h>
+#endif
 
 	/* Register call PCI serial devices.  Null out
 	 * the driver name upon failure, as a signal
@@ -6010,6 +6033,135 @@
 #endif
 
 /*
+ * ------------------------------------------------------------
+ * Serial GDB driver (most in gdbserial.c)
+ * ------------------------------------------------------------
+ */
+
+#ifdef CONFIG_X86_REMOTE_DEBUG
+#ifdef CONFIG_GDB_CONSOLE
+static struct console gdbcons = {
+	"gdb",
+	gdb_console_write,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	CON_PRINTBUFFER | CON_ENABLED,
+	-1,
+	0,
+	NULL
+};
+#endif
+
+
+/* 
+ *  Takes:
+ *	ttyS - integer specifying which serial port to use for debugging
+ *	baud - baud rate of specified serial port
+ *  Returns:
+ *	port for use by the gdb serial driver
+ */
+struct serial_state *
+gdb_serial_setup(int ttyS, int baud)
+{
+        struct serial_state *ser;
+        unsigned cval;
+        int     bits = 8;
+        int     parity = 'n';
+        int     cflag = CREAD | HUPCL | CLOCAL;
+        int     quot = 0;
+
+        /*
+         *      Now construct a cflag setting.
+         */
+        switch(baud) {
+                case 1200:
+                        cflag |= B1200;
+                        break;
+                case 2400:
+                        cflag |= B2400;
+                        break;
+                case 4800:
+                        cflag |= B4800;
+                        break;
+                case 19200:
+                        cflag |= B19200;
+                        break;
+                case 38400:
+                        cflag |= B38400;
+                        break;
+                case 57600:
+                        cflag |= B57600;
+                        break;
+                case 115200:
+                        cflag |= B115200;
+                        break;
+                case 9600:
+                default:
+                        cflag |= B9600;
+                        break;
+        }
+        switch(bits) {
+                case 7:
+                        cflag |= CS7;
+                        break;
+                default:
+                case 8:
+                        cflag |= CS8;
+                        break;
+        }
+        switch(parity) {
+                case 'o': case 'O':
+                        cflag |= PARODD;
+                        break;
+                case 'e': case 'E':
+                        cflag |= PARENB;
+                        break;
+        }
+
+        /*
+         *      Divisor, bytesize and parity
+         */
+
+        ser = rs_table + ttyS;
+	ser->flags &= ~ASYNC_BOOT_AUTOCONF;
+        quot = ser->baud_base / baud;
+        cval = cflag & (CSIZE | CSTOPB);
+        cval >>= 4;
+        if (cflag & PARENB)
+                cval |= UART_LCR_PARITY;
+        if (!(cflag & PARODD))
+                cval |= UART_LCR_EPAR;
+
+        /*
+         *      Disable UART interrupts, set DTR and RTS high
+         *      and set speed.
+         */
+	cval = 0x3;
+        outb(cval | UART_LCR_DLAB, ser->port + UART_LCR);       /* set DLAB */
+        outb(quot & 0xff, ser->port + UART_DLL);         /* LS of divisor */
+        outb(quot >> 8, ser->port + UART_DLM);           /* MS of divisor */
+        outb(cval, ser->port + UART_LCR);                /* reset DLAB */
+        outb(UART_IER_RDI, ser->port + UART_IER);        /* turn on interrupts*/
+        outb(UART_MCR_OUT2 | UART_MCR_DTR | UART_MCR_RTS, ser->port + UART_MCR);
+
+        /*
+         *      If we read 0xff from the LSR, there is no UART here.
+         */
+        if (inb(ser->port + UART_LSR) == 0xff)
+                return 0;
+        return ser;
+}
+#ifdef CONFIG_GDB_CONSOLE
+void __init gdb_console_init(void)
+{
+	register_console(&gdbcons);
+}
+#endif
+#endif /* CONFIG_X86_REMOTE_DEBUG */
+
+/*
   Local variables:
   compile-command: "gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strict-aliasing -pipe -fno-strength-reduce -march=i586 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h   -DEXPORT_SYMTAB -c serial.c"
   End:
--- diff/drivers/char/tty_io.c	2002-08-05 14:57:31.000000000 +0100
+++ source/drivers/char/tty_io.c	2002-11-05 15:20:24.000000000 +0000
@@ -90,6 +90,9 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/smp_lock.h>
+#ifdef CONFIG_GDB_CONSOLE
+#include <linux/gdb.h>
+#endif
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
@@ -2187,6 +2190,9 @@
 #ifdef CONFIG_VT
 	con_init();
 #endif
+#ifdef CONFIG_GDB_CONSOLE
+	gdb_console_init();
+#endif
 #ifdef CONFIG_AU1000_SERIAL_CONSOLE
 	au1000_serial_console_init();
 #endif
--- diff/include/asm-i386/ioctls.h	2002-08-05 14:57:40.000000000 +0100
+++ source/include/asm-i386/ioctls.h	2002-11-05 15:20:24.000000000 +0000
@@ -67,6 +67,7 @@
 #define TIOCGICOUNT	0x545D	/* read serial port inline interrupt counts */
 #define TIOCGHAYESESP   0x545E  /* Get Hayes ESP configuration */
 #define TIOCSHAYESESP   0x545F  /* Set Hayes ESP configuration */
+#define TIOCGDB         0x547F  /* enable GDB stub mode on this tty */
 
 /* Used for packet mode */
 #define TIOCPKT_DATA		 0
--- diff/include/asm-i386/page.h	2002-11-05 14:56:48.000000000 +0000
+++ source/include/asm-i386/page.h	2002-11-05 15:22:44.000000000 +0000
@@ -96,11 +96,18 @@
  */
 
 #if 1	/* Set to zero for a slightly smaller kernel */
+#ifdef CONFIG_X86_REMOTE_DEBUG
+#define BUG() do {						\
+	printk("Kernel BUG at %s:%d\n", __FILE__, __LINE__);	\
+	asm ("int $0x3");					\
+} while (0)
+#else
 #define BUG()				\
  __asm__ __volatile__(	"ud2\n"		\
 			"\t.word %c0\n"	\
 			"\t.long %c1\n"	\
 			 : : "i" (__LINE__), "i" (__FILE__))
+#endif
 #else
 #define BUG() __asm__ __volatile__("ud2\n")
 #endif
--- diff/include/asm-i386/processor.h	2002-11-05 14:56:47.000000000 +0000
+++ source/include/asm-i386/processor.h	2002-11-05 15:22:44.000000000 +0000
@@ -385,6 +385,9 @@
 /* IO permissions */
 	int		ioperm;
 	unsigned long	io_bitmap[IO_BITMAP_SIZE+1];
+#ifdef CONFIG_X86_REMOTE_DEBUG
+	struct pt_regs *kgdbregs;
+#endif
 };
 
 #define INIT_THREAD  {						\
--- diff/include/linux/dcache.h	2002-11-05 14:56:49.000000000 +0000
+++ source/include/linux/dcache.h	2002-11-05 15:22:44.000000000 +0000
@@ -4,6 +4,7 @@
 #ifdef __KERNEL__
 
 #include <asm/atomic.h>
+#include <linux/gdb.h>
 #include <linux/mount.h>
 
 /*
--- diff/include/linux/sched.h	2002-11-05 14:56:47.000000000 +0000
+++ source/include/linux/sched.h	2002-11-05 15:22:44.000000000 +0000
@@ -156,7 +156,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);
 
 extern int schedule_task(struct tq_struct *task);
 extern void flush_scheduled_tasks(void);
@@ -944,6 +946,12 @@
 	return res;
 }
 
+#ifdef CONFIG_KGDB_THREAD
+#define schedule() kern_schedule()
+#else
+#define schedule() do_schedule()
+#endif
+
 #endif /* __KERNEL__ */
 
 #endif
--- diff/init/main.c	2002-08-05 14:57:44.000000000 +0100
+++ source/init/main.c	2002-11-05 15:20:24.000000000 +0000
@@ -56,6 +56,10 @@
 #include <linux/nubus.h>
 #endif
 
+#ifdef CONFIG_X86_REMOTE_DEBUG
+#include <linux/gdb.h>
+#endif
+
 #ifdef CONFIG_ISAPNP
 #include <linux/isapnp.h>
 #endif
@@ -432,6 +436,11 @@
 	 *	make syscalls (and thus be locked).
 	 */
 	smp_init();
+#ifdef CONFIG_X86_REMOTE_DEBUG
+	if (gdb_enter) {
+		gdb_hook();		/* right at boot time */
+	}
+#endif
 	rest_init();
 }
 
--- diff/kernel/ksyms.c	2002-11-05 12:12:09.000000000 +0000
+++ source/kernel/ksyms.c	2002-11-05 15:20:24.000000000 +0000
@@ -446,7 +446,10 @@
 EXPORT_SYMBOL(sleep_on_timeout);
 EXPORT_SYMBOL(interruptible_sleep_on);
 EXPORT_SYMBOL(interruptible_sleep_on_timeout);
-EXPORT_SYMBOL(schedule);
+EXPORT_SYMBOL(do_schedule);
+#ifdef CONFIG_KGDB_THREAD
+EXPORT_SYMBOL(kern_schedule);
+#endif
 EXPORT_SYMBOL(schedule_timeout);
 EXPORT_SYMBOL(sys_sched_yield);
 EXPORT_SYMBOL(jiffies);
--- diff/kernel/sched.c	2002-08-05 14:57:44.000000000 +0100
+++ source/kernel/sched.c	2002-11-05 15:20:24.000000000 +0000
@@ -546,7 +546,7 @@
  * tasks can run. It can not be killed, and it cannot sleep. The 'state'
  * information in task[0] is never used.
  */
-asmlinkage void schedule(void)
+asmlinkage void do_schedule(void)
 {
 	struct schedule_data * sched_data;
 	struct task_struct *prev, *next, *p;
@@ -704,6 +704,22 @@
 	return;
 }
 
+asmlinkage void user_schedule(void)
+{
+#ifdef CONFIG_KGDB_THREAD
+	current->thread.kgdbregs = NULL;
+#endif
+	do_schedule();
+}
+
+#ifdef CONFIG_KGDB_THREAD
+asmlinkage void kern_do_schedule(struct pt_regs regs)
+{
+	current->thread.kgdbregs = &regs;
+	do_schedule();
+}
+#endif
+
 /*
  * The core wakeup function.  Non-exclusive wakeups (nr_exclusive == 0) just wake everything
  * up.  If it's an exclusive wakeup (nr_exclusive == small +ve number) then we wake all the
--- diff/Documentation/i386/gdb-serial.txt	1970-01-01 01:00:00.000000000 +0100
+++ source/Documentation/i386/gdb-serial.txt	2002-11-05 15:20:24.000000000 +0000
@@ -0,0 +1,386 @@
+Version
+=======
+
+This version of the gdbstub package was developed and tested on
+kernel version 2.3.48.  It will not install on a 2.2 kernel.  It may
+not work on earlier versions of 2.3 kernels.  It is possible that
+it will continue to work on later versions of 2.3 and then
+versions of 2.4 (I hope).
+
+
+Debugging Setup
+===============
+
+Designate one machine as the "development" machine.  This is the
+machine on which you run your compiles and which has your source
+code for the kernel.  Designate a second machine as the "target"
+machine.  This is the machine that will run your experimental
+kernel.
+
+The two machines will be connected together via a serial line out
+one or the other of the COM ports of the PC.  You will need a modem
+eliminator and the appropriate cables.
+
+On the DEVELOPMENT machine you need to apply the patch for the gdb
+hooks.  You have probably already done that if you are reading this
+file.
+
+On your DEVELOPMENT machine, go to your kernel source directory and
+do "make menuconfig".  Go down to the kernel hacking menu item and
+open it up.  Enable the kernel gdb stub code by selecting that item.
+
+Save and exit the menuconfig program.  Then do "make clean" and
+"make bzImage" (or whatever target you want to make).  This gets
+the kernel compiled with the "-g" option set -- necessary for
+debugging.
+
+You have just built the kernel on your DEVELOPMENT machine that you
+intend to run on our TARGET machine.
+
+To install this new kernel, use the following installation procedure.
+Remember, you are on the DEVELOPMENT machine patching the kernel source
+for the kernel that you intend to run on the TARGET machine.
+
+Copy this kernel to your target machine using your usual procedures.
+I usually arrange to copy development:/usr/src/linux/arch/i386/boot/zImage
+to /vmlinuz on the TARGET machine via a LAN based NFS access.  That is,
+I run the cp command on the target and copy from the development machine
+via the LAN.  Run Lilo on the new kernel on the target machine so that it
+will boot!  Then boot the kernel on the target machine.
+
+There is an utility program named "gdbstart" in the
+development:/usr/src/linux/arch/i386/kernel directory.
+You should copy this program over to your target machine, probably into
+/sbin.  This utility program is run on the target machine to
+activate the kernel hooks for the debugger.  It is invoked as follows:
+
+    gdbstart [-s speed] [-t tty-dev]
+    defaults:  /dev/ttyS0 with speed unmodified by gdbstart
+
+Don't run the program just yet.  We'll get to that in a bit.
+
+Decide on which tty port you want the machines to communicate, then
+cable them up back-to-back using the null modem.  COM1 is /dev/ttyS0
+and COM2 is /dev/ttyS1.
+
+On the DEVELOPMENT machine, create a file called .gdbinit in the
+directory /usr/src/linux.  An example .gdbinit file looks like this:
+
+define rmt
+set remotebaud 38400
+target remote /dev/ttyS0
+end
+
+Assuming that you added my gdbinit stuff to your .gdbinit, edit .gdbinit
+and find the section that looks like this:
+
+	define rmt
+	set remotebaud 38400
+	target remote /dev/ttyS0
+	end
+
+Change the "target" definition so that it specifies the tty port that
+you intend to use.  Change the "remotebaud" definition to match the
+data rate that you are going to use for the com line.
+
+On the TARGET machine I find it helpful to create shell script file
+named "debug" in the root home directory with the following contents:
+
+	gdbstart -s 38400 -t /dev/ttyS0 <<EOF
+	<blank line>
+	EOF
+
+This runs the gdbstart program and gives it the carriage return that
+it prompts for.  This sets the data rate from the target machine's side.
+
+You are now ready to try it out.
+
+On your TARGET machine, freshly rebooted with your gdbstub-equipped
+kernel, type "debug" in the root home directory.  The system will appear
+to hang with some messages on the screen from the debug stub.  What
+it is doing is waiting for contact from the development machine.
+
+On your DEVELOPMENT machine, cd /usr/src/linux and enter "gdb vmlinux".
+When gdb gets the symbols loaded and prompts you, enter "rmt" (that's
+the macro from the .gdbinit file that you just edited).  If everything
+is working correctly you should see gdb print out a few lines indicating
+that a breakpoint has been taken.  It will actually show a line of
+code in the target kernel inside the gdbstub activation code.
+
+The gdb interaction should look something like this:
+
+    linux-dev:/usr/src/linux# gdb vmlinux
+    GDB is free software and you are welcome to distribute copies of it
+     under certain conditions; type "show copying" to see the conditions.
+    There is absolutely no warranty for GDB; type "show warranty" for details.
+    GDB 4.15.1 (i486-slackware-linux), 
+    Copyright 1995 Free Software Foundation, Inc...
+    (gdb) rmt
+    breakpoint () at i386-stub.c:750
+    750     }
+    (gdb) 
+
+
+You can now use whatever gdb commands you like to set breakpoints.
+Enter "continue" to start your target machine executing again.  At this
+point the target system will run at full speed until it encounters
+your breakpoint or gets a segment violation in the kernel, or whatever.
+
+
+Triggering gdbstub at Kernel Boot Time
+======================================
+
+The gdbstub patch now has the ability for gdb to connect to the kernel during
+bootup (as opposed to waiting for the system to come all the way up and then
+running the gdbstart program on the target machine).  This new functionality was
+added by Scott Foehner <sfoehner@engr.sgi.com> at SGI.
+
+To force a kernel that has been compiled with gdbstub to pause during the boot
+process and wait for a connection from gdb, the paramter "gdb" should be passed
+to the kernel. This can be done by typing "gdb" after the name of the kernel
+on the LILO command line.  The patch defaults to use ttyS1 at a baud rate of
+38400. These parameters can be changed by using "gdbttyS=<port number>" and
+"gdbbaud=<baud rate>" on the command line.
+
+Example:
+
+LILO boot: linux gdb gdbttyS=1 gdbbaud=38400
+
+Note that this command is entered on the TARGET machine as it is booting
+the kernel that was compiled on the DEVELOPMENT machine.
+
+An alternate approach is to place a line in the /etc/lilo.conf file on
+your TARGET machine.  Under the heading for the kernel that you intend
+to boot, place a line that looks like this:
+
+    append = "gdb gdbttyS=1 gdbbaud=38400"
+
+This will cause the kernel to enter the gdbstub automatically at boot
+time.
+
+BE SURE to run "lilo" after changing the /etc/lilo.conf file.
+
+
+The "gdbstart" Program
+=====================
+
+This utility program is used to set up the com port and data rate
+for the connection from the target system to the development system.
+Its usage has been described above.
+
+This version of the patch uses the same tty ioctl for kernel versions
+2.0.30 onwards.  Thus, the gdbstart utility does not need to be re-compiled
+to install the patch in a later version of the kernel.  The ioctl added
+to the kernel for this purpose is far enough "off the end" of existing
+ioctls (as of 2.1.120) that it should not interfere with any new kernel
+tty ioctls for quite some time (famous last words).
+
+The source for the gdbstart program resides in the arch/i386/kernel directory.
+
+
+Debugging hints
+===============
+
+You can break into the target machine at any time from the development
+machine by typing ^C.  If the target machine has interrupts enabled
+this will stop it in the kernel and enter the debugger.
+
+There is unfortunately no way of breaking into the kernel if it is
+in a loop with interrupts disabled, so if this happens to you then
+you need to place exploratory breakpoints or printk's into the kernel
+to find out where it is looping.
+
+There is a copy of an e-mail in the kgdb distribution directory which
+describes how to create an NMI on an ISA bus machine using a paper
+clip.  I have a sophisticated version of this made by wiring a push
+button switch into a PC104/ISA bus adapter card.  The adapter card
+nicely furnishes wire wrap pins for all the ISA bus signals.
+
+When you are done debugging the kernel on the target machine it is
+a good idea to leave it in a running state.  This makes reboots
+faster, bypassing the fsck.  So do a gdb "continue" as the last gdb
+command if this is possible.  To terminate gdb itself on the development
+machine and leave the target machine running, type ^Z to suspend gdb
+and then kill it with "kill %1" or something similar.
+
+If gdbstub Does Not Work
+========================
+
+If it doesn't work, you will have to troubleshoot it.  Do the easy things
+first like double checking your cabling and data rates.  You might
+try some non-kernel based programs to see if the back-to-back connection
+works properly.  Just something simple like cat /etc/hosts >/dev/ttyS0
+on one machine and cat /dev/ttyS0 on the other will tell you if you
+can send data from one machine to the other.  There is no point in tearing
+out your hair in the kernel if the line doesn't work.
+
+All of the real action takes place in the file
+/usr/src/linux/arch/i386/kernel/gdbstub.c.  That is the code on the target
+machine that interacts with gdb on the development machine.  In gdb you can
+turn on a debug switch with the following command:
+
+	set remotedebug
+
+This will print out the protocol messages that gdb is exchanging with
+the target machine.
+
+Another place to look is /usr/src/linux/drivers/char/gdbserial.c
+That is the code that talks to the serial port on the target side.
+There might be a problem there.
+
+If you are really desperate you can use printk debugging in the
+gdbstub code in the target kernel until you get it working.  In particular,
+there is a global variable in /usr/src/linux/arch/i386/kernel/gdbstub.c
+named "remote_debug".  Compile your kernel with this set to 1, rather
+than 0 and the debug stub will print out lots of stuff as it does
+what it does.
+
+
+Debugging Loadable Modules
+==========================
+
+This technique comes courtesy of Edouard Parmelan
+<Edouard.Parmelan@quadratec.fr>
+
+When you run gdb, enter the command
+
+source gdbinit-modules
+
+This will read in a file of gdb macros that was installed in your
+kernel source directory with kgdb was installed.  This file implements
+the following commands:
+
+mod-list
+    Lists the loaded modules in the form <module-address> <module-name>
+
+mod-print-symbols <module-address>
+    Prints all the symbols in the indicated module.
+
+mod-add-symbols <module-address> <object-file-path-name>
+    Loads the symbols from the object file and associates them
+    with the indicated module.
+
+After you have loaded the module that you want to debug, use the command
+mod-list to find the <module-address> of your module.  Then use that
+address in the mod-add-symbols command to load your module's symbols.
+From that point onward you can debug your module as if it were a part
+of the kernel.
+
+The file gdbinit-modules also contains a command named mod-add-lis as
+an example of how to construct a command of your own to load your
+favorite module.  The idea is to "can" the pathname of the module
+in the command so you don't have to type so much.
+
+Threads
+=======
+
+Each process in a target machine is seen as a gdb thread. gdb thread related
+commands (info threads, thread n) can be used. 
+
+ia-32 hardware breakpoints
+==========================
+
+gdb stub contains support for hardware breakpoints using debugging features
+of ia-32(x86) processors. These breakpoints do not need code modification.
+They use debugging registers. 4 hardware breakpoints are available in ia-32
+processors.
+
+Each hardware breakpoint can be of one of the following three types.
+1. Execution breakpoint - An Execution breakpoint is triggered when code at the
+	breakpoint address is executed.
+
+	As limited number of hardware breakpoints are available, it is advisable
+	to use software breakpoints ( break command ) instead of execution
+	hardware breakpoints, unless modification of code is to be avoided.
+
+2. Write breakpoint - A write breakpoint is triggered when memory location at the
+	breakpoint address is written.
+
+	A write or can be placed for data of variable length. Length of a write
+	breakpoint indicates length of the datatype to be watched. Length is 1
+	for 1 byte data , 2 for 2 byte data, 3 for 4 byte data.
+
+3. Access breakpoint - An access breakpoint is triggered when memory location at
+	the breakpoint address is either read or written.
+
+	Access breakpoints also have lengths similar to write breakpoints.
+
+IO breakpoints in ia-32 are not supported.
+
+Since gdb stub at present does not use the protocol used by gdb for hardware
+breakpoints, hardware breakpoints are accessed through gdb macros. gdb macros
+for hardware breakpoints are described below.
+
+hwebrk	- Places an execution breakpoint
+	hwebrk breakpointno address
+hwwbrk	- Places a write breakpoint
+	hwwbrk breakpointno length address
+hwabrk	- Places an access breakpoint
+	hwabrk breakpointno length address
+hwrmbrk	- Removes a breakpoint
+	hwrmbrk breakpointno
+exinfo	- Tells whether a software or hardware breakpoint has occured.
+	Prints number of the hardware breakpoint if a hardware breakpoint has
+	occured.
+
+Arguments required by these commands are as follows
+breakpointno	- 0 to 3
+length		- 1 to 3
+address		- Memory location in hex digits ( without 0x ) e.g c015e9bc
+
+MP support
+==========
+
+When a breakpoint occurs or user issues a break ( Ctrl + C ) to gdb client,
+all the processors are forced to enter the debugger. Current thread
+corresponds to the thread running on the processor where breakpoint occured.
+Threads running on other processor(s) appear similar to other non running
+threads in the 'info threads' output.
+
+ia-32 hardware debugging registers on all processors are set to same values.
+Hence any hardware breakpoints may occur on any processor.
+
+gdb troubleshooting
+===================
+
+1. gdb hangs
+Kill it. restart gdb. Connect to target machine.
+
+2. gdb cannot connect to target machine (after killing a gdb and restarting
+another)
+If the target machine was not inside debugger when you killed gdb, gdb cannot
+connect because the target machine won't respond.
+In this case echo "Ctrl+C"(ascii 3) in the serial line.
+e.g. echo -e "\003" > /dev/ttyS1 
+This forces that target machine into debugger after which you can connect.
+
+3. gdb cannot connect even after echoing Ctrl+C into serial line
+Try changing serial line settings min to 1 and time to 0
+e.g. stty min 1 time 0 < /dev/ttyS1
+Try echoing again
+
+check serial line speed and set it to correct value if required
+e.g. stty ispeed 115200 ospeed 115200 < /dev/ttyS1
+
+Final Items
+===========
+
+I picked up this code from Dave Grothe and enhanced it.
+
+If you make some really cool modification to this stuff, or if you 
+fix a bug, please let me know.
+
+Amit S. Kale
+<akale@veritas.com>
+
+(First kgdb by David Grothe <dave@gcom.com>)
+
+(modified by Tigran Aivazian <tigran@sco.com>)
+    Putting gdbstub into the kernel config menu.
+
+(modified by Scott Foehner <sfoehner@engr.sgi.com>)
+    Hooks for entering gdbstub at boot time.
+
+(modified by Amit S. Kale <akale@veritas.com>)
+    Threads, ia-32 hw debugging, mp support, console support,
+    nmi watchdog handling.
--- diff/arch/i386/kernel/gdbstart.c	1970-01-01 01:00:00.000000000 +0100
+++ source/arch/i386/kernel/gdbstart.c	2002-11-05 15:20:24.000000000 +0000
@@ -0,0 +1,146 @@
+/*
+ * This program opens a tty file and issues the GDB stub activating
+ * ioctl on it.
+ */
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <asm/ioctls.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <stdlib.h>
+#include <termios.h>
+#include <unistd.h>
+
+char		*tty_name = "/dev/ttyS0" ;	/* COM1 port */
+int		 speed = 9600 ;			/* default speed */
+struct termios	 save_ts ;			/* original term struct */
+
+void print_usage(void)
+{
+    printf("gdbstub [-s speed] [-t tty-dev]\n") ;
+    printf("  defaults:  /dev/ttyS0 with speed unmodified by this program\n");
+
+} /* print_usage */
+
+void tty_err(char *msg)
+{
+    char	buf[100] ;
+
+    strcpy(buf, msg) ;
+    strcat(buf, ": ") ;
+    strcat(buf, tty_name) ;
+    perror(buf) ;
+    exit(1) ;
+
+} /* tty_err */
+
+
+void setup_term(int fd)
+{
+    struct termios	ts ;
+    int			speed_code ;
+
+    if (tcgetattr(fd, &ts) < 0) tty_err("tcgetattr") ;
+
+    save_ts = ts ;
+    switch (speed)
+    {
+    case 4800:
+	speed_code = B4800 ;
+	break ;
+    case 9600:
+	speed_code = B9600 ;
+	break ;
+    case 19200:
+	speed_code = B19200 ;
+	break ;
+    case 38400:
+	speed_code = B38400 ;
+	break ;
+    case 57600:
+	speed_code = B57600 ;
+	break ;
+    case 115200:
+	speed_code = B115200 ;
+	break ;
+    case 230400:
+	speed_code = B230400 ;
+	break ;
+    default:
+	printf("Invalid speed: %d\n", speed) ;
+	exit(1) ;
+    }
+
+    ts.c_cflag = CS8 | CREAD | CLOCAL ;
+    if (cfsetospeed(&ts, speed_code) < 0) tty_err("cfsetospeed") ;
+    if (cfsetispeed(&ts, speed_code) < 0) tty_err("cfsetispeed") ;
+
+    if (tcsetattr(fd, TCSANOW, &ts) < 0) tty_err("tcsetattr") ;
+
+} /* setup_term */
+
+int main(int argc, char **argv)
+{
+    int		opt ;
+    int		fil ;
+    int		rslt ;
+
+    while ((opt = getopt(argc, argv, "hs:t:")) > 0)
+    {
+	switch (opt)
+	{
+	case 's':
+	    speed = atol(optarg) ;
+	    break ;
+	case 't':
+	    tty_name = optarg ;
+	    break ;
+	case ':':
+	    printf("Invalid option\n") ;
+	    break ;
+	case '?':
+	case 'h':
+	default:
+	    print_usage() ;
+	    return 0;
+	}
+    }
+
+    fil = open(tty_name, O_RDWR) ;
+    if (fil < 0)
+    {
+	perror(tty_name) ;
+	return 0;
+    }
+
+
+    setup_term(fil) ;
+
+    /*
+     * When we issue this ioctl, control will not return until
+     * the debugger running on the remote host machine says "go".
+     */
+    printf("\nAbout to activate GDB stub in the kernel on %s\n", tty_name) ;
+    printf("Hit CR to continue, kill program to abort -- ") ;
+    getchar() ;
+    sync() ;
+    rslt = ioctl(fil, TIOCGDB, 0) ;
+    if (rslt < 0)
+    {
+	perror("TIOCGDB ioctl") ;
+	return 0;
+    }
+
+    printf("\nGDB stub successfully activated\n") ;
+
+    for (;;)
+    {
+	pause() ;
+    }
+
+    if (tcsetattr(fil, TCSANOW, &save_ts) < 0) tty_err("tcsetattr") ;
+    return 0;
+} /* main */
--- diff/arch/i386/kernel/gdbstub.c	1970-01-01 01:00:00.000000000 +0100
+++ source/arch/i386/kernel/gdbstub.c	2002-11-05 15:20:24.000000000 +0000
@@ -0,0 +1,1214 @@
+/*
+ *
+ * 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.
+ */
+/****************************************************************************
+ *  Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
+ *
+ *  Module name: remcom.c $
+ *  Revision: 1.34 $
+ *  Date: 91/03/09 12:29:49 $
+ *  Contributor:     Lake Stevens Instrument Division$
+ *
+ *  Description:     low level support for gdb debugger. $
+ *
+ *  Considerations:  only works on target hardware $
+ *
+ *  Written by:      Glenn Engel $
+ *  Updated by:	     Amit Kale<akale@veritas.com>
+ *  ModuleState:     Experimental $
+ *
+ *  NOTES:           See Below $
+ *
+ *  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>
+ *      thread support,
+ *      support for multiple processors,
+ *  	support for ia-32(x86) hardware debugging,
+ *  	Console support,
+ *  	handling nmi watchdog
+ *  	Amit S. Kale ( akale@veritas.com )
+ *
+ *
+ *  To enable debugger support, two things need to happen.  One, a
+ *  call to set_debug_traps() is necessary in order to allow any breakpoints
+ *  or error conditions to be properly intercepted and reported to gdb.
+ *  Two, a breakpoint needs to be generated to begin communication.  This
+ *  is most easily accomplished by a call to breakpoint().  Breakpoint()
+ *  simulates a breakpoint by executing an int 3.
+ *
+ *************
+ *
+ *    The following gdb commands are supported:
+ *
+ * command          function                               Return value
+ *
+ *    g             return the value of the CPU registers  hex data or ENN
+ *    G             set the value of the CPU registers     OK or ENN
+ *
+ *    mAA..AA,LLLL  Read LLLL bytes at address AA..AA      hex data or ENN
+ *    MAA..AA,LLLL: Write LLLL bytes at address AA.AA      OK or ENN
+ *
+ *    c             Resume at current address              SNN   ( signal NN)
+ *    cAA..AA       Continue at address AA..AA             SNN
+ *
+ *    s             Step one instruction                   SNN
+ *    sAA..AA       Step one instruction from AA..AA       SNN
+ *
+ *    k             kill
+ *
+ *    ?             What was the last sigval ?             SNN   (signal NN)
+ *
+ * All commands and responses are sent with a packet which includes a
+ * checksum.  A packet consists of
+ *
+ * $<packet info>#<checksum>.
+ *
+ * where
+ * <packet info> :: <characters representing the command or response>
+ * <checksum>    :: < two hex digits computed as modulo 256 sum of <packetinfo>>
+ *
+ * When a packet is received, it is first acknowledged with either '+' or '-'.
+ * '+' indicates a successful transfer.  '-' indicates a failed transfer.
+ *
+ * Example:
+ *
+ * Host:                  Reply:
+ * $m0,10#2a               +$00010203040506070809101112131415#42
+ *
+ ****************************************************************************/
+
+#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/gdb.h>
+#ifdef CONFIG_GDB_CONSOLE
+#include <linux/console.h>
+#endif
+#include <linux/init.h>
+
+/************************************************************************
+ *
+ * external low-level support routines
+ */
+typedef void (*Function)(void);           /* pointer to a function */
+
+/* Thread reference */
+typedef unsigned char threadref[8];
+
+extern int putDebugChar(int);   /* write a single character      */
+extern int getDebugChar(void);   /* read and return a single char */
+
+/************************************************************************/
+/* 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
+
+static char initialized;  /* boolean flag. != 0 means we've been initialized */
+
+static const char hexchars[]="0123456789abcdef";
+
+/* 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 */
+
+
+
+/***************************  ASSEMBLY CODE MACROS *************************/
+/* 									   */
+
+#define BREAKPOINT() asm("   int $3");
+
+/* 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;
+
+static spinlock_t slavecpulocks[KGDB_MAX_NO_CPUS];
+volatile int procindebug[KGDB_MAX_NO_CPUS];
+
+#ifdef CONFIG_SMP
+spinlock_t kgdb_spinlock = SPIN_LOCK_UNLOCKED;
+spinlock_t kgdb_nmispinlock = SPIN_LOCK_UNLOCKED;
+#else 
+unsigned kgdb_spinlock = 0;
+unsigned kgdb_nmispinlock = 0;
+#endif
+
+static void kgdb_usercode (void)
+{
+}
+
+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>     */
+void getpacket(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 = (getDebugChar() & 0x7f)) != '$');
+    checksum = 0;
+    xmitcsum = -1;
+
+    count = 0;
+
+    /* now, read until a # or end of buffer is found */
+    while (count < BUFMAX) {
+      ch = getDebugChar() & 0x7f;
+      if (ch == '#') break;
+      checksum = checksum + ch;
+      buffer[count] = ch;
+      count = count + 1;
+      }
+    buffer[count] = 0;
+
+    if (ch == '#') {
+      xmitcsum = hex(getDebugChar() & 0x7f) << 4;
+      xmitcsum += hex(getDebugChar() & 0x7f);
+
+      if (checksum != xmitcsum) putDebugChar('-');  /* failed checksum */
+      else {
+	 putDebugChar('+');  /* successful transfer */
+	 /* if a sequence char is present, reply the sequence ID */
+	 if (buffer[2] == ':') {
+	    putDebugChar( buffer[0] );
+	    putDebugChar( buffer[1] );
+	    /* remove sequence chars from buffer */
+	    count = strlen(buffer);
+	    for (i=3; i <= count; i++) buffer[i-3] = buffer[i];
+	 }
+      }
+    }
+  } while (checksum != xmitcsum);
+
+}
+
+/* send the packet in buffer.  */
+
+
+void putpacket(char * buffer)
+{
+  unsigned char checksum;
+  int  count;
+  char ch;
+
+  /*  $<packet info>#<checksum>. */
+  do {
+  putDebugChar('$');
+  checksum = 0;
+  count    = 0;
+
+  while ((ch=buffer[count])) {
+    if (! putDebugChar(ch)) return;
+    checksum += ch;
+    count += 1;
+  }
+
+  putDebugChar('#');
+  putDebugChar(hexchars[checksum >> 4]);
+  putDebugChar(hexchars[checksum % 16]);
+
+  } while ((getDebugChar() & 0x7f) != '+');
+
+}
+
+static char  remcomInBuffer[BUFMAX];
+static char  remcomOutBuffer[BUFMAX];
+static short error;
+
+static void regs_to_gdb_regs(int *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;
+} /* regs_to_gdb_regs */
+
+static void gdb_regs_to_regs(int *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
+
+} /* gdb_regs_to_regs */
+
+/* Indicate to caller of mem2hex or hex2mem that there has been an
+   error.  */
+static volatile int kgdb_memerr = 0;
+volatile int kgdb_memerr_expected = 0;
+static volatile int kgdb_memerr_cnt = 0;
+static          int garbage_loc = -1 ;
+
+int
+get_char (char *addr)
+{
+  return *addr;
+}
+
+void
+set_char ( char *addr, int val)
+{
+  *addr = val;
+}
+
+/* convert the memory pointed to by mem into hex, placing result in buf */
+/* return a pointer to the last char put in buf (null) */
+/* If MAY_FAULT is non-zero, then we should set kgdb_memerr in response to
+   a fault; if zero treat a fault like any other fault in the stub.  */
+char* mem2hex( char* mem,
+	       char* buf,
+	       int   count,
+	       int may_fault)
+{
+      int i;
+      unsigned char ch;
+
+      if (may_fault)
+      {
+          kgdb_memerr_expected = 1 ;
+          kgdb_memerr = 0 ;
+      }
+      for (i=0;i<count;i++) {
+
+	  ch = get_char (mem++);
+
+	  if (may_fault && kgdb_memerr)
+	  {
+	    *buf = 0 ;				/* truncate buffer */
+	    return (buf);
+	  }
+          *buf++ = hexchars[ch >> 4];
+          *buf++ = hexchars[ch % 16];
+      }
+      *buf = 0;
+      if (may_fault)
+	  kgdb_memerr_expected = 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 */
+char* hex2mem( char* buf,
+	       char* mem,
+	       int   count,
+	       int may_fault)
+{
+      int i;
+      unsigned char ch;
+
+      if (may_fault)
+      {
+          kgdb_memerr_expected = 1 ;
+          kgdb_memerr = 0 ;
+      }
+      for (i=0;i<count;i++) {
+          ch = hex(*buf++) << 4;
+          ch = ch + hex(*buf++);
+	  set_char (mem++, ch);
+
+	  if (may_fault && kgdb_memerr)
+	  {
+	    return (mem);
+	  }
+      }
+      if (may_fault)
+	  kgdb_memerr_expected = 0 ;
+      return(mem);
+}
+
+
+/**********************************************/
+/* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */
+/* RETURN NUMBER OF CHARS PROCESSED           */
+/**********************************************/
+int hexToInt(char **ptr, int *intValue)
+{
+    int numChars = 0;
+    int hexValue;
+
+    *intValue = 0;
+
+    while (**ptr)
+    {
+        hexValue = hex(**ptr);
+        if (hexValue >=0)
+        {
+            *intValue = (*intValue <<4) | hexValue;
+            numChars ++;
+        }
+        else
+            break;
+
+        (*ptr)++;
+    }
+
+    return (numChars);
+}
+
+#ifdef CONFIG_KGDB_THREAD
+static int
+stubhex (
+     int 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;
+}
+
+
+static int
+stub_unpack_int (
+     char *buff,
+     int fieldlength)
+{
+  int nibble;
+  int retval = 0;
+
+  while (fieldlength)
+    {
+      nibble = stubhex (*buff++);
+      retval |= nibble;
+      fieldlength--;
+      if (fieldlength)
+	retval = retval << 4;
+    }
+  return retval;
+}
+#endif
+
+static char *
+pack_hex_byte (
+     char *pkt,
+     int byte)
+{
+  *pkt++ = hexchars[(byte >> 4) & 0xf];
+  *pkt++ = hexchars[(byte & 0xf)];
+  return pkt;
+}
+
+#define BUF_THREAD_ID_SIZE 16
+
+#ifdef CONFIG_KGDB_THREAD
+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;
+}
+
+static char *
+unpack_byte (
+     char *buf,
+     int *value)
+{
+  *value = stub_unpack_int (buf, 2);
+  return buf + 2;
+}
+
+static char *
+unpack_threadid (
+     char *inbuf,
+     threadref *id)
+{
+  char *altref;
+  char *limit = inbuf + BUF_THREAD_ID_SIZE;
+  int x, y;
+
+  altref = (char *) id;
+
+  while (inbuf < limit)
+    {
+      x = stubhex (*inbuf++);
+      y = stubhex (*inbuf++);
+      *altref++ = (x << 4) | y;
+    }
+  return inbuf;
+}
+#endif
+
+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);
+}
+
+#ifdef CONFIG_KGDB_THREAD
+static int
+threadref_to_int (
+     threadref *ref)
+{
+  int i, value = 0;
+  unsigned char *scan;
+
+  scan = (char *) ref;
+  scan += 4;
+  i = 4;
+  while (i-- > 0)
+    value = (value << 8) | ((*scan++) & 0xff);
+  return value;
+}
+
+
+struct task_struct *
+getthread (
+	int pid)
+{
+	struct task_struct *thread;
+	thread = find_task_by_pid(pid);
+	if (thread) {
+		return thread;
+	}
+	thread = init_tasks[0];
+	do {
+		if (thread->pid == pid) {
+			return thread;
+		}
+		thread = thread->next_task;
+	} while (thread != init_tasks[0]);
+	return NULL;
+}
+#endif
+
+struct hw_breakpoint {
+	unsigned enabled;
+	unsigned type;
+	unsigned len;
+	unsigned addr;
+} breakinfo[4] = { { enabled:0 }, { enabled:0 }, { enabled:0 }, { enabled:0 }};
+
+void 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 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
+gdb_wait(void *arg)
+{
+	unsigned flags;
+	int processor;
+	
+	local_irq_save(flags);
+	processor = smp_processor_id();
+	procindebug[processor] = 1;
+	current->thread.kgdbregs = arg;
+	spin_lock(slavecpulocks + processor);
+	correct_hw_break();
+	procindebug[processor] = 0;
+	local_irq_restore(flags);
+}
+
+void
+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;
+}
+
+/*
+ * This function does all command procesing for interfacing to gdb.
+ *
+ * NOTE:  The INT nn instruction leaves the state of the interrupt
+ *        enable flag UNCHANGED.  That means that when this routine
+ *        is entered via a breakpoint (INT 3) instruction from code
+ *        that has interrupts enabled, then interrupts will STILL BE
+ *        enabled when this routine is entered.  The first thing that
+ *        we do here is disable interrupts so as to prevent recursive
+ *        entries and bothersome serial interrupts while we are
+ *        trying to run the serial port in polled mode.
+ *
+ * For kernel version 2.1.xx the cli() actually gets a spin lock so
+ * it is always necessary to do a restore_flags before returning
+ * so as to let go of that lock.
+ */
+int handle_exception(int exceptionVector,
+		     int signo,
+		     int err_code,
+		     struct pt_regs *linux_regs)
+{
+	struct task_struct	*usethread = NULL;
+	int			addr, length;
+	int			breakno, breaktype;
+	char			*ptr;
+	int			newPC;
+	unsigned long		flags = ~0UL;
+	int 			gdb_regs[NUMREGBYTES/4];
+	int			i;
+	int			dr6;
+#ifdef CONFIG_KGDB_THREAD
+	int			nothreads;
+	int			maxthreads;
+	int			threadid;
+	threadref		thref;
+	struct task_struct	*thread = NULL;
+#endif
+#define	regs	(*linux_regs)
+
+	/*
+	 * If the entry is not from the kernel then return to the Linux
+	 * trap handler and let it process the interrupt normally.
+	 */
+	if ((linux_regs->eflags & VM_MASK) || (3 & linux_regs->xcs)) {
+		return(0);
+	}
+
+	if (kgdb_memerr_expected)
+	{
+		/*
+		 * This fault occured because of the get_char or set_char
+		 * routines.  These two routines use either eax of edx to
+		 * indirectly reference the location in memory that they
+		 * are working with.  For a page fault, when we return
+		 * the instruction will be retried, so we have to make
+		 * sure that these registers point to valid memory.
+		 */
+		kgdb_memerr = 1 ;		/* set mem error flag */
+		kgdb_memerr_expected = 0 ;
+		kgdb_memerr_cnt++ ;	/* helps in debugging */
+		regs.eax = (long) &garbage_loc ;	/* make valid address */
+		regs.edx = (long) &garbage_loc ;	/* make valid address */
+		return(0) ;
+	}
+
+#ifdef CONFIG_SMP
+	if (!spin_is_locked(&kgdb_nmispinlock))
+#else
+	if (!kgdb_nmispinlock)
+#endif
+	{
+
+		/* Get kgdb spinlock */
+#ifdef CONFIG_SMP
+		spin_lock(&kgdb_spinlock);
+#else
+		kgdb_spinlock = 1;
+#endif
+
+		local_irq_save(flags);
+
+		/* Disable hardware debugging while we are in kgdb */
+		__asm__("movl %0,%%db7"
+			: /* no output */
+			: "r" (0));
+
+		for (i = 0; i < smp_num_cpus; i++) {
+			spin_lock_init(&slavecpulocks[i]);
+			spin_lock(&slavecpulocks[i]);
+		}
+
+		/* Force other cpus in debugger */
+		if (smp_call_function(gdb_wait, NULL, 0, 0) != 0 ){
+			return(1);
+		}
+
+		procindebug[smp_processor_id()] = 1;
+	}
+
+	gdb_i386vector  = exceptionVector;
+	gdb_i386errcode = err_code ;
+
+	/* reply to host that an exception has occurred */
+	remcomOutBuffer[0] = 'S';
+	remcomOutBuffer[1] =  hexchars[signo >> 4];
+	remcomOutBuffer[2] =  hexchars[signo % 16];
+	remcomOutBuffer[3] = 0;
+
+	putpacket(remcomOutBuffer);
+
+	while (1==1) {
+		error = 0;
+		remcomOutBuffer[0] = 0;
+		getpacket(remcomInBuffer);
+		switch (remcomInBuffer[0]) {
+		case '?' : 
+			remcomOutBuffer[0] = 'S';
+			remcomOutBuffer[1] =  hexchars[signo >> 4];
+			remcomOutBuffer[2] =  hexchars[signo % 16];
+			remcomOutBuffer[3] = 0;
+			break;
+		case 'g' : /* return the value of the CPU registers */
+			if (!usethread || usethread == current) {
+				regs_to_gdb_regs(gdb_regs, &regs) ;
+			} else {
+				memset(gdb_regs, 0, NUMREGBYTES);
+				if (usethread->thread.kgdbregs) {
+					kgdb_memerr_expected = 1 ;
+					kgdb_memerr = 0;
+					get_char((char *)usethread->thread.kgdbregs);
+					kgdb_memerr_expected = 0;
+					if (kgdb_memerr) {
+						gdb_regs[_PC] = (int)kgdb_usercode;
+					} else {
+						regs_to_gdb_regs(gdb_regs,
+							usethread->thread.kgdbregs);
+					}
+				} else {
+					gdb_regs[_PC] = (int)kgdb_usercode;
+				}
+			}
+			mem2hex((char*) gdb_regs, remcomOutBuffer, NUMREGBYTES, 0);
+			break;
+		case 'G' : /* set the value of the CPU registers - return OK */
+			hex2mem(&remcomInBuffer[1], (char*) gdb_regs, NUMREGBYTES, 0);
+			if (!usethread || usethread == current) {
+				gdb_regs_to_regs(gdb_regs, &regs) ;
+				strcpy(remcomOutBuffer,"OK");
+			} else {
+				strcpy(remcomOutBuffer,"E00");
+			}
+			break;
+
+		/* mAA..AA,LLLL  Read LLLL bytes at address AA..AA */
+		case 'm' :
+			/* TRY TO READ %x,%x.  IF SUCCEED, SET PTR = 0 */
+			ptr = &remcomInBuffer[1];
+			if (hexToInt(&ptr,&addr))
+			if (*(ptr++) == ',')
+			if (hexToInt(&ptr,&length))
+			{
+				ptr = 0;
+				mem2hex((char*) addr, remcomOutBuffer, length, 1);
+				if (kgdb_memerr) {
+					strcpy (remcomOutBuffer, "E03");
+				}
+			}
+
+			if (ptr)
+			{
+				strcpy(remcomOutBuffer,"E01");
+			}
+			break;
+
+	      /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
+	      case 'M' :
+				/* TRY TO READ '%x,%x:'.  IF SUCCEED, SET PTR = 0 */
+				ptr = &remcomInBuffer[1];
+				if (hexToInt(&ptr,&addr))
+				if (*(ptr++) == ',')
+					if (hexToInt(&ptr,&length))
+						if (*(ptr++) == ':')
+						{
+							hex2mem(ptr, (char*) addr, length, 1);
+
+							if (kgdb_memerr) {
+								strcpy (remcomOutBuffer, "E03");
+							} else {
+								strcpy(remcomOutBuffer,"OK");
+							}
+
+							ptr = 0;
+						}
+				if (ptr)
+				{
+					strcpy(remcomOutBuffer,"E02");
+				}
+				break;
+
+	     /* cAA..AA    Continue at address AA..AA(optional) */
+	     /* sAA..AA   Step one instruction from AA..AA(optional) */
+	     case 'c' :
+	     case 's' :
+#ifdef CONFIG_SMP
+			if (spin_is_locked(&kgdb_nmispinlock))
+#else
+			if (kgdb_nmispinlock)
+#endif
+			{
+				strcpy(remcomOutBuffer,"E01");
+				break;
+			}
+
+			/* try to read optional parameter, pc unchanged if no parm */
+			ptr = &remcomInBuffer[1];
+			if (hexToInt(&ptr,&addr))
+			{
+				regs.eip = addr;
+			}
+
+			newPC = regs.eip ;
+
+			/* clear the trace bit */
+			regs.eflags &= 0xfffffeff;
+
+			/* set the trace bit if we're stepping */
+			if (remcomInBuffer[0] == 's') regs.eflags |= 0x100;
+
+			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 */
+							regs.eflags |= 0x10000;
+							break;
+						}
+					}
+				}
+			}
+			correct_hw_break();
+			asm volatile ( 
+				"movl %0, %%db6\n"
+				: 
+				: "r" (0) );
+			for (i = 0; i < smp_num_cpus; i++) {
+				spin_unlock(&slavecpulocks[i]);
+			}
+
+			procindebug[smp_processor_id()] = 0;
+			/* Release kgdb spinlock */
+#ifdef CONFIG_SMP
+			spin_unlock(&kgdb_spinlock);
+#else
+			kgdb_spinlock = 0;
+#endif
+			if (flags != ~0UL)
+				local_irq_restore(flags) ;
+			return(0) ;
+
+		/* kill the program */
+		case 'k' :  /* do nothing */
+		break;
+
+		/* query */
+		case 'q' :
+			switch (remcomInBuffer[1]) {
+#ifdef CONFIG_KGDB_THREAD
+			case 'L':	
+				/* List threads */
+				unpack_byte(remcomInBuffer+3, &maxthreads);
+				unpack_threadid(remcomInBuffer+5, &thref);
+
+				remcomOutBuffer[0] = 'q';
+				remcomOutBuffer[1] = 'M';
+				remcomOutBuffer[4] = '0';
+				pack_threadid(remcomOutBuffer+5, &thref);	
+
+				threadid = threadref_to_int(&thref);
+				for (nothreads = 0;
+					nothreads < maxthreads && threadid< PID_MAX;
+					threadid++ )
+				{
+					read_lock(&tasklist_lock);
+					thread = getthread(threadid);
+					read_unlock(&tasklist_lock);
+					if (thread) {
+						int_to_threadref(&thref, threadid);
+						pack_threadid(remcomOutBuffer+21+nothreads*16,
+							      &thref);
+						nothreads++;
+					}
+				}
+				if (threadid == PID_MAX) {
+					remcomOutBuffer[4] = '1';
+				}
+				pack_hex_byte(remcomOutBuffer+2, nothreads);
+				remcomOutBuffer[21+nothreads*16] = '\0';
+				break;
+
+			case 'C':
+				/* Current thread id */
+				remcomOutBuffer[0] = 'Q';
+				remcomOutBuffer[1] = 'C';
+				threadid = current->pid;
+				int_to_threadref(&thref, threadid);
+				pack_threadid(remcomOutBuffer+2, &thref);	
+				remcomOutBuffer[18] = '\0';
+				break;
+#endif
+
+			case 'E':
+				/* Print exception info */
+				printexceptioninfo(exceptionVector, err_code, remcomOutBuffer);
+				break;
+			}
+			break;
+
+#ifdef CONFIG_KGDB_THREAD
+		/* task related */
+		case 'H' :	 
+			switch (remcomInBuffer[1]) {
+				case 'g':
+					ptr = &remcomInBuffer[2];
+					hexToInt(&ptr, &threadid);
+					thread = getthread(threadid);
+					if (!thread) {
+						remcomOutBuffer[0] = 'E';
+						remcomOutBuffer[1] = '\0';
+						break;
+					}
+					usethread = thread;
+					/* follow through */
+				case 'c':
+					remcomOutBuffer[0] = 'O';
+					remcomOutBuffer[1] = 'K';
+					remcomOutBuffer[2] = '\0';
+				break;
+			}
+			break;
+
+		/* Query thread status */
+		case 'T':
+			ptr = &remcomInBuffer[1];
+			hexToInt(&ptr, &threadid);
+			thread = getthread(threadid);
+			if (thread) {
+				remcomOutBuffer[0] = 'O';
+				remcomOutBuffer[1] = 'K';
+				remcomOutBuffer[2] = '\0';
+			} else {
+				remcomOutBuffer[0] = 'E';
+				remcomOutBuffer[1] = '\0';
+			}
+			break;
+#endif
+
+		case 'Y':
+			ptr = &remcomInBuffer[1];
+			hexToInt(&ptr, &breakno);
+			ptr++;
+			hexToInt(&ptr, &breaktype);
+			ptr++;
+			hexToInt(&ptr, &length);
+			ptr++;
+			hexToInt(&ptr, &addr);
+			if (set_hw_break(breakno & 0x3, breaktype & 0x3 , length & 0x3, addr)
+				== 0) {
+				strcpy(remcomOutBuffer, "OK");
+			} else {
+				strcpy(remcomOutBuffer, "ERROR");
+			}
+			break;
+
+		/* Remove hardware breakpoint */      
+		case 'y':
+			ptr = &remcomInBuffer[1];
+			hexToInt(&ptr, &breakno);
+			if (remove_hw_break(breakno & 0x3) == 0) {
+				strcpy(remcomOutBuffer, "OK");
+			} else {
+				strcpy(remcomOutBuffer, "ERROR");
+			}
+			break;
+
+		} /* switch */
+
+		/* reply to the request */
+		putpacket(remcomOutBuffer);
+	}
+}
+
+/* this function is used to set up exception handlers for tracing and
+   breakpoints */
+void set_debug_traps(void)
+{
+	/*
+	 * linux_debug_hook is defined in traps.c.  We store a pointer
+	 * to our own exception handler into it.
+	 */
+	linux_debug_hook = handle_exception ;
+
+	/*
+	 * In case GDB is started before us, ack any packets (presumably
+	 * "$?#xx") sitting there.  */
+	putDebugChar ('+');
+
+	initialized = 1;
+}
+
+/* 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 (initialized)
+		BREAKPOINT();
+}
+
+#ifdef CONFIG_GDB_CONSOLE
+char	gdbconbuf[BUFMAX];
+
+void gdb_console_write(struct console *co, const char *s,
+				unsigned count)
+{
+	int	i;
+	int	wcount;
+	char	*bufptr;
+
+	if (!gdb_initialized) {
+		return;
+	}
+	gdbconbuf[0] = 'O';
+	bufptr = gdbconbuf + 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;
+
+		putpacket(gdbconbuf);
+
+	}
+}
+#endif
+static int __init kgdb_opt_gdb(char *s)
+{
+	gdb_enter = 1;
+	return 1;
+}
+static int __init kgdb_opt_gdbttyS(char *str)
+{
+	gdb_ttyS = simple_strtoul(str,NULL,10);
+	return 1;
+}
+static int __init kgdb_opt_gdbbaud(char *str)
+{
+	gdb_baud = simple_strtoul(str,NULL,10);
+	return 1;
+}
+
+/*
+ * Sequence of these lines has to be maintained because gdb option is a prefix
+ * of the other two options
+ */
+
+__setup("gdbttyS=", kgdb_opt_gdbttyS);
+__setup("gdbbaud=", kgdb_opt_gdbbaud);
+__setup("gdb", kgdb_opt_gdb);
--- diff/drivers/char/gdbserial.c	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/char/gdbserial.c	2002-11-05 15:20:24.000000000 +0000
@@ -0,0 +1,280 @@
+/*
+ * Serial interface GDB stub
+ *
+ * Written (hacked together) by David Grothe (dave@gcom.com)
+ *
+ * Modified by Scott Foehner (sfoehner@engr.sgi.com) to allow connect
+ * on boot-up
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/serial_reg.h>
+#include <linux/serialP.h>
+#include <linux/config.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/termios.h>
+#include <linux/gdb.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/segment.h>
+#include <asm/bitops.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/atomic.h>
+
+#undef	PRNT				/* define for debug printing */
+
+#define	GDB_BUF_SIZE	512		/* power of 2, please */
+
+static char	gdb_buf[GDB_BUF_SIZE] ;
+static int	gdb_buf_in_inx ;
+static atomic_t	gdb_buf_in_cnt ;
+static int	gdb_buf_out_inx ;
+
+extern void	set_debug_traps(void) ;		/* GDB routine */
+extern struct serial_state *	gdb_serial_setup(int ttyS, int baud);
+extern void	shutdown_for_gdb(struct async_struct * info) ;
+						/* in serial.c */
+
+int gdb_irq;
+int gdb_port;
+int gdb_ttyS = 1;	/* Default: ttyS1 */
+int gdb_baud = 38400; 
+int gdb_enter = 0;	/* Default: do not do gdb_hook on boot */
+int gdb_initialized = 0;
+
+static int initialized = -1;
+
+/*
+ * Get a byte from the hardware data buffer and return it
+ */
+static int	read_data_bfr(void)
+{
+    if (inb(gdb_port + UART_LSR) & UART_LSR_DR)
+	return(inb(gdb_port + UART_RX));
+
+    return( -1 ) ;
+
+} /* read_data_bfr */
+
+
+/*
+ * Get a char if available, return -1 if nothing available.
+ * Empty the receive buffer first, then look at the interface hardware.
+ */
+static int	read_char(void)
+{
+    if (atomic_read(&gdb_buf_in_cnt) != 0)	/* intr routine has q'd chars */
+    {
+	int		chr ;
+
+	chr = gdb_buf[gdb_buf_out_inx++] ;
+	gdb_buf_out_inx &= (GDB_BUF_SIZE - 1) ;
+	atomic_dec(&gdb_buf_in_cnt) ;
+	return(chr) ;
+    }
+
+    return(read_data_bfr()) ;	/* read from hardware */
+
+} /* read_char */
+
+/*
+ * Wait until the interface can accept a char, then write it.
+ */
+static void	write_char(int chr)
+{
+    while ( !(inb(gdb_port + UART_LSR) & UART_LSR_THRE) ) ;
+
+    outb(chr, gdb_port+UART_TX);
+
+} /* write_char */
+
+/*
+ * This is the receiver interrupt routine for the GDB stub.
+ * It will receive a limited number of characters of input
+ * from the gdb  host machine and save them up in a buffer.
+ *
+ * When the gdb stub routine getDebugChar() is called it
+ * draws characters out of the buffer until it is empty and
+ * then reads directly from the serial port.
+ *
+ * We do not attempt to write chars from the interrupt routine
+ * since the stubs do all of that via putDebugChar() which
+ * writes one byte after waiting for the interface to become
+ * ready.
+ *
+ * The debug stubs like to run with interrupts disabled since,
+ * after all, they run as a consequence of a breakpoint in
+ * the kernel.
+ *
+ * Perhaps someone who knows more about the tty driver than I
+ * care to learn can make this work for any low level serial
+ * driver.
+ */
+static void gdb_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+    int			 chr ;
+    int			 iir ;
+
+    do
+    {
+	chr = read_data_bfr() ;
+	iir = inb(gdb_port + UART_IIR) ;
+#ifdef PRNT
+	printk("gdb_interrupt: chr=%02x '%c'  after read iir=%02x\n", chr,
+		chr > ' ' && chr < 0x7F ? chr : ' ', iir) ;
+#endif
+	if (chr < 0) continue ;
+
+        if (chr == 3)                   /* Ctrl-C means remote interrupt */
+        {
+            breakpoint();
+            continue ;
+        }
+
+	if (atomic_read(&gdb_buf_in_cnt) >= GDB_BUF_SIZE)
+	{				/* buffer overflow, clear it */
+	    gdb_buf_in_inx = 0 ;
+	    atomic_set(&gdb_buf_in_cnt, 0) ;
+	    gdb_buf_out_inx = 0 ;
+	    break ;
+	}
+
+	gdb_buf[gdb_buf_in_inx++] = chr ;
+	gdb_buf_in_inx &= (GDB_BUF_SIZE - 1) ;
+	atomic_inc(&gdb_buf_in_cnt) ;
+    }
+    while (iir & UART_IIR_RDI);
+
+} /* gdb_interrupt */
+
+/*
+ * Just a NULL routine for testing.
+ */
+void gdb_null(void)
+{
+} /* gdb_null */
+
+
+int     gdb_hook(void)
+{
+    int         retval ;
+    struct serial_state *ser;
+
+#ifdef CONFIG_SMP
+    if (smp_num_cpus > KGDB_MAX_NO_CPUS) { 
+        printk("kgdb: too manu cpus. Cannot enable debugger with more than 8 cpus\n");
+	return (-1);
+    }
+#endif
+
+    /*
+     * Call first time just to get the ser ptr
+     */
+    if((ser = gdb_serial_setup(gdb_ttyS, gdb_baud)) == 0) {
+        printk ("gdb_serial_setup() error");
+        return(-1);
+    }
+
+    gdb_port = ser->port;
+    gdb_irq = ser->irq;
+
+    if (ser->info != NULL)
+    {
+	shutdown_for_gdb(ser->info) ;
+	/*
+	 * Call second time to do the setup now that we have
+	 * shut down the previous user of the interface.
+	 */
+	gdb_serial_setup(gdb_ttyS, gdb_baud) ;
+    }
+
+    retval = request_irq(gdb_irq,
+                         gdb_interrupt,
+                         SA_INTERRUPT,
+                         "GDB-stub", NULL);
+    if (retval == 0)
+        initialized = 1;
+    else
+    {
+        initialized = 0;
+	printk("gdb_hook: request_irq(irq=%d) failed: %d\n", gdb_irq, retval);
+    }
+
+    /*
+     * Call GDB routine to setup the exception vectors for the debugger
+     */
+    set_debug_traps() ;
+
+    /*
+     * Call the breakpoint() routine in GDB to start the debugging
+     * session.
+     */
+    printk("Waiting for connection from remote gdb... ") ;
+    breakpoint() ;
+    gdb_null() ;
+
+    printk("Connected.\n");
+
+    gdb_initialized = 1;
+    return(0) ;
+
+} /* gdb_hook_interrupt2 */
+
+/*
+ * getDebugChar
+ *
+ * This is a GDB stub routine.  It waits for a character from the
+ * serial interface and then returns it.  If there is no serial
+ * interface connection then it returns a bogus value which will
+ * almost certainly cause the system to hang.
+ */
+int	getDebugChar(void)
+{
+    volatile int	chr ;
+
+#ifdef PRNT
+    printk("getDebugChar: ") ;
+#endif
+
+    while ( (chr = read_char()) < 0 ) ;
+
+
+#ifdef PRNT
+    printk("%c\n", chr > ' ' && chr < 0x7F ? chr : ' ') ;
+#endif
+    return(chr) ;
+
+} /* getDebugChar */
+
+/*
+ * putDebugChar
+ *
+ * This is a GDB stub routine.  It waits until the interface is ready
+ * to transmit a char and then sends it.  If there is no serial
+ * interface connection then it simply returns to its caller, having
+ * pretended to send the char.
+ */
+void	putDebugChar(int chr)
+{
+#ifdef PRNT
+    printk("putDebugChar: chr=%02x '%c'\n", chr,
+		chr > ' ' && chr < 0x7F ? chr : ' ') ;
+#endif
+
+    write_char(chr) ;	/* this routine will wait */
+
+} /* putDebugChar */
+
--- diff/include/linux/gdb.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/linux/gdb.h	2002-11-05 15:22:44.000000000 +0000
@@ -0,0 +1,67 @@
+#ifndef _GDB_H_
+#define _GDB_H_
+
+/*
+ * Copyright (C) 2001 Amit S. Kale
+ */
+
+/* gdb locks */
+#define KGDB_MAX_NO_CPUS 8
+
+extern int gdb_enter;	/* 1 = enter debugger on boot */
+extern int gdb_ttyS;
+extern int gdb_baud;
+extern int gdb_initialized;
+
+extern int gdb_hook(void);
+extern void breakpoint(void);
+
+typedef int     gdb_debug_hook(int trapno,
+                               int signo,
+                               int err_code,
+                               struct pt_regs *regs);
+extern gdb_debug_hook  *linux_debug_hook;
+
+#ifdef CONFIG_SMP
+extern spinlock_t kgdb_spinlock;
+extern spinlock_t kgdb_nmispinlock;
+#else
+extern unsigned kgdb_spinlock;
+extern unsigned kgdb_nmispinlock;
+#endif
+
+extern volatile int kgdb_memerr_expected;
+
+struct console;
+void gdb_console_write(struct console *co, const char *s,
+				unsigned count);
+void gdb_console_init(void);
+
+extern volatile int procindebug[KGDB_MAX_NO_CPUS];
+
+#define KGDB_ASSERT(message, condition)	do {			\
+	if (!(condition)) {					\
+		printk("kgdb assertion failed: %s\n", message); \
+		asm ("int $0x3");				\
+	}							\
+} while (0)
+
+#ifdef CONFIG_KERNEL_ASSERTS
+#define KERNEL_ASSERT(message, condition) KGDB_ASSERT(message, condition)
+#else
+#define KERNEL_ASSERT(message, condition)
+#endif
+
+#define KA_VALID_ERRNO(errno) ((errno) > 0 && (errno) <= EMEDIUMTYPE)
+
+#define KA_VALID_PTR_ERR(ptr) KA_VALID_ERRNO(-PTR_ERR(ptr))
+
+#define KA_VALID_KPTR(ptr)  (!(ptr) ||	\
+	       ((void *)(ptr) >= (void *)PAGE_OFFSET &&  \
+	       (void *)(ptr) < ERR_PTR(-EMEDIUMTYPE)))
+
+#define KA_VALID_PTRORERR(errptr) (KA_VALID_KPTR(errptr) || KA_VALID_PTR_ERR(errptr))
+
+#define KA_HELD_GKL()	(current->lock_depth >= 0)
+
+#endif /* _GDB_H_ */