All of lore.kernel.org
 help / color / mirror / Atom feed
From: Pavel Machek <pavel@suse.cz>
To: trini@kernel.crashing.org,
	"Amit S. Kale" <akale@users.sourceforge.net>,
	kernel list <linux-kernel@vger.kernel.org>
Subject: Split kgdb into "lite" and "normal" parts
Date: Wed, 18 Feb 2004 23:50:10 +0100	[thread overview]
Message-ID: <20040218225010.GH321@elf.ucw.cz> (raw)

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

Hi!

This is based on current CVS version. If you want just basic
functionality, apply core-lite.patch and i386-lite.patch. If you want
all the features, add core.patch and i386.patch.

Amit, this should be "step 1: split" we were talking about. Could you
test it looks sane and add it to the cvs?
							Pavel
-- 
When do you have a heart between your knees?
[Johanka's followup: and *two* hearts?]

[-- Attachment #2: core-lite.patch --]
[-- Type: text/plain, Size: 35384 bytes --]

--- clean.2.5/Makefile	2004-02-05 01:53:53.000000000 +0100
+++ linux-mm/Makefile	2004-02-16 23:09:06.000000000 +0100
@@ -440,6 +440,8 @@
 
 ifndef CONFIG_FRAME_POINTER
 CFLAGS		+= -fomit-frame-pointer
+else
+CFLAGS		+= -fno-omit-frame-pointer
 endif
 
 ifdef CONFIG_DEBUG_INFO
--- clean.2.5/include/linux/debugger.h	2004-02-17 11:38:14.000000000 +0100
+++ linux-mm/include/linux/debugger.h	2004-02-16 23:09:06.000000000 +0100
@@ -0,0 +1,66 @@
+#ifndef _DEBUGGER_H_
+#define _DEBUGGER_H_
+
+/*
+ * Copyright (C) 2003-2004 Amit S. Kale
+ *
+ * Definition switchout for debuggers
+ */
+
+/*
+ * KGDB
+ */
+#ifdef CONFIG_KGDB
+
+typedef int gdb_debug_hook(int exVector, int signo, int err_code,
+                            struct pt_regs *regs);
+extern gdb_debug_hook  *linux_debug_hook;
+#define	CHK_DEBUGGER(trapnr,signr,error_code,regs,after)			\
+    {									\
+	if (linux_debug_hook != (gdb_debug_hook *) NULL && !user_mode(regs)) \
+	{								\
+		(*linux_debug_hook)(trapnr, signr, error_code, regs) ;	\
+		after;							\
+	}								\
+    }
+
+void kgdb_nmihook(int cpu, void *regs);
+static inline void debugger_nmihook(int cpu, void *regs)
+{
+	kgdb_nmihook(cpu, regs);
+}
+
+void kgdb_entry(void);
+static inline void debugger_entry(void)
+{
+	kgdb_entry();
+}
+
+extern int debugger_step;
+extern atomic_t debugger_active;
+
+/*
+ * No debugger in the kernel
+ */
+#else
+
+#define	CHK_DEBUGGER(trapnr,signr,error_code,regs,after)	
+
+static inline void debugger_nmihook(int cpu, void *regs)
+{
+	/* Do nothing */
+}
+
+static inline void debugger_entry(void)
+{
+	/* Do nothing */
+}
+
+#define debugger_step 0
+static const atomic_t debugger_active = { 0 };
+#define debugger_memerr_expected 0
+
+#endif
+
+
+#endif /* _DEBUGGER_H_ */
--- clean.2.5/include/linux/kgdb.h	2004-02-17 11:38:23.000000000 +0100
+++ linux-mm/include/linux/kgdb.h	2004-02-16 23:09:06.000000000 +0100
@@ -0,0 +1,112 @@
+#ifndef _KGDB_H_
+#define _KGDB_H_
+
+/*
+ * Copyright (C) 2001-2004 Amit S. Kale
+ */
+
+#include <linux/ptrace.h>
+#include <asm/kgdb.h>
+#include <linux/spinlock.h>
+#include <asm/atomic.h>
+#include <linux/debugger.h>
+
+/* To enter the debugger explicitly. */
+void breakpoint(void);
+
+#ifndef KGDB_MAX_NO_CPUS
+#if CONFIG_NR_CPUS > 8
+#error KGDB can handle max 8 CPUs
+#endif
+#define KGDB_MAX_NO_CPUS 8
+#endif
+
+extern atomic_t kgdb_setting_breakpoint;
+extern atomic_t kgdb_killed_or_detached;
+extern atomic_t kgdb_might_be_resumed;
+
+extern struct task_struct *kgdb_usethread, *kgdb_contthread;
+
+enum kgdb_bptype
+{
+	bp_breakpoint = '0',
+	bp_hardware_breakpoint,
+	bp_write_watchpoint,
+	bp_read_watchpoint,
+	bp_access_watchpoint
+};
+
+enum kgdb_bpstate
+{
+       bp_disabled,
+       bp_enabled
+};
+
+struct kgdb_bkpt
+{
+       unsigned long		bpt_addr;
+       unsigned char		saved_instr[BREAK_INSTR_SIZE];
+       enum kgdb_bptype		type;
+       enum kgdb_bpstate	state;
+};
+
+#ifndef BREAK_INSTR_SIZE
+#error BREAK_INSTR_SIZE  needed by kgdb
+#endif
+
+#ifndef MAX_BREAKPOINTS
+#define MAX_BREAKPOINTS        16
+#endif
+
+#define KGDB_HW_BREAKPOINT          1
+
+/* These are functions that the arch specific code can, and in some cases
+ * must, provide. */
+extern int kgdb_arch_init(void);
+extern void regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs);
+extern void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs,struct task_struct *p);
+extern void gdb_regs_to_regs(unsigned long *gdb_regs, struct pt_regs *regs);
+extern void kgdb_printexceptioninfo(int exceptionNo, int errorcode,
+		char *buffer);
+extern void kgdb_disable_hw_debug(struct pt_regs *regs);
+extern void kgdb_post_master_code(struct pt_regs *regs, int eVector,
+		int err_code);
+extern int kgdb_arch_handle_exception(int vector, int signo, int err_code,
+		char *InBuffer, char *outBuffer, struct pt_regs *regs);
+extern int kgdb_arch_set_break(unsigned long addr, int type);
+extern int kgdb_arch_remove_break(unsigned long addr, int type);
+extern void kgdb_correct_hw_break(void);
+extern void kgdb_shadowinfo(struct pt_regs *regs, char *buffer, unsigned threadid);
+extern struct task_struct *kgdb_get_shadow_thread(struct pt_regs *regs,
+		int threadid);
+extern struct pt_regs *kgdb_shadow_regs(struct pt_regs *regs, int threadid);
+
+struct kgdb_arch {
+	unsigned char gdb_bpt_instr[BREAK_INSTR_SIZE];
+	unsigned long flags;
+	unsigned shadowth;
+};			
+
+/* Thread reference */
+typedef unsigned char threadref[8];
+
+struct kgdb_serial {
+	int (*read_char)(void);
+	void (*write_char)(int);
+	void (*flush)(void);
+	int (*hook)(void);
+};
+
+extern struct kgdb_serial *kgdb_serial;
+extern struct kgdb_arch arch_kgdb_ops;
+extern int kgdb_initialized;
+
+struct uart_port;
+
+extern void kgdb8250_add_port(int i, struct uart_port *serial_req);
+
+int kgdb_hex2long(char **ptr, long *longValue);
+char *kgdb_mem2hex(char *mem, char *buf, int count);
+char *kgdb_hex2mem(char *buf, char *mem, int count);
+
+#endif /* _KGDB_H_ */
--- clean.2.5/init/main.c	2004-02-05 01:54:30.000000000 +0100
+++ linux-mm/init/main.c	2004-02-16 23:09:06.000000000 +0100
@@ -39,6 +39,7 @@
 #include <linux/writeback.h>
 #include <linux/cpu.h>
 #include <linux/efi.h>
+#include <linux/debugger.h>
 
 #include <asm/io.h>
 #include <asm/bugs.h>
@@ -580,6 +581,7 @@
 	do_pre_smp_initcalls();
 
 	smp_init();
+	debugger_entry();
 	do_basic_setup();
 
 	prepare_namespace();
--- clean.2.5/kernel/Makefile	2003-10-09 00:14:41.000000000 +0200
+++ linux-mm/kernel/Makefile	2004-02-16 23:09:06.000000000 +0100
@@ -19,6 +19,7 @@
 obj-$(CONFIG_COMPAT) += compat.o
 obj-$(CONFIG_IKCONFIG) += configs.o
 obj-$(CONFIG_IKCONFIG_PROC) += configs.o
+obj-$(CONFIG_KGDB) += kgdbstub.o
 
 ifneq ($(CONFIG_IA64),y)
 # According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
--- clean.2.5/kernel/kgdbstub.c	2004-02-17 11:38:39.000000000 +0100
+++ linux-mm/kernel/kgdbstub.c	2004-02-17 23:23:05.000000000 +0100
@@ -0,0 +1,1207 @@
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+/*
+ * Copyright (C) 2000-2001 VERITAS Software Corporation.
+ * Copyright (C) 2002-2004 Timesys Corporation
+ * Copyright (C) 2003-2004 Amit S. Kale
+ * Copyright (C) 2004 Pavel Machek <pavel@suse.cz>
+ *
+ * Restructured KGDB for 2.6 kernels.
+ * thread support, support for multiple processors,support for ia-32(x86) 
+ * hardware debugging, Console support, handling nmi watchdog
+ * - Amit S. Kale ( amitkale@emsyssoft.com )
+ *
+ * Several enhancements by George Anzinger <george@mvista.com>
+ * Generic KGDB Support
+ * Implemented by Anurekh Saxena (anurekh.saxena@timesys.com)
+ * 
+ * Contributor:     Lake Stevens Instrument Division
+ * Written by:      Glenn Engel
+ *  
+ * Modified for 386 by Jim Kingdon, Cygnus Support.
+ * Origianl kgdb, compatibility with 2.1.xx kernel by David Grothe <dave@gcom.com>
+ * Integrated into 2.2.5 kernel by Tigran Aivazian <tigran@sco.com>
+ */
+
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <asm/system.h>
+#include <asm/ptrace.h>
+#include <asm/uaccess.h>
+#include <linux/kgdb.h>
+#include <asm/atomic.h>
+#include <linux/notifier.h>
+#include <linux/module.h>
+#include <asm/cacheflush.h>
+#include <linux/init.h>
+
+extern int pid_max;
+
+#define BUF_THREAD_ID_SIZE 16
+
+/*
+ * kgdb_initialized indicates that kgdb is setup and is all ready to serve
+ * breakpoints and other kernel exceptions. kgdb_connected indicates that kgdb
+ * has connected to kgdb.
+ */
+int kgdb_initialized = 0;
+static volatile int kgdb_connected;
+
+/* If non-zero, wait for a gdb connection when kgdb_entry is called */
+int kgdb_enter = 0;
+
+/* Set to 1 to make kgdb allow access to user addresses. Can be set from gdb
+ * also at runtime. */
+int kgdb_useraccess = 0;
+
+struct kgdb_serial *kgdb_serial;
+
+/*
+ * Holds information about breakpoints in a kernel. These breakpoints are
+ * added and removed by gdb.
+ */
+struct kgdb_bkpt kgdb_break[MAX_BREAKPOINTS];
+
+struct kgdb_arch *kgdb_ops = &arch_kgdb_ops;
+
+static const char hexchars[] = "0123456789abcdef";
+
+static spinlock_t slavecpulocks[KGDB_MAX_NO_CPUS];
+static volatile int procindebug[KGDB_MAX_NO_CPUS];
+atomic_t kgdb_setting_breakpoint;
+atomic_t kgdb_killed_or_detached;
+atomic_t kgdb_might_be_resumed;
+struct task_struct *kgdb_usethread, *kgdb_contthread;
+
+int debugger_step;
+atomic_t debugger_active;
+
+/* This will point to kgdb_handle_exception by default.
+ * The architecture code can override this in its init function
+ */
+gdb_debug_hook *linux_debug_hook;
+
+static char remcomInBuffer[BUFMAX];
+static char remcomOutBuffer[BUFMAX];
+
+/*
+ * The following are the stub functions for code which is arch specific
+ * and can be omitted on some arches
+ * This function will handle the initalization of any architecture specific
+ * hooks.  If there is a suitable early output driver, kgdb_serial
+ * can be pointed at it now.
+ */
+int __attribute__ ((weak))
+kgdb_arch_init(void)
+{
+	return 0;
+}
+
+void __attribute__ ((weak))
+regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+{
+}
+
+void __attribute__ ((weak))
+sleeping_thread_to_gdb_regs(unsigned long *gdb_regs,struct task_struct *p)
+{
+}
+
+void __attribute__ ((weak))
+gdb_regs_to_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+{
+}
+
+void __attribute__ ((weak))
+kgdb_printexceptioninfo(int exceptionNo, int errorcode, char *buffer)
+{
+}
+
+void __attribute__ ((weak))
+kgdb_disable_hw_debug(struct pt_regs *regs)
+{
+}
+
+void __attribute__ ((weak))
+kgdb_post_master_code(struct pt_regs *regs, int eVector, int err_code)
+{
+}
+
+/*
+ * Handle any additional commands.  This must handle the 'c' and 's'
+ * command packets.
+ * Return -1 to loop over other commands, and 0 to exit from KGDB
+ */
+int __attribute__ ((weak))
+kgdb_arch_handle_exception(int vector, int signo, int err_code, char *InBuffer,
+		char *outBuffer, struct pt_regs *regs)
+{
+	return 0;
+}
+
+int __attribute__ ((weak))
+kgdb_arch_set_break(unsigned long addr, int type)
+{
+	return 0;
+}
+
+int __attribute__ ((weak))
+kgdb_arch_remove_break(unsigned long addr, int type)
+{
+	return 0;
+}
+
+void __attribute__ ((weak))
+kgdb_correct_hw_break(void)
+{
+}
+
+void __attribute__ ((weak))
+kgdb_shadowinfo(struct pt_regs *regs, char *buffer, unsigned threadid)
+{
+}
+
+struct task_struct __attribute__ ((weak))
+*kgdb_get_shadow_thread(struct pt_regs *regs, int threadid)
+{
+	return NULL;
+}
+
+struct pt_regs __attribute__ ((weak))
+*kgdb_shadow_regs(struct pt_regs *regs, int threadid)
+{
+	return NULL;
+}
+
+static int hex(char ch)
+{
+	if ((ch >= 'a') && (ch <= 'f'))
+		return (ch - 'a' + 10);
+	if ((ch >= '0') && (ch <= '9'))
+		return (ch - '0');
+	if ((ch >= 'A') && (ch <= 'F'))
+		return (ch - 'A' + 10);
+	return (-1);
+}
+
+/* scan for the sequence $<data>#<checksum>	*/
+static void 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 = (kgdb_serial->read_char() & 0x7f)) != '$');
+		checksum = 0;
+		xmitcsum = -1;
+
+		count = 0;
+
+		/* now, read until a # or end of buffer is found */
+		while (count < (BUFMAX - 1)) {
+			ch = kgdb_serial->read_char() & 0x7f;
+			if (ch == '#')
+				break;
+			checksum = checksum + ch;
+			buffer[count] = ch;
+			count = count + 1;
+		}
+		buffer[count] = 0;
+
+		if (ch == '#') {
+			xmitcsum = hex(kgdb_serial->read_char() & 0x7f) << 4;
+			xmitcsum += hex(kgdb_serial->read_char() & 0x7f);
+
+			if (checksum != xmitcsum)
+				kgdb_serial->write_char('-');	/* failed checksum */
+			else {
+				kgdb_serial->write_char('+');	/* successful transfer */
+				/* if a sequence char is present, reply the sequence ID */
+				if (buffer[2] == ':') {
+					kgdb_serial->write_char(buffer[0]);
+					kgdb_serial->write_char(buffer[1]);
+					/* remove sequence chars from buffer */
+					count = strlen(buffer);
+					for (i = 3; i <= count; i++)
+						buffer[i - 3] = buffer[i];
+				}
+			}
+			if (kgdb_serial->flush)
+				kgdb_serial->flush();
+		}
+	} while (checksum != xmitcsum);
+}
+
+/*
+ * Send the packet in buffer.
+ * Check for gdb connection if asked for.
+ */
+static void putpacket(char *buffer, int checkconnect)
+{
+	unsigned char checksum;
+	int count;
+	char ch;
+	static char gdbseq[] = "$Hc-1#09";
+	int i;
+	int send_count;
+
+	/*  $<packet info>#<checksum>. */
+	do {
+		kgdb_serial->write_char('$');
+		checksum = 0;
+		count = 0;
+		send_count = 0;
+
+		while ((ch = buffer[count])) {
+			kgdb_serial->write_char(ch);
+			checksum += ch;
+			count ++;
+			send_count ++;
+		}
+
+		kgdb_serial->write_char('#');
+		kgdb_serial->write_char(hexchars[checksum >> 4]);
+		kgdb_serial->write_char(hexchars[checksum % 16]);
+		if (kgdb_serial->flush)
+			kgdb_serial->flush();
+
+		i = 0;
+		while ((ch = kgdb_serial->read_char()) == gdbseq[i++] &&
+		       checkconnect) {
+			if (!gdbseq[i]) {
+				kgdb_serial->write_char('+');
+				if (kgdb_serial->flush)
+					kgdb_serial->flush();
+				breakpoint();
+
+				/*
+				 * GDB is available now.
+				 * Retransmit this packet.
+				 */
+				break;
+			}
+		}
+		if (checkconnect && ch == 3) {
+			kgdb_serial->write_char('+');
+			if (kgdb_serial->flush)
+				kgdb_serial->flush();
+			breakpoint();
+		}
+	} while (( ch & 0x7f) != '+');
+
+}
+
+static int get_char(char *addr, unsigned char *data)
+{
+	mm_segment_t fs;
+	int ret = 0;
+	
+	if (!kgdb_useraccess && (unsigned long)addr < TASK_SIZE) {
+		return -EINVAL;
+	}
+	wmb();
+	fs = get_fs();
+	set_fs(KERNEL_DS);
+	
+	if (get_user(*data, addr) != 0) {
+		ret = -EFAULT;
+	}
+	
+	set_fs(fs);
+	return ret;
+}
+
+static int set_char(char *addr, int data)
+{
+	mm_segment_t fs;
+	int ret = 0;
+	
+	if (!kgdb_useraccess && (unsigned long)addr < TASK_SIZE) {
+		return -EINVAL;
+	}
+	wmb();
+	fs = get_fs();
+	set_fs(KERNEL_DS);
+
+	if (put_user(data, addr) != 0) {
+		ret = -EFAULT;
+	}
+	
+	set_fs(fs);
+	return ret;
+}
+
+/*
+ * convert the memory pointed to by mem into hex, placing result in buf
+ * return a pointer to the last char put in buf (null). May return an error.
+ */
+char *kgdb_mem2hex(char *mem, char *buf, int count)
+{
+	int i;
+	unsigned char ch;
+	int error;
+	
+	for (i = 0; i < count; i++) {
+
+		if ((error = get_char(mem++, &ch)) < 0)
+			return ERR_PTR(error);
+		
+		*buf++ = hexchars[ch >> 4];
+		*buf++ = hexchars[ch % 16];
+	}
+	*buf = 0;
+	return (buf);
+}
+
+/*
+ * convert the hex array pointed to by buf into binary to be placed in mem
+ * return a pointer to the character AFTER the last byte written
+ * May return an error.
+ */
+char *kgdb_hex2mem(char *buf, char *mem, int count)
+{
+	int i;
+	unsigned char ch;
+	int error;
+	
+	for (i = 0; i < count; i++) {
+		ch = hex(*buf++) << 4;
+		ch = ch + hex(*buf++);
+		if ((error = set_char(mem++, ch)) < 0) 
+			return ERR_PTR(error);
+	}
+	return (mem);
+}
+
+/*
+ * While we find nice hex chars, build a longValue.
+ * Return number of chars processed.
+ */
+int kgdb_hex2long(char **ptr, long *longValue)
+{
+	int numChars = 0;
+	int hexValue;
+
+	*longValue = 0;
+
+	while (**ptr) {
+		hexValue = hex(**ptr);
+		if (hexValue >= 0) {
+			*longValue = (*longValue << 4) | hexValue;
+			numChars++;
+		} else
+			break;
+
+		(*ptr)++;
+	}
+
+	return (numChars);
+}
+
+static inline char *pack_hex_byte(char *pkt, int byte)
+{
+	*pkt++ = hexchars[(byte >> 4) & 0xf];
+	*pkt++ = hexchars[(byte & 0xf)];
+	return pkt;
+}
+
+static inline void error_packet(char *pkt, int error)
+{
+	error = -error;
+	pkt[0] = 'E';
+	pkt[1] = hexchars[(error / 10)];
+	pkt[2] = hexchars[(error % 10)];
+	pkt[3] = '\0';
+}
+
+static void ok_packet(char *pkt)
+{
+	strcpy(pkt, "OK");
+}
+
+static char *pack_threadid(char *pkt, threadref *id)
+{
+	char *limit;
+	unsigned char *altid;
+
+	altid = (unsigned char *) id;
+	limit = pkt + BUF_THREAD_ID_SIZE;
+	while (pkt < limit)
+		pkt = pack_hex_byte(pkt, *altid++);
+
+	return pkt;
+}
+
+void int_to_threadref(threadref *id, int value)
+{
+	unsigned char *scan;
+
+	scan = (unsigned char *) id;
+	{
+		int i = 4;
+		while (i--)
+			*scan++ = 0;
+	}
+	*scan++ = (value >> 24) & 0xff;
+	*scan++ = (value >> 16) & 0xff;
+	*scan++ = (value >> 8) & 0xff;
+	*scan++ = (value & 0xff);
+}
+
+static struct task_struct *getthread(struct pt_regs *regs,int tid)
+{
+	int i;
+	struct list_head *l;
+	struct task_struct *p;
+	struct pid *pid;
+
+	if (tid >= pid_max + num_online_cpus() + kgdb_ops->shadowth) {
+		return NULL;
+	}
+	if (tid >= pid_max + num_online_cpus()) {
+		return kgdb_get_shadow_thread(regs, tid - pid_max -
+				num_online_cpus());
+	}
+	if (tid >= pid_max) {
+		i = 0;
+		for_each_task_pid(0, PIDTYPE_PID, p, l, pid) {
+			if (tid == pid_max + i) {
+				return p;
+			}
+			i++;
+		}
+		return NULL;
+	}
+	if (!tid) {
+		return NULL;
+	}
+	return find_task_by_pid(tid);
+}
+
+#ifdef CONFIG_SMP
+void kgdb_wait(struct pt_regs *regs)
+{
+	unsigned long flags;
+	int processor;
+
+	local_irq_save(flags);
+	processor = smp_processor_id();
+	procindebug[processor] = 1;
+	current->thread.debuggerinfo = regs;
+
+	/* Wait till master processor goes completely into the debugger. FIXME: this looks racy */
+	while (!procindebug[atomic_read(&debugger_active) - 1]) {
+		int i = 10;	/* an arbitrary number */
+
+		while (--i)
+			asm volatile ("nop": : : "memory");
+		barrier();
+	}
+
+	/* Wait till master processor is done with debugging */
+	spin_lock(slavecpulocks + processor);
+
+	/* This has been taken from x86 kgdb implementation and
+	 * will be needed by architectures that have SMP support
+	 */
+	kgdb_correct_hw_break();
+
+	/* Signal the master processor that we are done */
+	procindebug[processor] = 0;
+	spin_unlock(slavecpulocks + processor);
+	local_irq_restore(flags);
+}
+#endif
+
+static int get_mem (char *addr, unsigned char *buf, int count)
+{
+	int error;
+	while (count) {
+		if((error = get_char(addr++, buf)) <  0) 
+			return error;
+		buf++;
+		count--;
+	}
+	return 0;
+}
+
+static int set_mem (char *addr,unsigned char *buf, int count)
+{
+	int error;
+	while (count) {
+		if ((error = set_char(addr++,*buf++)) < 0) 
+			return error;
+		count--;
+	}
+	return 0;
+}
+
+static int set_break (unsigned long addr)
+{
+	int i, breakno = -1;
+	int error;
+
+	for (i = 0; i < MAX_BREAKPOINTS; i++) {
+		if ((kgdb_break[i].state == bp_enabled) &&
+		    (kgdb_break[i].bpt_addr == addr)) {
+			return -EEXIST;
+		}
+
+		if (kgdb_break[i].state == bp_disabled) {
+			if ((breakno == -1) || (kgdb_break[i].bpt_addr == addr))
+				breakno = i;
+		}
+	}
+	if (breakno == -1)
+		return -E2BIG;
+
+	if ((error = get_mem((char *)addr, kgdb_break[breakno].saved_instr,
+				BREAK_INSTR_SIZE)) < 0)
+		return error;
+
+	if ((error = set_mem((char *)addr, kgdb_ops->gdb_bpt_instr,
+					BREAK_INSTR_SIZE)) < 0)
+		return error;
+	flush_cache_range (current->mm, addr, addr + BREAK_INSTR_SIZE);
+	flush_icache_range (addr, addr + BREAK_INSTR_SIZE);
+
+	kgdb_break[breakno].state = bp_enabled;
+	kgdb_break[breakno].type = bp_breakpoint;
+	kgdb_break[breakno].bpt_addr = addr;
+	
+	return 0;
+}	
+
+static int remove_break (unsigned long addr)
+{
+	int i;
+	int error;
+
+	for (i=0; i < MAX_BREAKPOINTS; i++) {
+		if ((kgdb_break[i].state == bp_enabled) &&
+		   (kgdb_break[i].bpt_addr == addr)) {
+			if ((error =set_mem((char *)addr, kgdb_break[i].saved_instr,
+			        BREAK_INSTR_SIZE)) < 0)
+				return error;
+			flush_cache_range (current->mm, addr, addr + BREAK_INSTR_SIZE);
+			flush_icache_range (addr, addr + BREAK_INSTR_SIZE);
+			kgdb_break[i].state = bp_disabled;
+			return 0;
+		}
+	}
+	return -ENOENT;
+}
+
+int remove_all_break(void)
+{
+	int i;
+	int error;
+	for (i=0; i < MAX_BREAKPOINTS; i++) {
+		if(kgdb_break[i].state == bp_enabled) {
+			unsigned long addr = kgdb_break[i].bpt_addr;
+			if ((error = set_mem((char *)addr, kgdb_break[i].saved_instr,
+			       BREAK_INSTR_SIZE)) < 0)
+				return error;
+			flush_cache_range (current->mm, addr, addr + BREAK_INSTR_SIZE);
+			flush_icache_range (addr, addr + BREAK_INSTR_SIZE);
+		}
+		kgdb_break[i].state = bp_disabled;
+	}
+	return 0;
+}
+		
+static inline int shadow_pid(int realpid)
+{
+	if (realpid) {
+		return realpid;
+	}
+	return pid_max + smp_processor_id();
+}
+
+/*
+ * This function does all command procesing for interfacing to gdb.
+ *
+ * Locking hierarchy:
+ *	interface locks, if any (begin_session)
+ *	kgdb lock (debugger_active)
+ *
+ */
+int kgdb_handle_exception(int exVector, int signo, int err_code, 
+                     struct pt_regs *linux_regs)
+{
+	unsigned long length, addr;
+	char *ptr;
+	unsigned long flags;
+	unsigned long gdb_regs[NUMREGBYTES / sizeof (unsigned long)];
+	int i;
+	long threadid;
+	threadref thref;
+	struct task_struct *thread = NULL;
+	unsigned procid;
+	static char tmpstr[256];
+	int numshadowth = num_online_cpus() + kgdb_ops->shadowth;
+	long kgdb_usethreadid = 0;
+	int error = 0;
+
+	/* Panic on recursive debugger calls. */
+	if (atomic_read(&debugger_active) == smp_processor_id() + 1) {
+		return 0;
+	}
+
+	/* 
+	 * Interrupts will be restored by the 'trap return' code, except when
+	 * single stepping.
+	 */
+	local_irq_save(flags);
+	
+	/* Hold debugger_active */
+	procid = smp_processor_id();
+	while (cmpxchg(&atomic_read(&debugger_active), 0, (procid + 1)) != 0) {
+		int i = 25;	/* an arbitrary number */
+
+		while (--i)
+			asm volatile ("nop": : : "memory");
+	}
+	
+	debugger_step = 0;
+
+	current->thread.debuggerinfo = linux_regs;
+
+	kgdb_disable_hw_debug(linux_regs);
+
+	for (i = 0; i < num_online_cpus(); i++) {
+		spin_lock(&slavecpulocks[i]);
+	}
+
+	/* spin_lock code is good enough as a barrier so we don't
+	 * need one here */
+	procindebug[smp_processor_id()] = 1;
+
+	/* Clear the out buffer. */
+	memset(remcomOutBuffer, 0, sizeof(remcomOutBuffer));
+
+	/* Master processor is completely in the debugger */
+	kgdb_post_master_code(linux_regs, exVector, err_code);
+
+	if (atomic_read(&kgdb_killed_or_detached) &&
+	    atomic_read(&kgdb_might_be_resumed)) {
+		getpacket(remcomInBuffer);
+		if(remcomInBuffer[0] == 'H' && remcomInBuffer[1] =='c') {
+			remove_all_break();
+			atomic_set(&kgdb_killed_or_detached, 0);
+			ok_packet(remcomOutBuffer);
+		}
+		else
+			return 1;
+	} else {
+
+		/* reply to host that an exception has occurred */
+		ptr = remcomOutBuffer;
+		*ptr++ = 'T';
+		*ptr++ = hexchars[(signo >> 4) % 16];
+		*ptr++ = hexchars[signo % 16];
+		ptr += strlen(strcpy(ptr, "thread:"));
+		int_to_threadref(&thref, shadow_pid(current->pid));
+		ptr = pack_threadid(ptr, &thref);
+		*ptr++ = ';';
+		*ptr = '\0';
+	}		
+
+	putpacket(remcomOutBuffer, 0);
+	kgdb_connected = 1;
+	
+	kgdb_usethread = current;
+	kgdb_usethreadid = shadow_pid(current->pid);
+
+	while (1) {
+		int bpt_type = 0;
+		error = 0;
+
+		/* Clear the out buffer. */
+		memset(remcomOutBuffer, 0, sizeof(remcomOutBuffer));
+
+		getpacket(remcomInBuffer);
+
+		switch (remcomInBuffer[0]) {
+		case '?':
+			remcomOutBuffer[0] = 'S';
+			remcomOutBuffer[1] = hexchars[signo >> 4];
+			remcomOutBuffer[2] = hexchars[signo % 16];
+			break;
+
+		case 'g':	/* return the value of the CPU registers */
+			thread = kgdb_usethread;
+				
+			if (!thread)
+				thread = current;
+			
+			/* All threads that don't have debuggerinfo should be
+			   in __schedule() sleeping, since all other CPUs
+			   are in kgdb_wait, and thus have debuggerinfo. */
+			   
+			if (kgdb_usethreadid >= pid_max + num_online_cpus()) {
+				regs_to_gdb_regs(gdb_regs,
+					kgdb_shadow_regs(linux_regs,
+						kgdb_usethreadid - pid_max -
+						num_online_cpus()));
+			} else if (thread->thread.debuggerinfo) {
+				if ((error = get_char(thread->thread.debuggerinfo,
+					(unsigned char *)gdb_regs)) < 0) {
+					error_packet(remcomOutBuffer, error);
+					break;
+				}
+				regs_to_gdb_regs(gdb_regs,
+					(struct pt_regs *)
+					thread->thread.debuggerinfo);
+			} else {
+				/* Pull stuff saved during 
+				 * switch_to; nothing else is
+				 * accessible (or even particularly relevant).
+				 * This should be enough for a stack trace. */
+				sleeping_thread_to_gdb_regs(gdb_regs, thread);
+			}
+				
+			kgdb_mem2hex((char *) gdb_regs, remcomOutBuffer, NUMREGBYTES);
+			break;
+
+		case 'G':	/* set the value of the CPU registers - return OK */
+			kgdb_hex2mem(&remcomInBuffer[1], (char *) gdb_regs,
+				NUMREGBYTES);
+				
+			if (kgdb_usethread && kgdb_usethread != current)
+				error_packet(remcomOutBuffer, -EINVAL);
+			else {
+				gdb_regs_to_regs(gdb_regs,
+					(struct pt_regs *)
+					current->thread.debuggerinfo);
+				ok_packet(remcomOutBuffer);
+			}
+
+			break;
+
+			/* mAA..AA,LLLL  Read LLLL bytes at address AA..AA */
+		case 'm':
+			ptr = &remcomInBuffer[1];
+			if (kgdb_hex2long(&ptr, &addr) > 0 && *ptr++ == ',' &&
+			    kgdb_hex2long(&ptr, &length) > 0) {
+				if (IS_ERR(ptr = kgdb_mem2hex((char *) addr,
+							remcomOutBuffer,
+							length)))
+					error_packet(remcomOutBuffer,
+							PTR_ERR(ptr));
+			} else
+				error_packet(remcomOutBuffer, -EINVAL);
+			break;
+
+		/* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
+		case 'M':
+			ptr = &remcomInBuffer[1];
+			if (kgdb_hex2long(&ptr, &addr) > 0 && *(ptr++) == ','
+				&& kgdb_hex2long(&ptr, &length) > 0 &&
+				*(ptr++) == ':') {
+				if (IS_ERR(ptr = kgdb_hex2mem(ptr, (char *)addr,
+							length)))
+					error_packet(remcomOutBuffer,
+							PTR_ERR(ptr));
+			} else
+				error_packet(remcomOutBuffer, -EINVAL);
+			break;
+
+			/* kill or detach. KGDB should treat this like a 
+			 * continue.
+			 */
+		case 'D':
+			if ((error = remove_all_break()) < 0) {
+				error_packet(remcomOutBuffer, error);
+			} else {
+				ok_packet(remcomOutBuffer);
+				kgdb_connected = 0;
+			}
+			putpacket(remcomOutBuffer, 0);
+			goto default_handle;
+
+		case 'k':
+			/* Don't care about error from remove_all_break */
+			remove_all_break();
+			kgdb_connected = 0;
+			goto default_handle;
+
+			/* query */
+		case 'q':
+			switch (remcomInBuffer[1]) {
+			case 's':
+			case 'f':
+				if (memcmp(remcomInBuffer+2, "ThreadInfo",10))
+				{
+					error_packet(remcomOutBuffer,
+							-EINVAL);
+					break;
+				}
+				if (remcomInBuffer[1] == 'f') {
+					threadid = 1;
+				}
+				remcomOutBuffer[0] = 'm';
+				ptr = remcomOutBuffer + 1;
+				for (i = 0; i < 32 && threadid < pid_max +
+						numshadowth; threadid++) {
+					thread = getthread(linux_regs,
+							threadid);
+					if (thread) {
+						int_to_threadref(&thref,
+								threadid);
+						pack_threadid(ptr, &thref);
+						ptr += 16;
+						*(ptr++) = ',';
+						i++;
+					}
+				}
+				break;
+
+			case 'C':
+				/* Current thread id */
+				strcpy(remcomOutBuffer, "QC");
+
+				threadid = shadow_pid(current->pid);
+				
+				int_to_threadref(&thref, threadid);
+				pack_threadid(remcomOutBuffer + 2, &thref);
+				break;
+
+			case 'E':
+				/* Print exception info */
+				kgdb_printexceptioninfo(exVector, err_code,
+						remcomOutBuffer);
+				break;
+			case 'T':
+				if (memcmp(remcomInBuffer+1,
+					"ThreadExtraInfo,",16))
+				{
+					error_packet(remcomOutBuffer, -EINVAL);
+					break;
+				}
+				threadid = 0;
+				ptr = remcomInBuffer+17;
+				kgdb_hex2long(&ptr, &threadid);
+				if (!getthread(linux_regs, threadid)) {
+					error_packet(remcomOutBuffer, -EINVAL);
+					break;
+				}
+				if (threadid < pid_max) {
+					kgdb_mem2hex(getthread(linux_regs,
+						threadid)->comm,
+						remcomOutBuffer, 16);
+				} else if (threadid >= pid_max +
+						num_online_cpus()) {
+					kgdb_shadowinfo(linux_regs,
+						remcomOutBuffer,
+						threadid - pid_max -
+						num_online_cpus());
+				} else {
+					sprintf(tmpstr, "Shadow task %d"
+						" for pid 0",
+						(int)(threadid - pid_max));
+					kgdb_mem2hex(tmpstr, remcomOutBuffer,
+							strlen(tmpstr));
+				}
+				break;
+			}
+			break;
+
+			/* task related */
+		case 'H':
+			switch (remcomInBuffer[1]) {
+			case 'g':
+				ptr = &remcomInBuffer[2];
+				kgdb_hex2long(&ptr, &threadid);
+				thread = getthread(linux_regs, threadid);
+				if (!thread && threadid > 0) {
+					error_packet(remcomOutBuffer, -EINVAL);
+					break;
+				}
+				kgdb_usethread = thread;
+				kgdb_usethreadid = threadid;
+				ok_packet(remcomOutBuffer);
+				break;
+
+			case 'c':
+				atomic_set(&kgdb_killed_or_detached, 0);
+				ptr = &remcomInBuffer[2];
+				kgdb_hex2long(&ptr, &threadid);
+				if (!threadid) {
+					kgdb_contthread = 0;
+				} else {
+					thread = getthread(linux_regs, threadid);
+					if (!thread && threadid > 0) {
+						error_packet(remcomOutBuffer,
+								-EINVAL);
+						break;
+					}
+					kgdb_contthread = thread;
+				}
+				ok_packet(remcomOutBuffer);
+				break;
+			}
+			break;
+
+			/* Query thread status */
+		case 'T':
+			ptr = &remcomInBuffer[1];
+			kgdb_hex2long(&ptr, &threadid);
+			thread = getthread(linux_regs, threadid);
+			if (thread)
+				ok_packet(remcomOutBuffer);
+			else
+				error_packet(remcomOutBuffer, -EINVAL);
+			break;
+		case 'z':
+		case 'Z':
+			ptr = &remcomInBuffer[2];
+			if (*(ptr++) != ',') {
+				error_packet(remcomOutBuffer, -EINVAL);
+				break;
+			}
+			kgdb_hex2long(&ptr, &addr);
+			
+			bpt_type = remcomInBuffer[1];
+			if (bpt_type != bp_breakpoint) {
+				if (bpt_type == bp_hardware_breakpoint && 
+				    !(kgdb_ops->flags & KGDB_HW_BREAKPOINT))
+					break;
+
+				/* if set_break is not defined, then
+				 * remove_break does not matter
+				 */
+				if(!(kgdb_ops->flags & KGDB_HW_BREAKPOINT))
+					break;
+			}
+			
+			if (remcomInBuffer[0] == 'Z') {
+				if (bpt_type == bp_breakpoint)
+					error = set_break(addr);
+				else
+					error = kgdb_arch_set_break(addr,
+							bpt_type);
+			}
+			else {
+				if (bpt_type == bp_breakpoint)
+					error = remove_break(addr);
+				else
+					error = kgdb_arch_remove_break(addr,
+							bpt_type);
+			}
+			
+			if (error == 0)
+				ok_packet(remcomOutBuffer);
+			else
+				error_packet(remcomOutBuffer, error);
+			
+			break;
+
+		default:
+		default_handle:
+			error = kgdb_arch_handle_exception(exVector, signo,
+					err_code, remcomInBuffer,
+					remcomOutBuffer, linux_regs);
+
+			if(error >= 0 || remcomInBuffer[0] == 'D' ||
+			    remcomInBuffer[0] == 'k')
+				goto kgdb_exit;
+
+
+		} /* switch */
+
+		/* reply to the request */
+		putpacket(remcomOutBuffer, 0);
+	}
+
+kgdb_exit:
+	procindebug[smp_processor_id()] = 0;	
+	
+	for (i = 0; i < num_online_cpus(); i++) {
+		spin_unlock(&slavecpulocks[i]);
+	}
+	/* Wait till all the processors have quit
+	 * from the debugger 
+	 */
+	for (i = 0; i < num_online_cpus(); i++) { 
+		while (procindebug[i]) {
+			int j = 10; /* an arbitrary number */
+
+			while (--j) {
+				asm volatile ("nop" : : : "memory");
+			}
+			barrier();
+		}
+	}
+
+	/* Free debugger_active */
+	atomic_set(&kgdb_killed_or_detached, 1);
+	atomic_set(&debugger_active, 0);
+	local_irq_restore(flags);
+
+	return error;
+}
+
+/*
+ * GDB places a breakpoint at this function to know dynamically
+ * loaded objects. It's not defined static so that only one instance with this
+ * name exists in the kernel.
+ */
+
+int module_event(struct notifier_block * self, unsigned long val, void * data)
+{
+	return 0;
+}
+
+static struct notifier_block kgdb_module_load_nb = {
+	.notifier_call = module_event,
+};
+
+/* This function will generate a breakpoint exception.  It is used at the
+   beginning of a program to sync up with a debugger and can be used
+   otherwise as a quick means to stop program execution and "break" into
+   the debugger. */
+
+void breakpoint(void)
+{
+	if (!kgdb_initialized) {
+		kgdb_enter = 1;
+		kgdb_entry();
+		if (!kgdb_initialized) {
+			printk("kgdb not enabled. Cannot do breakpoint\n");
+			return;
+		}
+	}
+
+	atomic_set(&kgdb_setting_breakpoint, 1);
+	wmb();
+	BREAKPOINT();
+	wmb();
+	atomic_set(&kgdb_setting_breakpoint, 0);
+}
+
+void kgdb_nmihook(int cpu, void *regs)
+{
+#ifdef CONFIG_SMP
+	if (!procindebug[cpu] && atomic_read(&debugger_active) != (cpu + 1)) {
+		kgdb_wait((struct pt_regs *)regs);
+	}
+#endif
+}
+
+void kgdb_entry(void)
+{
+	int i;
+	
+	if (kgdb_initialized) {
+		/* KGDB was initialized */
+		return;
+	}
+
+	for (i = 0; i < KGDB_MAX_NO_CPUS; i++) 
+		spin_lock_init(&slavecpulocks[i]);
+
+	/* Free debugger_active */
+	atomic_set(&debugger_active, 0);
+
+	/* This flag is used, if gdb has detached and wants to start
+	 * another session
+	 */
+	atomic_set(&kgdb_killed_or_detached, 1);
+	atomic_set(&kgdb_might_be_resumed, 0);
+
+	for (i = 0; i < MAX_BREAKPOINTS; i++) 
+		kgdb_break[i].state = bp_disabled;
+
+	linux_debug_hook = kgdb_handle_exception;
+	
+	/* Let the arch do any initalization it needs to, including
+	 * pointing to a suitable early output device. */
+	kgdb_arch_init();
+
+	/* We can't do much if this fails */
+	register_module_notifier(&kgdb_module_load_nb);
+
+	atomic_set(&kgdb_setting_breakpoint, 0);
+
+	if (!kgdb_serial || kgdb_serial->hook() < 0) {
+		/* KGDB interface isn't ready yet */
+		return;
+	}
+	kgdb_initialized = 1;
+	if (!kgdb_enter) {
+		return;
+	}
+	/*
+	 * Call the breakpoint() routine in GDB to start the debugging
+	 * session
+	 */
+	printk(KERN_CRIT "Waiting for connection from remote gdb... ");
+	breakpoint() ;
+	printk("Connected.\n");
+}
+
+EXPORT_SYMBOL(breakpoint);
+
+static int __init opt_kgdb_enter(char *str)
+{
+	kgdb_enter = 1;
+	return 1;
+}
+
+static int __init opt_gdb(char *str)
+{
+	kgdb_enter = 1;
+	return 1;
+}
+
+/*
+ * These options have been deprecated and are present only to maintain
+ * compatibility with kgdb for 2.4 and earlier kernels.
+ */
+#ifdef CONFIG_KGDB_8250
+extern int kgdb8250_baud;
+extern int kgdb8250_ttyS;
+static int __init opt_gdbttyS(char *str)
+{
+	kgdb8250_ttyS = simple_strtoul(str, NULL, 10);
+	return 1;
+}
+static int __init opt_gdbbaud(char *str)
+{
+	kgdb8250_baud = simple_strtoul(str, NULL, 10);
+	return 1;
+}
+#endif
+
+/*
+ *
+ * Sequence of following lines has to be maintained because gdb option is a
+ * prefix of the other two options
+ */
+
+#ifdef CONFIG_KGDB_8250
+__setup("gdbttyS=", opt_gdbttyS);
+__setup("gdbbaud=", opt_gdbbaud);
+#endif
+__setup("gdb", opt_gdb);
+__setup("kgdbwait", opt_kgdb_enter);
--- clean.2.5/kernel/sched.c	2004-02-05 01:54:30.000000000 +0100
+++ linux-mm/kernel/sched.c	2004-02-16 23:09:06.000000000 +0100
@@ -37,6 +37,7 @@
 #include <linux/rcupdate.h>
 #include <linux/cpu.h>
 #include <linux/percpu.h>
+#include <linux/debugger.h>
 
 #ifdef CONFIG_NUMA
 #define cpu_to_node_mask(cpu) node_to_cpumask(cpu_to_node(cpu))
@@ -2958,6 +2959,8 @@
 #if defined(in_atomic)
 	static unsigned long prev_jiffy;	/* ratelimiting */
 
+	if (atomic_read(&debugger_active))
+		return;
 	if ((in_atomic() || irqs_disabled()) && system_running) {
 		if (time_before(jiffies, prev_jiffy + HZ) && prev_jiffy)
 			return;

[-- Attachment #3: i386-lite.patch --]
[-- Type: text/plain, Size: 17108 bytes --]

--- clean.2.5/arch/i386/Kconfig	2004-02-05 01:53:54.000000000 +0100
+++ linux-mm/arch/i386/Kconfig	2004-02-16 23:15:53.000000000 +0100
@@ -1253,6 +1253,20 @@
 	  If you say Y here, various routines which may sleep will become very
 	  noisy if they are called with a spinlock held.	
 
+config KGDB
+	bool "KGDB: kernel debugging with remote gdb"
+	depends on DEBUG_KERNEL
+	select DEBUG_INFO
+	select FRAME_POINTER
+	help
+	  If you say Y here, it will be possible to remotely debug the
+	  kernel using gdb. This enlarges your kernel image disk size by
+	  several megabytes and requires a machine with more than 128 MB
+	  RAM to avoid excessive linking time. 
+	  Documentation of kernel debugger available at
+	  http://kgdb.sourceforge.net
+	  This is only useful for kernel hackers. If unsure, say N.
+
 config FRAME_POINTER
 	bool "Compile the kernel with frame pointers"
 	help
--- clean.2.5/arch/i386/kernel/Makefile	2004-01-09 20:24:13.000000000 +0100
+++ linux-mm/arch/i386/kernel/Makefile	2004-02-16 23:09:06.000000000 +0100
@@ -31,6 +31,7 @@
 obj-$(CONFIG_ACPI_SRAT) 	+= srat.o
 obj-$(CONFIG_HPET_TIMER) 	+= time_hpet.o
 obj-$(CONFIG_EFI) 		+= efi.o efi_stub.o
+obj-$(CONFIG_KGDB)		+= i386-stub.o
 
 EXTRA_AFLAGS   := -traditional
 
--- clean.2.5/arch/i386/kernel/i386-stub.c	2004-02-17 11:39:06.000000000 +0100
+++ linux-mm/arch/i386/kernel/i386-stub.c	2004-02-16 23:09:06.000000000 +0100
@@ -0,0 +1,373 @@
+/*
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ */
+
+/*
+ * Copyright (C) 2000-2001 VERITAS Software Corporation.
+ */
+/*
+ *  Contributor:     Lake Stevens Instrument Division$
+ *  Written by:      Glenn Engel $
+ *  Updated by:	     Amit Kale<akale@veritas.com>
+ *  Modified for 386 by Jim Kingdon, Cygnus Support.
+ *  Origianl kgdb, compatibility with 2.1.xx kernel by David Grothe <dave@gcom.com>
+ */
+
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <asm/vm86.h>
+#include <asm/system.h>
+#include <asm/ptrace.h>			/* for linux pt_regs struct */
+#include <linux/kgdb.h>
+#ifdef CONFIG_GDB_CONSOLE
+#include <linux/console.h>
+#endif
+#include <linux/init.h>
+#include <linux/debugger.h>
+
+/* Put the error code here just in case the user cares.  */
+int gdb_i386errcode;
+/* Likewise, the vector number here (since GDB only gets the signal
+   number through the usual means, and that's not very specific).  */
+int gdb_i386vector = -1;
+
+#if KGDB_MAX_NO_CPUS != 8
+#error change the definition of slavecpulocks
+#endif
+
+void regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+{
+    gdb_regs[_EAX] =  regs->eax;
+    gdb_regs[_EBX] =  regs->ebx;
+    gdb_regs[_ECX] =  regs->ecx;
+    gdb_regs[_EDX] =  regs->edx;
+    gdb_regs[_ESI] =  regs->esi;
+    gdb_regs[_EDI] =  regs->edi;
+    gdb_regs[_EBP] =  regs->ebp;
+    gdb_regs[ _DS] =  regs->xds;
+    gdb_regs[ _ES] =  regs->xes;
+    gdb_regs[ _PS] =  regs->eflags;
+    gdb_regs[ _CS] =  regs->xcs;
+    gdb_regs[ _PC] =  regs->eip;
+    gdb_regs[_ESP] =  (int) (&regs->esp) ;
+    gdb_regs[ _SS] =  __KERNEL_DS;
+    gdb_regs[ _FS] =  0xFFFF;
+    gdb_regs[ _GS] =  0xFFFF;
+}
+
+void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
+{
+	gdb_regs[_EAX] = 0;
+	gdb_regs[_EBX] = 0;
+	gdb_regs[_ECX] = 0;
+	gdb_regs[_EDX] = 0;
+	gdb_regs[_ESI] = 0;
+	gdb_regs[_EDI] = 0;
+	gdb_regs[_EBP] = *(int *)p->thread.esp;
+	gdb_regs[_DS]  = __KERNEL_DS;
+	gdb_regs[_ES]  = __KERNEL_DS;
+	gdb_regs[_PS]  = 0;
+	gdb_regs[_CS]  = __KERNEL_CS;
+	gdb_regs[_PC]  = p->thread.eip;
+	gdb_regs[_ESP] = p->thread.esp;
+	gdb_regs[_SS]  = __KERNEL_DS;
+	gdb_regs[_FS]  = 0xFFFF;
+	gdb_regs[_GS]  = 0xFFFF;
+}
+
+void gdb_regs_to_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+{
+    regs->eax	=     gdb_regs[_EAX] ;
+    regs->ebx	=     gdb_regs[_EBX] ;
+    regs->ecx	=     gdb_regs[_ECX] ;
+    regs->edx	=     gdb_regs[_EDX] ;
+    regs->esi	=     gdb_regs[_ESI] ;
+    regs->edi	=     gdb_regs[_EDI] ;
+    regs->ebp	=     gdb_regs[_EBP] ;
+    regs->xds	=     gdb_regs[ _DS] ;
+    regs->xes	=     gdb_regs[ _ES] ;
+    regs->eflags=     gdb_regs[ _PS] ;
+    regs->xcs	=     gdb_regs[ _CS] ;
+    regs->eip	=     gdb_regs[ _PC] ;
+#if 0					/* can't change these */
+    regs->esp	=     gdb_regs[_ESP] ;
+    regs->xss	=     gdb_regs[ _SS] ;
+    regs->fs	=     gdb_regs[ _FS] ;
+    regs->gs	=     gdb_regs[ _GS] ;
+#endif
+
+}
+
+struct hw_breakpoint {
+	unsigned enabled;
+	unsigned type;
+	unsigned len;
+	unsigned addr;
+} breakinfo[4] = { {
+enabled:0}, {
+enabled:0}, {
+enabled:0}, {
+enabled:0}};
+
+void kgdb_correct_hw_break(void)
+{
+	int breakno;
+	int correctit;
+	int breakbit;
+	unsigned dr7;
+
+	asm volatile ("movl %%db7, %0\n":"=r" (dr7)
+		      :);
+	do {
+		unsigned addr0, addr1, addr2, addr3;
+		asm volatile ("movl %%db0, %0\n"
+			      "movl %%db1, %1\n"
+			      "movl %%db2, %2\n"
+			      "movl %%db3, %3\n":"=r" (addr0), "=r"(addr1),
+			      "=r"(addr2), "=r"(addr3):);
+	} while (0);
+	correctit = 0;
+	for (breakno = 0; breakno < 3; breakno++) {
+		breakbit = 2 << (breakno << 1);
+		if (!(dr7 & breakbit) && breakinfo[breakno].enabled) {
+			correctit = 1;
+			dr7 |= breakbit;
+			dr7 &= ~(0xf0000 << (breakno << 2));
+			dr7 |= (((breakinfo[breakno].len << 2) |
+				 breakinfo[breakno].type) << 16) <<
+			    (breakno << 2);
+			switch (breakno) {
+			case 0:
+				asm volatile ("movl %0, %%dr0\n"::"r"
+					      (breakinfo[breakno].addr));
+				break;
+
+			case 1:
+				asm volatile ("movl %0, %%dr1\n"::"r"
+					      (breakinfo[breakno].addr));
+				break;
+
+			case 2:
+				asm volatile ("movl %0, %%dr2\n"::"r"
+					      (breakinfo[breakno].addr));
+				break;
+
+			case 3:
+				asm volatile ("movl %0, %%dr3\n"::"r"
+					      (breakinfo[breakno].addr));
+				break;
+			}
+		} else if ((dr7 & breakbit) && !breakinfo[breakno].enabled) {
+			correctit = 1;
+			dr7 &= ~breakbit;
+			dr7 &= ~(0xf0000 << (breakno << 2));
+		}
+	}
+	if (correctit) {
+		asm volatile ("movl %0, %%db7\n"::"r" (dr7));
+	}
+}
+
+int kgdb_remove_hw_break(unsigned long addr, int type)
+{
+	int i, idx = -1;
+	for (i = 0; i < 4; i ++) {
+		if (breakinfo[i].addr == addr && breakinfo[i].enabled) {
+			idx = i;
+			break;
+		}
+	}
+	if (idx == -1)
+		return -1;
+
+	breakinfo[idx].enabled = 0;
+	return 0;
+}
+
+int kgdb_set_hw_break(unsigned long addr, int type)
+{
+	int i, idx = -1;
+	for (i = 0; i < 4; i ++) {
+		if (!breakinfo[i].enabled) {
+			idx = i;
+			break;
+		}
+	}
+	if (idx == -1)
+		return -1;
+
+	breakinfo[idx].enabled = 1;
+	breakinfo[idx].type = type;
+	breakinfo[idx].len = 1;
+	breakinfo[idx].addr = addr;
+	return 0;
+}
+
+int remove_hw_break(unsigned breakno)
+{
+	if (!breakinfo[breakno].enabled) {
+		return -1;
+	}
+	breakinfo[breakno].enabled = 0;
+	return 0;
+}
+
+int set_hw_break(unsigned breakno,
+		 unsigned type, unsigned len, unsigned addr)
+{
+	if (breakinfo[breakno].enabled) {
+		return -1;
+	}
+	breakinfo[breakno].enabled = 1;
+	breakinfo[breakno].type = type;
+	breakinfo[breakno].len = len;
+	breakinfo[breakno].addr = addr;
+	return 0;
+}
+
+void kgdb_printexceptioninfo(int exceptionNo, int errorcode, char *buffer)
+{
+	unsigned	dr6;
+	int		i;
+	switch (exceptionNo) {
+	case 1:		/* debug exception */
+		break;
+	case 3:		/* breakpoint */
+		sprintf(buffer, "Software breakpoint");
+		return;
+	default:
+		sprintf(buffer, "Details not available");
+		return;
+	}
+	asm volatile ("movl %%db6, %0\n":"=r" (dr6)
+		      :);
+	if (dr6 & 0x4000) {
+		sprintf(buffer, "Single step");
+		return;
+	}
+	for (i = 0; i < 4; ++i) {
+		if (dr6 & (1 << i)) {
+			sprintf(buffer, "Hardware breakpoint %d", i);
+			return;
+		}
+	}
+	sprintf(buffer, "Unknown trap");
+	return;
+}
+
+void kgdb_disable_hw_debug(struct pt_regs *regs) 
+{
+	/* Disable hardware debugging while we are in kgdb */
+	asm volatile("movl %0,%%db7": /* no output */ : "r"(0));
+}
+
+void kgdb_post_master_code(struct pt_regs *regs, int eVector, int err_code)
+{
+	/* Master processor is completely in the debugger */
+	gdb_i386vector = eVector;
+	gdb_i386errcode = err_code;
+}
+
+int kgdb_arch_handle_exception(int exceptionVector, int signo,
+		int err_code, char *remcomInBuffer, char *remcomOutBuffer,
+		struct pt_regs *linux_regs)
+{
+	long addr, length;
+	long breakno, breaktype;
+	char *ptr;
+	int newPC;
+	int dr6;
+	
+	switch (remcomInBuffer[0]) {
+	case 'c':
+	case 's':
+		if (kgdb_contthread && kgdb_contthread != current) {
+			strcpy(remcomOutBuffer, "E00");
+			break;
+		}
+
+		kgdb_contthread = NULL;
+
+		/* try to read optional parameter, pc unchanged if no parm */
+		ptr = &remcomInBuffer[1];
+		if (kgdb_hex2long(&ptr, &addr)) {
+			linux_regs->eip = addr;
+		} 
+		newPC = linux_regs->eip;
+		
+		/* clear the trace bit */
+		linux_regs->eflags &= 0xfffffeff;
+
+		/* set the trace bit if we're stepping */
+		if (remcomInBuffer[0] == 's') {
+			linux_regs->eflags |= 0x100;
+			debugger_step = 1;
+		}
+
+		asm volatile ("movl %%db6, %0\n" : "=r" (dr6));
+		if (!(dr6 & 0x4000)) {
+			for (breakno = 0; breakno < 4; ++breakno) {
+				if (dr6 & (1 << breakno)) {
+					if (breakinfo[breakno].type == 0) {
+						/* Set restore flag */
+						linux_regs->eflags |= 0x10000;
+						break;
+					}
+				}
+			}
+		}
+		kgdb_correct_hw_break();
+		asm volatile ("movl %0, %%db6\n"::"r" (0));
+
+		return (0);
+
+	case 'Y':
+		ptr = &remcomInBuffer[1];
+		kgdb_hex2long(&ptr, &breakno);
+		ptr++;
+		kgdb_hex2long(&ptr, &breaktype);
+		ptr++;
+		kgdb_hex2long(&ptr, &length);
+		ptr++;
+		kgdb_hex2long(&ptr, &addr);
+		if (set_hw_break(breakno & 0x3, breaktype & 0x3, 
+				 length & 0x3, addr) == 0) {
+			strcpy(remcomOutBuffer, "OK");
+		} else {
+			strcpy(remcomOutBuffer, "ERROR");
+		}
+		break;
+
+		/* Remove hardware breakpoint */
+	case 'y':
+		ptr = &remcomInBuffer[1];
+		kgdb_hex2long(&ptr, &breakno);
+		if (remove_hw_break(breakno & 0x3) == 0) {
+			strcpy(remcomOutBuffer, "OK");
+		} else {
+			strcpy(remcomOutBuffer, "ERROR");
+		}
+		break;
+
+	}		/* switch */
+	return -1; /* this means that we do not want to exit from the handler */
+}
+
+struct kgdb_arch arch_kgdb_ops =  {
+	.gdb_bpt_instr = {0xcc},
+	.flags = KGDB_HW_BREAKPOINT,
+};
--- clean.2.5/arch/i386/kernel/nmi.c	2003-08-10 21:22:30.000000000 +0200
+++ linux-mm/arch/i386/kernel/nmi.c	2004-02-16 23:09:06.000000000 +0100
@@ -25,6 +25,7 @@
 #include <linux/module.h>
 #include <linux/nmi.h>
 #include <linux/sysdev.h>
+#include <linux/debugger.h>
 
 #include <asm/smp.h>
 #include <asm/mtrr.h>
@@ -420,14 +421,25 @@
 	int sum, cpu = smp_processor_id();
 
 	sum = irq_stat[cpu].apic_timer_irqs;
+	if (atomic_read(&debugger_active)) {
 
-	if (last_irq_sums[cpu] == sum) {
+		/*
+		 * The machine is in debugger, hold this cpu if already
+		 * not held.
+		 */
+		debugger_nmihook(cpu, regs);
+		alert_counter[cpu] = 0;
+
+	} else if (last_irq_sums[cpu] == sum) {
 		/*
 		 * Ayiee, looks like this CPU is stuck ...
 		 * wait a few IRQs (5 seconds) before doing the oops ...
 		 */
 		alert_counter[cpu]++;
 		if (alert_counter[cpu] == 5*nmi_hz) {
+
+			CHK_DEBUGGER(2,SIGSEGV,0,regs,)
+
 			spin_lock(&nmi_print_lock);
 			/*
 			 * We are in trouble anyway, lets at least try
--- clean.2.5/arch/i386/kernel/signal.c	2003-11-24 17:08:26.000000000 +0100
+++ linux-mm/arch/i386/kernel/signal.c	2004-02-16 23:09:06.000000000 +0100
@@ -580,7 +580,8 @@
 		 * have been cleared if the watchpoint triggered
 		 * inside the kernel.
 		 */
-		__asm__("movl %0,%%db7"	: : "r" (current->thread.debugreg[7]));
+		if (current->thread.debugreg[7])
+			__asm__("movl %0,%%db7"	: : "r" (current->thread.debugreg[7]));
 
 		/* Whee!  Actually deliver the signal.  */
 		handle_signal(signr, &info, oldset, regs);
--- clean.2.5/arch/i386/kernel/traps.c	2003-10-18 20:26:27.000000000 +0200
+++ linux-mm/arch/i386/kernel/traps.c	2004-02-16 23:09:06.000000000 +0100
@@ -51,6 +51,7 @@
 
 #include <linux/irq.h>
 #include <linux/module.h>
+#include <linux/debugger.h>
 
 #include "mach_traps.h"
 
@@ -256,6 +257,7 @@
 {
 	static int die_counter;
 
+	CHK_DEBUGGER(1,SIGTRAP,err,regs,)
 	console_verbose();
 	spin_lock_irq(&die_lock);
 	bust_spinlocks(1);
@@ -330,6 +332,7 @@
 #define DO_ERROR(trapnr, signr, str, name) \
 asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
 { \
+	CHK_DEBUGGER(trapnr,signr,error_code,regs,)\
 	do_trap(trapnr, signr, str, 0, regs, error_code, NULL); \
 }
 
@@ -347,7 +350,10 @@
 #define DO_VM86_ERROR(trapnr, signr, str, name) \
 asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
 { \
+	CHK_DEBUGGER(trapnr,signr,error_code,regs,goto skip_trap)\
 	do_trap(trapnr, signr, str, 1, regs, error_code, NULL); \
+skip_trap: \
+	return; \
 }
 
 #define DO_VM86_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \
@@ -547,7 +553,7 @@
 	tsk->thread.debugreg[6] = condition;
 
 	/* Mask out spurious TF errors due to lazy TF clearing */
-	if (condition & DR_STEP) {
+	if (condition & DR_STEP && !debugger_step) {
 		/*
 		 * The TF error should be masked out only if the current
 		 * process is not traced and if the TRAP flag has been set
@@ -570,11 +576,13 @@
 	info.si_errno = 0;
 	info.si_code = TRAP_BRKPT;
 	
-	/* If this is a kernel mode trap, save the user PC on entry to 
-	 * the kernel, that's what the debugger can make sense of.
-	 */
-	info.si_addr = ((regs->xcs & 3) == 0) ? (void *)tsk->thread.eip : 
-	                                        (void *)regs->eip;
+
+	/* If this is a kernel mode trap, we need to reset db7 to allow us
+	 * to continue sanely */
+	if ((regs->xcs & 3) == 0)
+		goto clear_dr7;
+
+	info.si_addr = (void *)regs->eip;
 	force_sig_info(SIGTRAP, &info, tsk);
 
 	/* Disable additional traps. They'll be re-enabled when
@@ -584,6 +592,7 @@
 	__asm__("movl %0,%%db7"
 		: /* no output */
 		: "r" (0));
+	CHK_DEBUGGER(1,SIGTRAP,error_code,regs,)
 	return;
 
 debug_vm86:
--- clean.2.5/arch/i386/mm/fault.c	2003-12-21 20:29:03.000000000 +0100
+++ linux-mm/arch/i386/mm/fault.c	2004-02-16 23:09:06.000000000 +0100
@@ -2,6 +2,11 @@
  *  linux/arch/i386/mm/fault.c
  *
  *  Copyright (C) 1995  Linus Torvalds
+ *
+ *  Change History
+ *
+ *	Tigran Aivazian <tigran@sco.com>	Remote debugging support.
+ *
  */
 
 #include <linux/signal.h>
@@ -21,6 +26,7 @@
 #include <linux/vt_kern.h>		/* For unblank_screen() */
 #include <linux/highmem.h>
 #include <linux/module.h>
+#include <linux/debugger.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -399,6 +405,8 @@
  	if (is_prefetch(regs, address))
  		return;
 
+	CHK_DEBUGGER(14, SIGSEGV,error_code, regs,)
+
 /*
  * Oops. The kernel tried to access some bad page. We'll have to
  * terminate things with extreme prejudice.
@@ -406,6 +414,7 @@
 
 	bust_spinlocks(1);
 
+
 	if (address < PAGE_SIZE)
 		printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
 	else


--- clean.2.5/include/asm-i386/kgdb.h	2004-02-17 11:39:24.000000000 +0100
+++ linux-mm/include/asm-i386/kgdb.h	2004-02-16 23:09:06.000000000 +0100
@@ -0,0 +1,49 @@
+#ifndef _ASM_KGDB_H_
+#define _ASM_KGDB_H_
+
+/*
+ * Copyright (C) 2001-2004 Amit S. Kale
+ */
+
+#include <linux/ptrace.h>
+
+/* gdb locks */
+#define KGDB_MAX_NO_CPUS 8
+
+/************************************************************************/
+/* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
+/* at least NUMREGBYTES*2 are needed for register packets */
+/* Longer buffer is needed to list all threads */
+#define BUFMAX 1024
+
+/* Number of bytes of registers.  */
+#define NUMREGBYTES 64
+/*
+ *  Note that this register image is in a different order than
+ *  the register image that Linux produces at interrupt time.
+ *  
+ *  Linux's register image is defined by struct pt_regs in ptrace.h.
+ *  Just why GDB uses a different order is a historical mystery.
+ */
+enum regnames { _EAX,  /* 0 */
+	_ECX,  /* 1 */
+	_EDX,  /* 2 */
+	_EBX,  /* 3 */
+	_ESP,  /* 4 */
+	_EBP,  /* 5 */
+	_ESI,  /* 6 */
+	_EDI,  /* 7 */
+	_PC,   /* 8 also known as eip */
+	_PS,   /* 9 also known as eflags */
+	_CS,   /* 10 */
+	_SS,   /* 11 */
+	_DS,   /* 12 */
+	_ES,   /* 13 */
+	_FS,   /* 14 */
+	_GS    /* 15 */
+};
+
+#define BREAKPOINT() asm("   int $3");
+#define BREAK_INSTR_SIZE       1
+
+#endif /* _ASM_KGDB_H_ */
--- clean.2.5/include/asm-i386/processor.h	2004-01-09 20:24:24.000000000 +0100
+++ linux-mm/include/asm-i386/processor.h	2004-02-16 23:09:06.000000000 +0100
@@ -425,6 +425,8 @@
 	unsigned int		saved_fs, saved_gs;
 /* IO permissions */
 	unsigned long	*io_bitmap_ptr;
+	void *		debuggerinfo;
+
 };
 
 #define INIT_THREAD  {							\

[-- Attachment #4: core.patch --]
[-- Type: text/plain, Size: 3224 bytes --]

--- linux-mm/include/linux/sched.h	2004-02-16 23:18:56.000000000 +0100
+++ clean-mm/include/linux/sched.h	2004-02-16 23:00:15.000000000 +0100
@@ -173,7 +173,9 @@
 
 #define	MAX_SCHEDULE_TIMEOUT	LONG_MAX
 extern signed long FASTCALL(schedule_timeout(signed long timeout));
-asmlinkage void schedule(void);
+asmlinkage void do_schedule(void);
+asmlinkage void kern_schedule(void);
+asmlinkage void kern_do_schedule(struct pt_regs);
 
 struct namespace;
 
@@ -906,6 +908,15 @@
 
 #endif /* CONFIG_SMP */
 
+static inline void schedule(void)
+{
+#ifdef CONFIG_KGDB_THREAD
+	kern_schedule();
+#else
+	do_schedule();
+#endif
+}
+
 #endif /* __KERNEL__ */
 
 #endif
--- linux-mm/kernel/kgdbstub.c	2004-02-17 23:23:05.000000000 +0100
+++ clean-mm/kernel/kgdbstub.c	2004-02-16 23:00:15.000000000 +0100
@@ -48,6 +48,9 @@
 #include <linux/notifier.h>
 #include <linux/module.h>
 #include <asm/cacheflush.h>
+#ifdef CONFIG_KGDB_CONSOLE
+#include <linux/console.h>
+#endif
 #include <linux/init.h>
 
 extern int pid_max;
@@ -1160,7 +1163,68 @@
 	printk("Connected.\n");
 }
 
+#ifdef CONFIG_KGDB_CONSOLE
+char kgdbconbuf[BUFMAX];
+
+void kgdb_console_write(struct console *co, const char *s, unsigned count)
+{
+	int i;
+	int wcount;
+	char *bufptr;
+	unsigned long flags;
+
+	if (!kgdb_connected) {
+		return;
+	}
+	local_irq_save(flags);
+
+	kgdbconbuf[0] = 'O';
+	bufptr = kgdbconbuf + 1;
+	while (count > 0) {
+		if ((count << 1) > (BUFMAX - 2)) {
+			wcount = (BUFMAX - 2) >> 1;
+		} else {
+			wcount = count;
+		}
+		count -= wcount;
+		for (i = 0; i < wcount; i++) {
+			bufptr = pack_hex_byte(bufptr, s[i]);
+		}
+		*bufptr = '\0';
+		s += wcount;
+
+		putpacket(kgdbconbuf, 1);
+
+	}
+	local_irq_restore(flags);
+}
+
+/* Always fail so that kgdb console doesn't become the default console */
+static int __init kgdb_console_setup(struct console *co, char *options)
+{
+	return -1;
+}
+
+static struct console kgdbcons = {
+	.name = "kgdb",
+	.write = kgdb_console_write,
+	.setup = kgdb_console_setup,
+	.flags = CON_PRINTBUFFER | CON_ENABLED,
+	.index = -1,
+};
+
+static int __init kgdb_console_init(void)
+{
+	register_console(&kgdbcons);
+	return 0;
+}
+console_initcall(kgdb_console_init);
+#endif
+
 EXPORT_SYMBOL(breakpoint);
+#ifdef CONFIG_KGDB_THREAD
+EXPORT_SYMBOL(kern_schedule);
+#endif
 
 static int __init opt_kgdb_enter(char *str)
 {
--- linux-mm/kernel/sched.c	2004-02-16 23:09:06.000000000 +0100
+++ clean-mm/kernel/sched.c	2004-02-16 23:00:15.000000000 +0100
@@ -1589,7 +1589,7 @@
 /*
  * schedule() is the main scheduler function.
  */
-asmlinkage void schedule(void)
+asmlinkage void do_schedule(void)
 {
 	long *switch_count;
 	task_t *prev, *next;
@@ -1761,6 +1761,23 @@
 
 EXPORT_SYMBOL(default_wake_function);
 
+asmlinkage void user_schedule(void)
+{
+#ifdef CONFIG_KGDB_THREAD
+	current->thread.debuggerinfo = NULL;
+#endif
+	do_schedule();
+}
+
+#ifdef CONFIG_KGDB_THREAD
+asmlinkage void kern_do_schedule(struct pt_regs regs)
+{
+	current->thread.debuggerinfo = &regs;
+	do_schedule();
+	current->thread.debuggerinfo = NULL;
+}
+#endif
+
 /*
  * The core wakeup function.  Non-exclusive wakeups (nr_exclusive == 0) just
  * wake everything up.  If it's an exclusive wakeup (nr_exclusive == small +ve

[-- Attachment #5: i386.patch --]
[-- Type: text/plain, Size: 3539 bytes --]

--- linux-mm/arch/i386/Kconfig	2004-02-16 23:15:53.000000000 +0100
+++ clean-mm/arch/i386/Kconfig	2004-02-16 23:00:15.000000000 +0100
@@ -1267,6 +1267,23 @@
 	  http://kgdb.sourceforge.net
 	  This is only useful for kernel hackers. If unsure, say N.
 
+config KGDB_THREAD
+	bool "KGDB: Thread analysis"
+	depends on KGDB
+	help
+	  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.
+
+config KGDB_CONSOLE
+	bool "KGDB: Console messages through gdb"
+	depends on KGDB
+	help
+	  If you say Y here, console messages will appear through gdb.
+	  Other consoles such as tty or ttyS will continue to work as usual.
+
 config FRAME_POINTER
 	bool "Compile the kernel with frame pointers"
 	help
--- linux-mm/arch/i386/kernel/entry.S	2004-02-17 23:23:55.000000000 +0100
+++ clean-mm/arch/i386/kernel/entry.S	2004-02-16 23:00:15.000000000 +0100
@@ -226,7 +226,7 @@
 	jz restore_all
 	movl $PREEMPT_ACTIVE,TI_PRE_COUNT(%ebp)
 	sti
-	call schedule
+	call user_schedule
 	movl $0,TI_PRE_COUNT(%ebp)
 	cli
 	jmp need_resched
@@ -308,7 +308,7 @@
 	testb $_TIF_NEED_RESCHED, %cl
 	jz work_notifysig
 work_resched:
-	call schedule
+	call user_schedule
 	cli				# make sure we don't miss an interrupt
 					# setting need_resched or sigpending
 					# between sampling and the iret
@@ -399,7 +399,17 @@
 	ALIGN
 common_interrupt:
 	SAVE_ALL
+	movl %esp, %eax
+/* Create a fake function call followed by a fake function prologue to fool
+ * gdb into believing that this is a normal function call. */
+	pushl EIP(%eax)
+
+common_interrupt_1:
+	pushl %ebp
+	movl %esp, %ebp
+	pushl %eax
 	call do_IRQ
+	addl $12, %esp
 	jmp ret_from_intr
 
 #define BUILD_INTERRUPT(name, nr)	\
@@ -606,6 +616,31 @@
 	pushl $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 sys_restart_syscall	/* 0 - old "setup()" system call, used for restarting */
--- linux-mm/arch/i386/kernel/irq.c	2004-02-17 23:23:55.000000000 +0100
+++ clean-mm/arch/i386/kernel/irq.c	2004-02-16 23:00:15.000000000 +0100
@@ -410,7 +410,7 @@
  * SMP cross-CPU interrupts have their own specific
  * handlers).
  */
-asmlinkage unsigned int do_IRQ(struct pt_regs regs)
+asmlinkage unsigned int do_IRQ(struct pt_regs *regs)
 {	
 	/* 
 	 * We ack quickly, we don't want the irq controller
@@ -422,7 +422,7 @@
 	 * 0 return value means that this irq is already being
 	 * handled by some other CPU. (or is disabled)
 	 */
-	int irq = regs.orig_eax & 0xff; /* high bits used in ret_from_ code  */
+	int irq = regs->orig_eax & 0xff; /* high bits used in ret_from_ code  */
 	irq_desc_t *desc = irq_desc + irq;
 	struct irqaction * action;
 	unsigned int status;
@@ -488,7 +488,7 @@
 		irqreturn_t action_ret;
 
 		spin_unlock(&desc->lock);
-		action_ret = handle_IRQ_event(irq, &regs, action);
+		action_ret = handle_IRQ_event(irq, regs, action);
 		spin_lock(&desc->lock);
 		if (!noirqdebug)
 			note_interrupt(irq, desc, action_ret);

             reply	other threads:[~2004-02-18 22:56 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2004-02-18 22:50 Pavel Machek [this message]
2004-02-19  7:52 ` Split kgdb into "lite" and "normal" parts Amit S. Kale
2004-02-24 21:39   ` Tom Rini
2004-02-24 22:15     ` Pavel Machek
2004-02-24 23:21       ` Tom Rini
2004-02-24 23:27         ` Pavel Machek
2004-02-24 23:38           ` Tom Rini
2004-02-24 23:49             ` Pavel Machek
2004-02-24 23:57               ` Tom Rini
2004-02-25  0:08                 ` Pavel Machek
2004-02-25  7:15                   ` Amit S. Kale
2004-02-25  7:19             ` Amit S. Kale
2004-02-25 15:58               ` Tom Rini
2004-02-25 20:58                 ` Tom Rini

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20040218225010.GH321@elf.ucw.cz \
    --to=pavel@suse.cz \
    --cc=akale@users.sourceforge.net \
    --cc=linux-kernel@vger.kernel.org \
    --cc=trini@kernel.crashing.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.