+++ /dev/null
- Documentation/Configure.help | 23
- Documentation/i386/gdb-serial.txt | 386 ++++++++++
- Makefile | 4
- arch/i386/Makefile | 6
- arch/i386/config.in | 39 -
- arch/i386/kernel/Makefile | 18
- arch/i386/kernel/entry.S | 27
- arch/i386/kernel/gdbstart.c | 148 ++++
- arch/i386/kernel/gdbstub.c | 1402 ++++++++++++++++++++++++++++++++++++++
- arch/i386/kernel/nmi.c | 30
- arch/i386/kernel/signal.c | 3
- arch/i386/kernel/traps.c | 44 +
- arch/i386/mm/fault.c | 31
- drivers/char/Makefile | 1
- drivers/char/gdbserial.c | 280 +++++++
- drivers/char/serial.c | 147 +++
- drivers/char/tty_io.c | 6
- include/asm-i386/ioctls.h | 1
- include/asm-i386/page.h | 4
- include/asm-i386/processor.h | 3
- include/linux/dcache.h | 1
- include/linux/gdb.h | 63 +
- include/linux/sched.h | 13
- init/main.c | 9
- kernel/ksyms.c | 5
- kernel/sched.c | 18
- 26 files changed, 2679 insertions(+), 33 deletions(-)
-
---- linux-2.4.18-p4smp/arch/i386/config.in~linux-2.4.18-14-kgdb-1.6 2003-07-09 13:14:53.000000000 -0600
-+++ linux-2.4.18-p4smp-braam/arch/i386/config.in 2003-07-09 13:18:12.000000000 -0600
-@@ -456,25 +456,26 @@ mainmenu_option next_comment
- comment 'Kernel hacking'
-
- bool 'Kernel debugging' CONFIG_DEBUG_KERNEL
--if [ "$CONFIG_DEBUG_KERNEL" != "n" ]; then
-- bool ' Compile the kernel with frame pointers' CONFIG_FRAME_POINTER
-- bool ' Use Scan technique for doing stack trace' CONFIG_STACK_TRACE_SCAN
-- if [ "$CONFIG_FRAME_POINTER" = "y" ]; then
-- bool ' Use Frame Pointer Walk technique for doing stack trace' CONFIG_STACK_TRACE_FPTR
-- fi
-- int 'Number of parameters to show in stack trace' CONFIG_STACK_TRACE_PARAM_COUNT 4
-- bool ' Debug high memory support' CONFIG_DEBUG_HIGHMEM
-- bool ' Debug memory allocations' CONFIG_DEBUG_SLAB
-- bool ' Memory mapped I/O debugging' CONFIG_DEBUG_IOVIRT
-- bool ' Magic SysRq key' CONFIG_MAGIC_SYSRQ
-- bool ' Spinlock debugging' CONFIG_DEBUG_SPINLOCK
-- bool ' Kernel Core Dump Facility' CONFIG_MCL_COREDUMP
-- if [ "$CONFIG_MCL_COREDUMP" = "y" ]; then
-- bool ' Reboot using bootimg' CONFIG_BOOTIMG
-- fi
-- bool ' OPROFILE support' CONFIG_OPROFILE
--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
-+ else
-+ bool 'Kernel debugging' CONFIG_DEBUG_KERNEL
-+ if [ "$CONFIG_DEBUG_KERNEL" != "n" ]; then
-+ bool ' Compile the kernel with frame pointers' CONFIG_FRAME_POINTER
-+ bool ' Debug high memory support' CONFIG_DEBUG_HIGHMEM
-+ bool ' Debug memory allocations' CONFIG_DEBUG_SLAB
-+ bool ' Memory mapped I/O debugging' CONFIG_DEBUG_IOVIRT
-+ bool ' Magic SysRq key' CONFIG_MAGIC_SYSRQ
-+ bool ' Spinlock debugging' CONFIG_DEBUG_SPINLOCK
-+ bool ' Kernel Core Dump Facility' CONFIG_MCL_COREDUMP
-+ if [ "$CONFIG_MCL_COREDUMP" = "y" ]; then
-+ bool ' Reboot using bootimg' CONFIG_BOOTIMG
-+ fi
-+ bool ' OPROFILE support' CONFIG_OPROFILE
-+ fi
-+ fi
- endmenu
-
- source lib/Config.in
---- linux-2.4.18-p4smp/arch/i386/kernel/entry.S~linux-2.4.18-14-kgdb-1.6 2003-07-09 13:14:53.000000000 -0600
-+++ linux-2.4.18-p4smp-braam/arch/i386/kernel/entry.S 2003-07-09 13:15:23.000000000 -0600
-@@ -266,7 +266,7 @@ ret_from_exception:
-
- ALIGN
- reschedule:
-- call SYMBOL_NAME(schedule) # test
-+ call SYMBOL_NAME(user_schedule) # test
- jmp ret_from_sys_call
-
- ENTRY(divide_error)
-@@ -404,6 +404,31 @@ ENTRY(spurious_interrupt_bug)
- 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*/
---- /dev/null 2003-01-30 03:24:37.000000000 -0700
-+++ linux-2.4.18-p4smp-braam/arch/i386/kernel/gdbstart.c 2003-07-09 13:15:23.000000000 -0600
-@@ -0,0 +1,148 @@
-+/*
-+ * 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>
-+
-+#define TIOCGDB 0x547F
-+
-+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 */
-+
-+void 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 ;
-+ }
-+ }
-+
-+ fil = open(tty_name, O_RDWR) ;
-+ if (fil < 0)
-+ {
-+ perror(tty_name) ;
-+ return ;
-+ }
-+
-+
-+ 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 ;
-+ }
-+
-+ printf("\nGDB stub successfully activated\n") ;
-+
-+ for (;;)
-+ {
-+ pause() ;
-+ }
-+
-+ if (tcsetattr(fil, TCSANOW, &save_ts) < 0) tty_err("tcsetattr") ;
-+
-+} /* main */
---- /dev/null 2003-01-30 03:24:37.000000000 -0700
-+++ linux-2.4.18-p4smp-braam/arch/i386/kernel/gdbstub.c 2003-07-09 13:15:23.000000000 -0600
-@@ -0,0 +1,1402 @@
-+/*
-+ *
-+ * 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;
-+
-+#if KGDB_MAX_NO_CPUS != 8
-+#error change the definition of slavecpulocks
-+#endif
-+
-+static spinlock_t slavecpulocks[KGDB_MAX_NO_CPUS] = { SPIN_LOCK_UNLOCKED,
-+ SPIN_LOCK_UNLOCKED, SPIN_LOCK_UNLOCKED, SPIN_LOCK_UNLOCKED,
-+ SPIN_LOCK_UNLOCKED, SPIN_LOCK_UNLOCKED, SPIN_LOCK_UNLOCKED,
-+ SPIN_LOCK_UNLOCKED };
-+volatile int procindebug[KGDB_MAX_NO_CPUS];
-+
-+volatile unsigned kgdb_step = 0;
-+
-+volatile unsigned kgdb_lock = 0;
-+
-+enum gdb_bptype
-+{
-+ bp_breakpoint = '0',
-+ bp_hardware_breakpoint,
-+ bp_write_watchpoint,
-+ bp_read_watchpoint,
-+ bp_access_watchpoint
-+};
-+
-+enum gdb_bpstate
-+{
-+ bp_disabled,
-+ bp_enabled
-+};
-+
-+#define BREAK_INSTR_SIZE 1
-+
-+struct gdb_breakpoint
-+{
-+ unsigned int bpt_addr;
-+ unsigned char saved_instr[BREAK_INSTR_SIZE];
-+ enum gdb_bptype type;
-+ enum gdb_bpstate state;
-+};
-+
-+typedef struct gdb_breakpoint gdb_breakpoint_t;
-+
-+#define MAX_BREAKPOINTS 16
-+
-+gdb_breakpoint_t kgdb_break[MAX_BREAKPOINTS];
-+static char gdb_bpt_instr[BREAK_INSTR_SIZE] = {0xcc};
-+
-+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) (®s->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;
-+}
-+
-+static void
-+get_mem (char *addr,
-+ unsigned char *buf,
-+ int count)
-+{
-+ while (count) {
-+ *buf++ = get_char(addr++);
-+ if (kgdb_memerr)
-+ return;
-+ count--;
-+ }
-+}
-+
-+static void
-+set_mem (char *addr,
-+ char *buf,
-+ int count)
-+{
-+ while (count) {
-+ set_char(addr++,*buf++);
-+ if (kgdb_memerr)
-+ return;
-+ count--;
-+ }
-+}
-+
-+/* 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)
-+{
-+ task_t *thread;
-+ thread = find_task_by_pid(pid);
-+ if (thread) {
-+ return thread;
-+ }
-+ thread = &init_task;
-+ do {
-+ if (thread->pid == pid) {
-+ return thread;
-+ }
-+ thread = thread->next_task;
-+ } while (thread != &init_task);
-+ 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;
-+}
-+
-+static int
-+set_break (
-+ unsigned addr)
-+{
-+ int i, breakno = -1;
-+
-+ for (i = 0; i < MAX_BREAKPOINTS; i++) {
-+ if ((kgdb_break[i].state == bp_enabled) &&
-+ (kgdb_break[i].bpt_addr == addr)) {
-+ breakno = -1;
-+ break;
-+ }
-+
-+ if (kgdb_break[i].state == bp_disabled) {
-+ if ((breakno == -1) || (kgdb_break[i].bpt_addr == addr))
-+ breakno = i;
-+ }
-+ }
-+ if (breakno == -1)
-+ return -1;
-+
-+ get_mem((char *)addr,kgdb_break[breakno].saved_instr,BREAK_INSTR_SIZE);
-+ if (kgdb_memerr)
-+ return -1;
-+
-+ set_mem((char *)addr,gdb_bpt_instr,BREAK_INSTR_SIZE);
-+ if (kgdb_memerr)
-+ return -1;
-+
-+ 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 addr)
-+{
-+ int i;
-+
-+ for (i=0; i<MAX_BREAKPOINTS; i++) {
-+ if ((kgdb_break[i].state == bp_enabled) &&
-+ (kgdb_break[i].bpt_addr == addr)) {
-+ set_mem((char *)addr, kgdb_break[i].saved_instr,
-+ BREAK_INSTR_SIZE);
-+ if (kgdb_memerr)
-+ return -1;
-+ kgdb_break[i].state = bp_disabled;
-+ return 0;
-+ }
-+ }
-+ return -1;
-+}
-+
-+static void
-+clear_disabled_break()
-+{
-+ int i;
-+ for (i=0; i<MAX_BREAKPOINTS; i++) {
-+ if (kgdb_break[i].state == bp_disabled)
-+ kgdb_break[i].bpt_addr = 0;
-+ }
-+}
-+
-+void gdb_wait(struct pt_regs *regs)
-+{
-+ unsigned flags;
-+ int processor;
-+
-+ local_irq_save(flags);
-+ processor = smp_processor_id();
-+ procindebug[processor] = 1;
-+ current->thread.kgdbregs = regs;
-+
-+ /* Wait till master processor goes completely into the debugger */
-+ while (!procindebug[kgdb_lock - 1]) {
-+ int i = 10; /* an arbitrary number */
-+
-+ while (--i)
-+ asm volatile ("nop": : : "memory");
-+
-+ }
-+
-+ /* Wait till master processor is done with debugging */
-+ spin_lock(slavecpulocks + processor);
-+ correct_hw_break();
-+
-+ /* Signal the master processor that we are done */
-+ procindebug[processor] = 0;
-+ spin_unlock(slavecpulocks + processor);
-+ 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;
-+ int gdb_regs[NUMREGBYTES/4];
-+ int i;
-+ int dr6;
-+ int ret;
-+ int maxbpt, bpt_done;
-+ unsigned long bptaddr;
-+ struct pt_regs tempregs;
-+#ifdef CONFIG_KGDB_THREAD
-+ int nothreads;
-+ int maxthreads;
-+ int threadid;
-+ threadref thref;
-+ struct task_struct *thread = NULL;
-+#endif
-+ unsigned procid;
-+
-+#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) ;
-+ }
-+
-+ /* Hold kgdb_lock */
-+ procid = smp_processor_id();
-+ while (cmpxchg(&kgdb_lock, 0, (procid + 1)) != 0) {
-+ int i = 25; /* an arbitrary number */
-+
-+ while (--i)
-+ asm volatile ("nop": : : "memory");
-+ }
-+
-+ kgdb_step = 0;
-+
-+ 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(&slavecpulocks[i]);
-+ }
-+
-+ /* spin_lock code is good enough as a barrier so we don't
-+ * need one here */
-+ procindebug[smp_processor_id()] = 1;
-+
-+ /* Master processor is completely in the debugger */
-+
-+ 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, ®s) ;
-+ } 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) {
-+ *(((char *)&tempregs) + i) = '\0';
-+ gdb_regs[_PC] = kgdb_usercode;
-+ } else {
-+ regs_to_gdb_regs(gdb_regs,
-+ usethread->thread.kgdbregs);
-+ }
-+ } else {
-+ gdb_regs[_PC] = 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, ®s) ;
-+ 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) */
-+ /* D Detach from debugger */
-+ case 'c' :
-+ case 's' :
-+ case 'D' :
-+
-+ /* 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;
-+ kgdb_step = 1;
-+ }
-+ if (remcomInBuffer[0] == 'D') {
-+ clear_disabled_break();
-+ strcpy(remcomOutBuffer,"+");
-+ putpacket(remcomOutBuffer);
-+ }
-+
-+ 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) );
-+
-+ procindebug[smp_processor_id()] = 0;
-+
-+ /* Signal the slave processors to quit from
-+ * the debugger */
-+ for (i = 0; i < smp_num_cpus; i++) {
-+ spin_unlock(&slavecpulocks[i]);
-+ }
-+
-+ /* Wait till all the processors have quit
-+ * from the debugger */
-+
-+ for (i = 0; i < smp_num_cpus; i++) {
-+ while (procindebug[i]) {
-+ int j = 10; /* an arbitrary number */
-+
-+ while (--j) {
-+ asm volatile ("nop"
-+ : : : "memory");
-+ }
-+ }
-+ }
-+
-+ /* Release kgdb_lock */
-+ asm volatile (
-+#ifndef CONFIG_X86_OOSTORE
-+ "movb $0,%0"
-+#else
-+ "lock movb $0,%0"
-+#endif
-+ : "=m" (kgdb_lock) : : "memory");
-+
-+ 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;
-+ case 'Z':
-+ case 'z':
-+ ptr = &remcomInBuffer[1];
-+ if (*ptr++ != bp_breakpoint)
-+ break;
-+ if (*(ptr++) != ',') {
-+ strcpy(remcomOutBuffer, "ERROR");
-+ break;
-+ }
-+ hexToInt(&ptr, &addr);
-+ if (remcomInBuffer[0] == 'Z')
-+ ret = set_break(addr);
-+ else
-+ ret = remove_break(addr);
-+
-+ if (ret == 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)
-+{
-+ int i = 0;
-+ /*
-+ * linux_debug_hook is defined in traps.c. We store a pointer
-+ * to our own exception handler into it.
-+ */
-+ linux_debug_hook = handle_exception ;
-+
-+ for (i=0; i<MAX_BREAKPOINTS; i++) {
-+ kgdb_break[i].bpt_addr = 0;
-+ kgdb_break[i].state = bp_disabled;
-+ }
-+
-+ /*
-+ * 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(void)
-+{
-+ 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);
---- linux-2.4.18-p4smp/arch/i386/kernel/Makefile~linux-2.4.18-14-kgdb-1.6 2003-07-09 13:14:53.000000000 -0600
-+++ linux-2.4.18-p4smp-braam/arch/i386/kernel/Makefile 2003-07-09 13:15:23.000000000 -0600
-@@ -10,7 +10,15 @@
- .S.o:
- $(CC) $(AFLAGS) -traditional -c $< -o $*.o
-
--all: kernel.o head.o init_task.o
-+ifeq ($(CONFIG_X86_REMOTE_DEBUG),y)
-+GDBSTART=gdbstart
-+GDBCLEAN= -rm -f gdbstart /sbin/gdbstart
-+else
-+GDBSTART=
-+GDBCLEAN=
-+endif
-+
-+all: kernel.o head.o init_task.o $(GDBSTART)
-
- O_TARGET := kernel.o
-
-@@ -33,6 +41,7 @@ endif
- obj-$(CONFIG_MCA) += mca.o
- obj-$(CONFIG_E820_PROC) += e820.o rpmhelper.o
- obj-$(CONFIG_MTRR) += mtrr.o
-+obj-$(CONFIG_X86_REMOTE_DEBUG) += gdbstub.o
- obj-$(CONFIG_X86_MSR) += msr.o
- obj-$(CONFIG_X86_CPUID) += cpuid.o
- obj-$(CONFIG_MICROCODE) += microcode.o
-@@ -51,4 +60,11 @@ obj-$(CONFIG_ABI) += lcall7.o
- obj-$(CONFIG_MCL_COREDUMP) += crash.o
-
-
-+gdbstart: gdbstart.o
-+ ${HOSTCC} -o gdbstart gdbstart.o
-+gdbstart.o: gdbstart.c
-+ ${HOSTCC} -c -o gdbstart.o gdbstart.c
-+
-+kernelclean: dummy
-+
- include $(TOPDIR)/Rules.make
---- linux-2.4.18-p4smp/arch/i386/kernel/nmi.c~linux-2.4.18-14-kgdb-1.6 2003-07-09 13:14:53.000000000 -0600
-+++ linux-2.4.18-p4smp-braam/arch/i386/kernel/nmi.c 2003-07-09 13:15:23.000000000 -0600
-@@ -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 */
-@@ -347,7 +361,20 @@ void nmi_watchdog_tick (struct pt_regs *
- x86_do_profile(regs->eip);
-
- sum = irq_stat[cpu].apic_timer_irqs;
-+#ifdef CONFIG_X86_REMOTE_DEBUG
-+ if (kgdb_lock) {
-+
-+ /*
-+ * The machine is in kgdb, hold this cpu if already
-+ * not held.
-+ */
-
-+ if (!procindebug[cpu] && kgdb_lock != (cpu + 1)) {
-+ gdb_wait(regs);
-+ }
-+ alert_counter[cpu] = 0;
-+ } else
-+#endif
- if (last_irq_sums[cpu] == sum) {
- /*
- * Ayiee, looks like this CPU is stuck ...
-@@ -355,6 +382,9 @@ void nmi_watchdog_tick (struct pt_regs *
- */
- alert_counter[cpu]++;
- if (alert_counter[cpu] == 5*nmi_hz) {
-+
-+ CHK_REMOTE_DEBUG(2,SIGSEGV,0,regs,)
-+
- spin_lock(&nmi_print_lock);
- /*
- * We are in trouble anyway, lets at least try
---- linux-2.4.18-p4smp/arch/i386/kernel/signal.c~linux-2.4.18-14-kgdb-1.6 2003-07-09 13:14:53.000000000 -0600
-+++ linux-2.4.18-p4smp-braam/arch/i386/kernel/signal.c 2003-07-09 13:15:23.000000000 -0600
-@@ -701,7 +701,8 @@ int do_signal(struct pt_regs *regs, sigs
- * 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, ka, &info, oldset, regs);
---- linux-2.4.18-p4smp/arch/i386/kernel/traps.c~linux-2.4.18-14-kgdb-1.6 2003-07-09 13:14:53.000000000 -0600
-+++ linux-2.4.18-p4smp-braam/arch/i386/kernel/traps.c 2003-07-09 13:19:30.000000000 -0600
-@@ -49,12 +49,33 @@
- #endif
-
- #include <linux/irq.h>
-+#ifdef CONFIG_X86_REMOTE_DEBUG
-+#include <linux/gdb.h>
-+#endif
- #include <linux/module.h>
-
- #ifdef CONFIG_MCL_COREDUMP
- #include <linux/crash.h>
- #endif
-
-+#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);
-@@ -409,6 +430,7 @@ void die(const char * str, struct pt_reg
- bust_spinlocks(1);
- handle_BUG(regs);
- printk("%s: %04lx\n", str, err & 0xffff);
-+ CHK_REMOTE_DEBUG(1,SIGTRAP,err,regs,)
- show_registers(regs);
- if (netdump_func)
- netdump_func(regs);
-@@ -479,6 +501,7 @@ static void inline do_trap(int trapnr, i
- #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); \
- }
-
-@@ -496,7 +519,10 @@ asmlinkage void do_##name(struct pt_regs
- #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) \
-@@ -548,6 +574,7 @@ gp_in_kernel:
- regs->eip = fixup;
- return;
- }
-+ CHK_REMOTE_DEBUG(13,SIGSEGV,error_code,regs,)
- die("general protection fault", regs, error_code);
- }
- }
-@@ -659,7 +686,7 @@ asmlinkage void do_debug(struct pt_regs
- __asm__ __volatile__("movl %%db6,%0" : "=r" (condition));
-
- /* If the user set TF, it's simplest to clear it right away. */
-- if ((eip >=PAGE_OFFSET) && (regs->eflags & TF_MASK))
-+ if ((eip >=PAGE_OFFSET) && (regs->eflags & TF_MASK) && !kgdb_step)
- goto clear_TF;
-
- /* Mask out spurious debug traps due to lazy DR7 setting */
-@@ -675,7 +702,7 @@ asmlinkage void do_debug(struct pt_regs
- tsk->thread.debugreg[6] = condition;
-
- /* Mask out spurious TF errors due to lazy TF clearing */
-- if (condition & DR_STEP) {
-+ if (condition & DR_STEP && !kgdb_step) {
- /*
- * The TF error should be masked out only if the current
- * process is not traced and if the TRAP flag has been set
-@@ -698,11 +725,13 @@ asmlinkage void do_debug(struct pt_regs
- 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
-@@ -712,6 +741,7 @@ clear_dr7:
- __asm__("movl %0,%%db7"
- : /* no output */
- : "r" (0));
-+ CHK_REMOTE_DEBUG(1,SIGTRAP,error_code,regs,)
- return;
-
- debug_vm86:
---- linux-2.4.18-p4smp/arch/i386/Makefile~linux-2.4.18-14-kgdb-1.6 2003-07-09 13:14:53.000000000 -0600
-+++ linux-2.4.18-p4smp-braam/arch/i386/Makefile 2003-07-09 13:15:23.000000000 -0600
-@@ -105,6 +105,11 @@ arch/i386/mm: dummy
- $(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 @@ install: vmlinux
-
- archclean:
- @$(MAKEBOOT) clean
-+ @$(CLEANKERNEL)
-
- archmrproper:
-
---- linux-2.4.18-p4smp/arch/i386/mm/fault.c~linux-2.4.18-14-kgdb-1.6 2003-07-09 13:14:53.000000000 -0600
-+++ linux-2.4.18-p4smp-braam/arch/i386/mm/fault.c 2003-07-09 13:15:23.000000000 -0600
-@@ -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>
-@@ -183,6 +191,15 @@ asmlinkage void do_page_fault(struct pt_
- 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);
-@@ -301,6 +318,19 @@ no_context:
- 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.
-@@ -308,6 +338,7 @@ no_context:
-
- bust_spinlocks(1);
-
-+
- if (address < PAGE_SIZE)
- printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
- else
---- linux-2.4.18-p4smp/Documentation/Configure.help~linux-2.4.18-14-kgdb-1.6 2003-07-09 13:14:53.000000000 -0600
-+++ linux-2.4.18-p4smp-braam/Documentation/Configure.help 2003-07-09 13:15:23.000000000 -0600
-@@ -20274,6 +20274,29 @@ CONFIG_SGIWD93_SCSI
- 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.
-+
- Magic System Request Key support
- CONFIG_MAGIC_SYSRQ
- If you say Y here, you will have some control over the system even
---- /dev/null 2003-01-30 03:24:37.000000000 -0700
-+++ linux-2.4.18-p4smp-braam/Documentation/i386/gdb-serial.txt 2003-07-09 13:15:23.000000000 -0600
-@@ -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.
---- /dev/null 2003-01-30 03:24:37.000000000 -0700
-+++ linux-2.4.18-p4smp-braam/drivers/char/gdbserial.c 2003-07-09 13:15:23.000000000 -0600
-@@ -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 */
-+
---- linux-2.4.18-p4smp/drivers/char/Makefile~linux-2.4.18-14-kgdb-1.6 2003-07-09 13:14:53.000000000 -0600
-+++ linux-2.4.18-p4smp-braam/drivers/char/Makefile 2003-07-09 13:15:23.000000000 -0600
-@@ -142,6 +142,7 @@ ifeq ($(CONFIG_DUMMY_KEYB),y)
- 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
---- linux-2.4.18-p4smp/drivers/char/serial.c~linux-2.4.18-14-kgdb-1.6 2003-07-09 13:14:53.000000000 -0600
-+++ linux-2.4.18-p4smp-braam/drivers/char/serial.c 2003-07-09 13:15:23.000000000 -0600
-@@ -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>
- *
-@@ -66,6 +71,8 @@
- * to waiting processes
- * Sapan Bhatia <sapan@corewars.org>
- *
-+ * 10/00: added console support for kgdb. Amit Kale <akale@veritas.com>
-+ *
- */
-
- static char *serial_version = "5.05c";
-@@ -215,7 +222,7 @@ static char *serial_revdate = "2001-07-0
- #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
-@@ -235,6 +242,9 @@ static char *serial_revdate = "2001-07-0
- #if defined(LOCAL_HEADERS) || (LINUX_VERSION_CODE < 0x020317) /* 2.3.23 */
- #include "serial_compat.h"
- #endif
-+#ifdef CONFIG_X86_REMOTE_DEBUG
-+#include <linux/gdb.h>
-+#endif
-
- #include <asm/system.h>
- #include <asm/io.h>
-@@ -1586,6 +1596,12 @@ static void shutdown(struct async_struct
-
- spin_unlock_irqrestore( &info->irq_spinlock, 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[] = {
-@@ -2698,6 +2714,12 @@ static int rs_ioctl(struct tty_struct *t
- 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;
- }
-@@ -6043,6 +6065,129 @@ void __init serial_console_init(void)
- #endif
-
- /*
-+ * ------------------------------------------------------------
-+ * Serial GDB driver (most in gdbserial.c)
-+ * ------------------------------------------------------------
-+ */
-+
-+#ifdef CONFIG_X86_REMOTE_DEBUG
-+#ifdef CONFIG_GDB_CONSOLE
-+static struct console gdbcons = {
-+ name: "gdb",
-+ write: gdb_console_write,
-+ flags: CON_PRINTBUFFER | CON_ENABLED,
-+ index: -1,
-+};
-+#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:
---- linux-2.4.18-p4smp/drivers/char/tty_io.c~linux-2.4.18-14-kgdb-1.6 2003-07-09 13:14:53.000000000 -0600
-+++ linux-2.4.18-p4smp-braam/drivers/char/tty_io.c 2003-07-09 13:15:23.000000000 -0600
-@@ -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>
-@@ -2233,6 +2236,9 @@ void __init console_init(void)
- #ifdef CONFIG_AU1000_SERIAL_CONSOLE
- au1000_serial_console_init();
- #endif
-+#ifdef CONFIG_GDB_CONSOLE
-+ gdb_console_init();
-+#endif
- #ifdef CONFIG_SERIAL_CONSOLE
- #if (defined(CONFIG_8xx) || defined(CONFIG_8260))
- console_8xx_init();
---- linux-2.4.18-p4smp/include/asm-i386/ioctls.h~linux-2.4.18-14-kgdb-1.6 2003-07-09 13:14:53.000000000 -0600
-+++ linux-2.4.18-p4smp-braam/include/asm-i386/ioctls.h 2003-07-09 13:15:23.000000000 -0600
-@@ -68,6 +68,7 @@
- #define TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */
- #define TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */
- #define FIOQSIZE 0x5460
-+#define TIOCGDB 0x547F /* enable GDB stub mode on this tty */
-
- /* Used for packet mode */
- #define TIOCPKT_DATA 0
---- linux-2.4.18-p4smp/include/asm-i386/page.h~linux-2.4.18-14-kgdb-1.6 2003-07-09 13:14:53.000000000 -0600
-+++ linux-2.4.18-p4smp-braam/include/asm-i386/page.h 2003-07-09 13:15:23.000000000 -0600
-@@ -95,6 +95,9 @@ typedef struct { unsigned long pgprot; }
- * undefined" opcode for parsing in the trap handler.
- */
-
-+#ifdef CONFIG_X86_REMOTE_DEBUG
-+#define BUG() KGDB_ASSERT("BUG", 0)
-+#else
- #if 1 /* Set to zero for a slightly smaller kernel */
- #define BUG() \
- __asm__ __volatile__( "ud2\n" \
-@@ -104,6 +107,7 @@ typedef struct { unsigned long pgprot; }
- #else
- #define BUG() __asm__ __volatile__("ud2\n")
- #endif
-+#endif
-
- #define PAGE_BUG(page) do { \
- BUG(); \
---- linux-2.4.18-p4smp/include/asm-i386/processor.h~linux-2.4.18-14-kgdb-1.6 2003-07-09 13:14:53.000000000 -0600
-+++ linux-2.4.18-p4smp-braam/include/asm-i386/processor.h 2003-07-09 13:20:27.000000000 -0600
-@@ -390,6 +390,9 @@ struct thread_struct {
- /* IO permissions */
- int ioperm;
- unsigned long io_bitmap[IO_BITMAP_SIZE+1];
-+#ifdef CONFIG_X86_REMOTE_DEBUG
-+ struct pt_regs *kgdbregs;
-+#endif
- /* performance counters */
- struct vperfctr *perfctr;
- };
---- linux-2.4.18-p4smp/include/linux/dcache.h~linux-2.4.18-14-kgdb-1.6 2003-07-09 13:14:53.000000000 -0600
-+++ linux-2.4.18-p4smp-braam/include/linux/dcache.h 2003-07-09 13:15:23.000000000 -0600
-@@ -4,6 +4,7 @@
- #ifdef __KERNEL__
-
- #include <asm/atomic.h>
-+#include <linux/gdb.h>
- #include <linux/mount.h>
-
- /*
---- /dev/null 2003-01-30 03:24:37.000000000 -0700
-+++ linux-2.4.18-p4smp-braam/include/linux/gdb.h 2003-07-09 13:15:23.000000000 -0600
-@@ -0,0 +1,63 @@
-+#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;
-+
-+extern volatile unsigned kgdb_lock;
-+
-+extern volatile int kgdb_memerr_expected;
-+
-+extern volatile unsigned kgdb_step;
-+
-+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];
-+
-+void gdb_wait(struct pt_regs *regs);
-+
-+#define KGDB_ASSERT(message, condition) do { \
-+ if (!(condition)) { \
-+ printk("kgdb assertion failed: %s\n", message); \
-+ asm ("int $0x3"); \
-+ } \
-+} while (0)
-+
-+#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))
-+
-+#ifndef CONFIG_SMP
-+#define KA_HELD_GKL() 1
-+#else
-+#define KA_HELD_GKL() (current->lock_depth >= 0)
-+#endif
-+
-+#endif /* _GDB_H_ */
---- linux-2.4.18-p4smp/include/linux/sched.h~linux-2.4.18-14-kgdb-1.6 2003-07-09 13:14:53.000000000 -0600
-+++ linux-2.4.18-p4smp-braam/include/linux/sched.h 2003-07-09 13:15:23.000000000 -0600
-@@ -159,7 +159,9 @@ extern int set_user(uid_t new_ruid, int
-
- #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);
-@@ -1025,6 +1027,15 @@ static inline int need_resched(void)
- return unlikely(current->need_resched);
- }
-
-+static inline void schedule(void)
-+{
-+#ifdef CONFIG_KGDB_THREAD
-+ kern_schedule();
-+#else
-+ do_schedule();
-+#endif
-+}
-+
- #endif /* __KERNEL__ */
-
- #endif
---- linux-2.4.18-p4smp/init/main.c~linux-2.4.18-14-kgdb-1.6 2003-07-09 13:14:53.000000000 -0600
-+++ linux-2.4.18-p4smp-braam/init/main.c 2003-07-09 13:15:23.000000000 -0600
-@@ -57,6 +57,10 @@
- #include <linux/nubus.h>
- #endif
-
-+#ifdef CONFIG_X86_REMOTE_DEBUG
-+#include <linux/gdb.h>
-+#endif
-+
- #ifdef CONFIG_ISAPNP
- #include <linux/isapnp.h>
- #endif
-@@ -476,6 +480,11 @@ asmlinkage void __init start_kernel(void
- * make syscalls (and thus be locked).
- */
- smp_init();
-+#ifdef CONFIG_X86_REMOTE_DEBUG
-+ if (gdb_enter) {
-+ gdb_hook(); /* right at boot time */
-+ }
-+#endif
-
- /* Do the rest non-__init'ed, we're now alive */
- rest_init();
---- linux-2.4.18-p4smp/kernel/ksyms.c~linux-2.4.18-14-kgdb-1.6 2003-07-09 13:14:53.000000000 -0600
-+++ linux-2.4.18-p4smp-braam/kernel/ksyms.c 2003-07-09 13:15:23.000000000 -0600
-@@ -478,7 +478,10 @@ EXPORT_SYMBOL(sleep_on);
- 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(set_user_nice);
---- linux-2.4.18-p4smp/kernel/sched.c~linux-2.4.18-14-kgdb-1.6 2003-07-09 13:14:53.000000000 -0600
-+++ linux-2.4.18-p4smp-braam/kernel/sched.c 2003-07-09 13:15:23.000000000 -0600
-@@ -797,7 +797,7 @@ void scheduling_functions_start_here(voi
- /*
- * 'schedule()' is the main scheduler function.
- */
--asmlinkage void schedule(void)
-+asmlinkage void do_schedule(void)
- {
- task_t *prev, *next;
- runqueue_t *rq;
-@@ -879,6 +879,22 @@ switch_tasks:
- goto need_resched;
- }
-
-+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 = ®s;
-+ 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
---- linux-2.4.18-p4smp/Makefile~linux-2.4.18-14-kgdb-1.6 2003-07-09 13:14:53.000000000 -0600
-+++ linux-2.4.18-p4smp-braam/Makefile 2003-07-09 13:15:23.000000000 -0600
-@@ -101,9 +101,13 @@ CPPFLAGS := -D__KERNEL__ -I$(HPATH)
-
- CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes -Wno-trigraphs -O2 \
- -fno-strict-aliasing -fno-common
-+ifeq ($(CONFIG_X86_REMOTE_DEBUG),y)
-+CFLAGS += -g
-+else
- ifndef CONFIG_FRAME_POINTER
- CFLAGS += -fomit-frame-pointer
- endif
-+endif
- AFLAGS := -D__ASSEMBLY__ $(CPPFLAGS)
-
- ifeq ($(CONFIG_MCL_COREDUMP),y)
-
-_