Signed-off-by: Andy Whitcroft <apw@shadowen.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
----
-
- 25-akpm/Documentation/i386/kgdb/andthen | 100 +
- 25-akpm/Documentation/i386/kgdb/debug-nmi.txt | 37
- 25-akpm/Documentation/i386/kgdb/gdb-globals.txt | 71
- 25-akpm/Documentation/i386/kgdb/gdbinit | 14
- 25-akpm/Documentation/i386/kgdb/gdbinit-modules | 146 +
- 25-akpm/Documentation/i386/kgdb/gdbinit.hw | 117 +
- 25-akpm/Documentation/i386/kgdb/kgdb.txt | 775 +++++++
- 25-akpm/Documentation/i386/kgdb/loadmodule.sh | 78
- 25-akpm/MAINTAINERS | 6
- 25-akpm/arch/i386/Kconfig | 8
- 25-akpm/arch/i386/Kconfig.debug | 2
- 25-akpm/arch/i386/Kconfig.kgdb | 175 +
- 25-akpm/arch/i386/Makefile | 3
- 25-akpm/arch/i386/kernel/Makefile | 1
- 25-akpm/arch/i386/kernel/entry.S | 29
- 25-akpm/arch/i386/kernel/kgdb_stub.c | 2330 ++++++++++++++++++++++++
- 25-akpm/arch/i386/kernel/nmi.c | 25
- 25-akpm/arch/i386/kernel/smp.c | 12
- 25-akpm/arch/i386/kernel/traps.c | 77
- 25-akpm/arch/i386/lib/Makefile | 1
- 25-akpm/arch/i386/lib/kgdb_serial.c | 485 ++++
- 25-akpm/arch/i386/mm/fault.c | 6
- 25-akpm/arch/x86_64/boot/compressed/head.S | 1
- 25-akpm/arch/x86_64/boot/compressed/misc.c | 1
- 25-akpm/drivers/char/keyboard.c | 3
- 25-akpm/drivers/char/sysrq.c | 23
- 25-akpm/drivers/serial/8250.c | 40
- 25-akpm/drivers/serial/serial_core.c | 5
- 25-akpm/include/asm-i386/bugs.h | 21
- 25-akpm/include/asm-i386/kgdb.h | 59
- 25-akpm/include/asm-i386/kgdb_local.h | 102 +
- 25-akpm/include/linux/config.h | 3
- 25-akpm/include/linux/dwarf2-lang.h | 132 +
- 25-akpm/include/linux/dwarf2.h | 738 +++++++
- 25-akpm/include/linux/serial_core.h | 4
- 25-akpm/include/linux/spinlock.h | 12
- 25-akpm/kernel/pid.c | 6
- 25-akpm/kernel/sched.c | 7
- 38 files changed, 5645 insertions(+), 10 deletions(-)
-
-diff -puN arch/i386/Kconfig~kgdb-ga arch/i386/Kconfig
---- 25/arch/i386/Kconfig~kgdb-ga 2004-10-21 14:54:15.256604136 -0700
-+++ 25-akpm/arch/i386/Kconfig 2004-10-21 14:54:15.295598208 -0700
-@@ -1184,6 +1184,14 @@ menu "Executable file formats"
-
- source "fs/Kconfig.binfmt"
-
-+config TRAP_BAD_SYSCALL_EXITS
-+ bool "Debug bad system call exits"
-+ depends on KGDB
-+ help
-+ If you say Y here the kernel will check for system calls which
-+ return without clearing preempt.
-+ default n
+Index: linux/Documentation/i386/kgdb/andthen
+===================================================================
+--- linux.orig/Documentation/i386/kgdb/andthen
++++ linux/Documentation/i386/kgdb/andthen
+@@ -0,0 +1,100 @@
+
- endmenu
-
- source "drivers/Kconfig"
-diff -puN arch/i386/kernel/entry.S~kgdb-ga arch/i386/kernel/entry.S
---- 25/arch/i386/kernel/entry.S~kgdb-ga 2004-10-21 14:54:15.257603984 -0700
-+++ 25-akpm/arch/i386/kernel/entry.S 2004-10-21 14:54:15.296598056 -0700
-@@ -48,6 +48,18 @@
- #include <asm/smp.h>
- #include <asm/page.h>
- #include "irq_vectors.h"
-+ /* We do not recover from a stack overflow, but at least
-+ * we know it happened and should be able to track it down.
-+ */
-+#ifdef CONFIG_STACK_OVERFLOW_TEST
-+#define STACK_OVERFLOW_TEST \
-+ testl $(THREAD_SIZE - 512),%esp; \
-+ jnz 10f; \
-+ call stack_overflow; \
-+10:
-+#else
-+#define STACK_OVERFLOW_TEST
-+#endif
-
- #define nr_syscalls ((syscall_table_size)/4)
-
-@@ -94,7 +106,8 @@ VM_MASK = 0x00020000
- pushl %ebx; \
- movl $(__USER_DS), %edx; \
- movl %edx, %ds; \
-- movl %edx, %es;
-+ movl %edx, %es; \
-+ STACK_OVERFLOW_TEST
-
- #define RESTORE_INT_REGS \
- popl %ebx; \
-@@ -198,6 +211,7 @@ need_resched:
- # sysenter call handler stub
- ENTRY(sysenter_entry)
- movl TSS_sysenter_esp0(%esp),%esp
-+ .globl sysenter_past_esp
- sysenter_past_esp:
- sti
- pushl $(__USER_DS)
-@@ -260,6 +274,19 @@ syscall_exit:
- testw $_TIF_ALLWORK_MASK, %cx # current->work
- jne syscall_exit_work
- restore_all:
-+#ifdef CONFIG_TRAP_BAD_SYSCALL_EXITS
-+ movl EFLAGS(%esp), %eax # mix EFLAGS and CS
-+ movb CS(%esp), %al
-+ testl $(VM_MASK | 3), %eax
-+ jz resume_kernelX # returning to kernel or vm86-space
++define set_andthen
++ set var $thp=0
++ set var $thp=(struct kgdb_and_then_struct *)&kgdb_data[0]
++ set var $at_size = (sizeof kgdb_data)/(sizeof *$thp)
++ set var $at_oc=kgdb_and_then_count
++ set var $at_cc=$at_oc
++end
+
-+ cmpl $0,TI_preempt_count(%ebp) # non-zero preempt_count ?
-+ jz resume_kernelX
++define andthen_next
++ set var $at_cc=$arg0
++end
+
-+ int $3
++define andthen
++ andthen_set_edge
++ if ($at_cc >= $at_oc)
++ printf "Outside window. Window size is %d\n",($at_oc-$at_low)
++ else
++ printf "%d: ",$at_cc
++ output *($thp+($at_cc++ % $at_size ))
++ printf "\n"
++ end
++end
++define andthen_set_edge
++ set var $at_oc=kgdb_and_then_count
++ set var $at_low = $at_oc - $at_size
++ if ($at_low < 0 )
++ set var $at_low = 0
++ end
++ if (( $at_cc > $at_oc) || ($at_cc < $at_low))
++ printf "Count outside of window, setting count to "
++ if ($at_cc >= $at_oc)
++ set var $at_cc = $at_oc
++ else
++ set var $at_cc = $at_low
++ end
++ printf "%d\n",$at_cc
++ end
++end
+
-+resume_kernelX:
-+#endif
- RESTORE_ALL
-
- # perform work that needs to be done immediately before resumption
-diff -puN /dev/null arch/i386/kernel/kgdb_stub.c
---- /dev/null 2003-09-15 06:40:47.000000000 -0700
-+++ 25-akpm/arch/i386/kernel/kgdb_stub.c 2004-10-21 14:54:15.307596384 -0700
-@@ -0,0 +1,2330 @@
-+/*
-+ *
-+ * 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.
-+ *
-+ */
++define beforethat
++ andthen_set_edge
++ if ($at_cc <= $at_low)
++ printf "Outside window. Window size is %d\n",($at_oc-$at_low)
++ else
++ printf "%d: ",$at_cc-1
++ output *($thp+(--$at_cc % $at_size ))
++ printf "\n"
++ end
++end
+
-+/*
-+ * Copyright (c) 2000 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: David Grothe <dave@gcom.com>
-+ * ModuleState: Experimental $
-+ *
-+ * NOTES: See Below $
-+ *
-+ * Modified for 386 by Jim Kingdon, Cygnus Support.
-+ * Compatibility with 2.1.xx kernel by David Grothe <dave@gcom.com>
-+ *
-+ * Changes to allow auto initilization. All that is needed is that it
-+ * be linked with the kernel and a break point (int 3) be executed.
-+ * The header file <asm/kgdb.h> defines BREAKPOINT to allow one to do
-+ * this. It should also be possible, once the interrupt system is up, to
-+ * call putDebugChar("+"). Once this is done, the remote debugger should
-+ * get our attention by sending a ^C in a packet. George Anzinger
-+ * <george@mvista.com>
-+ * Integrated into 2.2.5 kernel by Tigran Aivazian <tigran@sco.com>
-+ * Added thread support, support for multiple processors,
-+ * support for ia-32(x86) hardware debugging.
-+ * 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
-+ *
-+ ****************************************************************************/
-+#define KGDB_VERSION "<20030915.1651.33>"
-+#include <linux/config.h>
-+#include <linux/types.h>
-+#include <asm/string.h> /* for strcpy */
-+#include <linux/kernel.h>
-+#include <linux/sched.h>
-+#include <asm/vm86.h>
-+#include <asm/system.h>
-+#include <asm/ptrace.h> /* for linux pt_regs struct */
-+#include <asm/kgdb_local.h>
-+#include <linux/list.h>
-+#include <asm/atomic.h>
-+#include <asm/processor.h>
-+#include <linux/irq.h>
-+#include <asm/desc.h>
++document andthen_next
++ andthen_next <count>
++ . sets the number of the event to display next. If this event
++ . is not in the event pool, either andthen or beforethat will
++ . correct it to the nearest event pool edge. The event pool
++ . ends at the last event recorded and begins <number of events>
++ . prior to that. If beforethat is used next, it will display
++ . event <count> -1.
++.
++ andthen commands are: set_andthen, andthen_next, andthen and beforethat
++end
+
-+/************************************************************************
-+ *
-+ * external low-level support routines
-+ */
-+typedef void (*Function) (void); /* pointer to a function */
+
-+/* Thread reference */
-+typedef unsigned char threadref[8];
++document andthen
++ andthen
++. displays the next event in the list. <set_andthen> sets up to display
++. the oldest saved event first.
++. <count> (optional) count of the event to display.
++. note the number of events saved is specified at configure time.
++. if events are saved between calls to andthen the index will change
++. but the displayed event will be the next one (unless the event buffer
++. is overrun).
++.
++. andthen commands are: set_andthen, andthen_next, andthen and beforethat
++end
+
-+extern void putDebugChar(int); /* write a single character */
-+extern int getDebugChar(void); /* read and return a single char */
++document set_andthen
++ set_andthen
++. sets up to use the <andthen> and <beforethat> commands.
++. if you have defined your own struct, use the above and
++. then enter the following:
++. p $thp=(struct kgdb_and_then_structX *)&kgdb_data[0]
++. where <kgdb_and_then_structX> is the name of your structure.
++.
++. andthen commands are: set_andthen, andthen_next, andthen and beforethat
++end
+
-+/************************************************************************/
-+/* 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 400
++document beforethat
++ beforethat
++. displays the next prior event in the list. <set_andthen> sets up to
++. display the last occuring event first.
++.
++. note the number of events saved is specified at configure time.
++. if events are saved between calls to beforethat the index will change
++. but the displayed event will be the next one (unless the event buffer
++. is overrun).
++.
++. andthen commands are: set_andthen, andthen_next, andthen and beforethat
++end
+Index: linux/Documentation/i386/kgdb/debug-nmi.txt
+===================================================================
+--- linux.orig/Documentation/i386/kgdb/debug-nmi.txt
++++ linux/Documentation/i386/kgdb/debug-nmi.txt
+@@ -0,0 +1,37 @@
++Subject: Debugging with NMI
++Date: Mon, 12 Jul 1999 11:28:31 -0500
++From: David Grothe <dave@gcom.com>
++Organization: Gcom, Inc
++To: David Grothe <dave@gcom.com>
+
-+char *kgdb_version = KGDB_VERSION;
++Kernel hackers:
+
-+/* debug > 0 prints ill-formed commands in valid packets & checksum errors */
-+int debug_regs = 0; /* set to non-zero to print registers */
++Maybe this is old hat, but it is new to me --
+
-+/* filled in by an external module */
-+char *gdb_module_offsets;
++On an ISA bus machine, if you short out the A1 and B1 pins of an ISA
++slot you will generate an NMI to the CPU. This interrupts even a
++machine that is hung in a loop with interrupts disabled. Used in
++conjunction with kgdb <
++ftp://ftp.gcom.com/pub/linux/src/kgdb-2.3.35/kgdb-2.3.35.tgz > you can
++gain debugger control of a machine that is hung in the kernel! Even
++without kgdb the kernel will print a stack trace so you can find out
++where it was hung.
+
-+static const char hexchars[] = "0123456789abcdef";
++The A1/B1 pins are directly opposite one another and the farthest pins
++towards the bracket end of the ISA bus socket. You can stick a paper
++clip or multi-meter probe between them to short them out.
+
-+/* 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 */
-+};
++I had a spare ISA bus to PC104 bus adapter around. The PC104 end of the
++board consists of two rows of wire wrap pins. So I wired a push button
++between the A1/B1 pins and now have an ISA board that I can stick into
++any ISA bus slot for debugger entry.
+
-+/*************************** ASSEMBLY CODE MACROS *************************/
-+/*
-+ * Put the error code here just in case the user cares.
-+ * Likewise, the vector number here (since GDB only gets the signal
-+ * number through the usual means, and that's not very specific).
-+ * The called_from is the return address so he can tell how we entered kgdb.
-+ * This will allow him to seperate out the various possible entries.
-+ */
-+#define REMOTE_DEBUG 0 /* set != to turn on printing (also available in info) */
++Microsoft has a circuit diagram of a PCI card at
++http://www.microsoft.com/hwdev/DEBUGGING/DMPSW.HTM. If you want to
++build one you will have to mail them and ask for the PAL equations.
++Nobody makes one comercially.
+
-+#define PID_MAX PID_MAX_DEFAULT
++[THIS TIP COMES WITH NO WARRANTY WHATSOEVER. It works for me, but if
++your machine catches fire, it is your problem, not mine.]
+
-+#ifdef CONFIG_SMP
-+void smp_send_nmi_allbutself(void);
-+#define IF_SMP(x) x
-+#undef MAX_NO_CPUS
-+#ifndef CONFIG_NO_KGDB_CPUS
-+#define CONFIG_NO_KGDB_CPUS 2
-+#endif
-+#if CONFIG_NO_KGDB_CPUS > NR_CPUS
-+#define MAX_NO_CPUS NR_CPUS
-+#else
-+#define MAX_NO_CPUS CONFIG_NO_KGDB_CPUS
-+#endif
-+#define hold_init hold_on_sstep: 1,
-+#define MAX_CPU_MASK (unsigned long)((1LL << MAX_NO_CPUS) - 1LL)
-+#define NUM_CPUS num_online_cpus()
-+#else
-+#define IF_SMP(x)
-+#define hold_init
-+#undef MAX_NO_CPUS
-+#define MAX_NO_CPUS 1
-+#define NUM_CPUS 1
-+#endif
-+#define NOCPU (struct task_struct *)0xbad1fbad
-+/* *INDENT-OFF* */
-+struct kgdb_info {
-+ int used_malloc;
-+ void *called_from;
-+ long long entry_tsc;
-+ int errcode;
-+ int vector;
-+ int print_debug_info;
-+#ifdef CONFIG_SMP
-+ int hold_on_sstep;
-+ struct {
-+ volatile struct task_struct *task;
-+ int pid;
-+ int hold;
-+ struct pt_regs *regs;
-+ } cpus_waiting[MAX_NO_CPUS];
-+#endif
-+} kgdb_info = {hold_init print_debug_info:REMOTE_DEBUG, vector:-1};
++-- Dave (the kgdb guy)
+Index: linux/Documentation/i386/kgdb/gdb-globals.txt
+===================================================================
+--- linux.orig/Documentation/i386/kgdb/gdb-globals.txt
++++ linux/Documentation/i386/kgdb/gdb-globals.txt
+@@ -0,0 +1,71 @@
++Sender: akale@veritas.com
++Date: Fri, 23 Jun 2000 19:26:35 +0530
++From: "Amit S. Kale" <akale@veritas.com>
++Organization: Veritas Software (India)
++To: Dave Grothe <dave@gcom.com>, linux-kernel@vger.rutgers.edu
++CC: David Milburn <dmilburn@wirespeed.com>,
++ "Edouard G. Parmelan" <Edouard.Parmelan@quadratec.fr>,
++ ezannoni@cygnus.com, Keith Owens <kaos@ocs.com.au>
++Subject: Re: Module debugging using kgdb
+
-+/* *INDENT-ON* */
++Dave Grothe wrote:
++>
++> Amit:
++>
++> There is a 2.4.0 version of kgdb on our ftp site:
++> ftp://ftp.gcom.com/pub/linux/src/kgdb. I mirrored your version of gdb
++> and loadmodule.sh there.
++>
++> Have a look at the README file and see if I go it right. If not, send
++> me some corrections and I will update it.
++>
++> Does your version of gdb solve the global variable problem?
+
-+#define used_m kgdb_info.used_malloc
-+/*
-+ * This is little area we set aside to contain the stack we
-+ * need to build to allow gdb to call functions. We use one
-+ * per cpu to avoid locking issues. We will do all this work
-+ * with interrupts off so that should take care of the protection
-+ * issues.
-+ */
-+#define LOOKASIDE_SIZE 200 /* should be more than enough */
-+#define MALLOC_MAX 200 /* Max malloc size */
-+struct {
-+ unsigned int esp;
-+ int array[LOOKASIDE_SIZE];
-+} fn_call_lookaside[MAX_NO_CPUS];
++Yes.
++Thanks to Elena Zanoni, gdb (developement version) can now calculate
++correctly addresses of dynamically loaded object files. I have not been
++following gdb developement for sometime and am not sure when symbol
++address calculation fix is going to appear in a gdb stable version.
+
-+static int trap_cpu;
-+static unsigned int OLD_esp;
++Elena, any idea when the fix will make it to a prebuilt gdb from a
++redhat release?
+
-+#define END_OF_LOOKASIDE &fn_call_lookaside[trap_cpu].array[LOOKASIDE_SIZE]
-+#define IF_BIT 0x200
-+#define TF_BIT 0x100
++For the time being I have built a gdb developement version. It can be
++used for module debugging with loadmodule.sh script.
+
-+#define MALLOC_ROUND 8-1
++The problem with calculating of module addresses with previous versions
++of gdb was as follows:
++gdb did not use base address of a section while calculating address of
++a symbol in the section in an object file loaded via 'add-symbol-file'.
++It used address of .text segment instead. Due to this addresses of
++symbols in .data, .bss etc. (e.g. global variables) were calculated incorrectly.
+
-+static char malloc_array[MALLOC_MAX];
-+IF_SMP(static void to_gdb(const char *mess));
-+void *
-+malloc(int size)
-+{
++Above mentioned fix allow gdb to use base address of a segment while
++calculating address of a symbol in it. It adds a parameter '-s' to
++'add-symbol-file' command for specifying base address of a segment.
+
-+ if (size <= (MALLOC_MAX - used_m)) {
-+ int old_used = used_m;
-+ used_m += ((size + MALLOC_ROUND) & (~MALLOC_ROUND));
-+ return &malloc_array[old_used];
-+ } else {
-+ return NULL;
-+ }
-+}
++loadmodule.sh script works as follows.
+
-+/*
-+ * Gdb calls functions by pushing agruments, including a return address
-+ * on the stack and the adjusting EIP to point to the function. The
-+ * whole assumption in GDB is that we are on a different stack than the
-+ * one the "user" i.e. code that hit the break point, is on. This, of
-+ * course is not true in the kernel. Thus various dodges are needed to
-+ * do the call without directly messing with EIP (which we can not change
-+ * as it is just a location and not a register. To adjust it would then
-+ * require that we move every thing below EIP up or down as needed. This
-+ * will not work as we may well have stack relative pointer on the stack
-+ * (such as the pointer to regs, for example).
++1. Copy a module file to target machine.
++2. Load the module on the target machine using insmod with -m parameter.
++insmod produces a module load map which contains base addresses of all
++sections in the module and addresses of symbols in the module file.
++3. Find all sections and their base addresses in the module from
++the module map.
++4. Generate a script that loads the module file. The script uses
++'add-symbol-file' and specifies address of text segment followed by
++addresses of all segments in the module.
+
-+ * So here is what we do:
-+ * We detect gdb attempting to store into the stack area and instead, store
-+ * into the fn_call_lookaside.array at the same relative location as if it
-+ * were the area ESP pointed at. We also trap ESP modifications
-+ * and uses these to adjust fn_call_lookaside.esp. On entry
-+ * fn_call_lookaside.esp will be set to point at the last entry in
-+ * fn_call_lookaside.array. This allows us to check if it has changed, and
-+ * if so, on exit, we add the registers we will use to do the move and a
-+ * trap/ interrupt return exit sequence. We then adjust the eflags in the
-+ * regs array (remember we now have a copy in the fn_call_lookaside.array) to
-+ * kill the interrupt bit, AND we change EIP to point at our set up stub.
-+ * As part of the register set up we preset the registers to point at the
-+ * begining and end of the fn_call_lookaside.array, so all the stub needs to
-+ * do is move words from the array to the stack until ESP= the desired value
-+ * then do the rti. This will then transfer to the desired function with
-+ * all the correct registers. Nifty huh?
-+ */
-+extern asmlinkage void fn_call_stub(void);
-+extern asmlinkage void fn_rtn_stub(void);
-+/* *INDENT-OFF* */
-+__asm__("fn_rtn_stub:\n\t"
-+ "movl %eax,%esp\n\t"
-+ "fn_call_stub:\n\t"
-+ "1:\n\t"
-+ "addl $-4,%ebx\n\t"
-+ "movl (%ebx), %eax\n\t"
-+ "pushl %eax\n\t"
-+ "cmpl %esp,%ecx\n\t"
-+ "jne 1b\n\t"
-+ "popl %eax\n\t"
-+ "popl %ebx\n\t"
-+ "popl %ecx\n\t"
-+ "iret \n\t");
-+/* *INDENT-ON* */
-+#define gdb_i386vector kgdb_info.vector
-+#define gdb_i386errcode kgdb_info.errcode
-+#define waiting_cpus kgdb_info.cpus_waiting
-+#define remote_debug kgdb_info.print_debug_info
-+#define hold_cpu(cpu) kgdb_info.cpus_waiting[cpu].hold
-+/* gdb locks */
-+
-+#ifdef CONFIG_SMP
-+static int in_kgdb_called;
-+static spinlock_t waitlocks[MAX_NO_CPUS] =
-+ {[0 ... MAX_NO_CPUS - 1] = SPIN_LOCK_UNLOCKED };
-+/*
-+ * The following array has the thread pointer of each of the "other"
-+ * cpus. We make it global so it can be seen by gdb.
-+ */
-+volatile int in_kgdb_entry_log[MAX_NO_CPUS];
-+volatile struct pt_regs *in_kgdb_here_log[MAX_NO_CPUS];
-+/*
-+static spinlock_t continuelocks[MAX_NO_CPUS];
-+*/
-+spinlock_t kgdb_spinlock = SPIN_LOCK_UNLOCKED;
-+/* waiters on our spinlock plus us */
-+static atomic_t spinlock_waiters = ATOMIC_INIT(1);
-+static int spinlock_count = 0;
-+static int spinlock_cpu = 0;
-+/*
-+ * Note we use nested spin locks to account for the case where a break
-+ * point is encountered when calling a function by user direction from
-+ * kgdb. Also there is the memory exception recursion to account for.
-+ * Well, yes, but this lets other cpus thru too. Lets add a
-+ * cpu id to the lock.
-+ */
-+#define KGDB_SPIN_LOCK(x) if( spinlock_count == 0 || \
-+ spinlock_cpu != smp_processor_id()){\
-+ atomic_inc(&spinlock_waiters); \
-+ while (! spin_trylock(x)) {\
-+ in_kgdb(®s);\
-+ }\
-+ atomic_dec(&spinlock_waiters); \
-+ spinlock_count = 1; \
-+ spinlock_cpu = smp_processor_id(); \
-+ }else{ \
-+ spinlock_count++; \
-+ }
-+#define KGDB_SPIN_UNLOCK(x) if( --spinlock_count == 0) spin_unlock(x)
-+#else
-+unsigned kgdb_spinlock = 0;
-+#define KGDB_SPIN_LOCK(x) --*x
-+#define KGDB_SPIN_UNLOCK(x) ++*x
-+#endif
-+
-+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 ((remote_debug) && (checksum != xmitcsum)) {
-+ printk
-+ ("bad checksum. My count = 0x%x, sent=0x%x. buf=%s\n",
-+ checksum, xmitcsum, buffer);
-+ }
-+
-+ 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);
-+
-+ if (remote_debug)
-+ printk("R:%s\n", buffer);
-+}
-+
-+/* send the packet in buffer. */
-+
-+void
-+putpacket(char *buffer)
-+{
-+ unsigned char checksum;
-+ int count;
-+ char ch;
-+
-+ /* $<packet info>#<checksum>. */
-+ do {
-+ if (remote_debug)
-+ printk("T:%s\n", buffer);
-+ putDebugChar('$');
-+ checksum = 0;
-+ count = 0;
-+
-+ while ((ch = buffer[count])) {
-+ putDebugChar(ch);
-+ 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;
-+
-+void
-+debug_error(char *format, char *parm)
-+{
-+ if (remote_debug)
-+ printk(format, parm);
-+}
-+
-+static void
-+print_regs(struct pt_regs *regs)
-+{
-+ printk("EAX=%08lx ", regs->eax);
-+ printk("EBX=%08lx ", regs->ebx);
-+ printk("ECX=%08lx ", regs->ecx);
-+ printk("EDX=%08lx ", regs->edx);
-+ printk("\n");
-+ printk("ESI=%08lx ", regs->esi);
-+ printk("EDI=%08lx ", regs->edi);
-+ printk("EBP=%08lx ", regs->ebp);
-+ printk("ESP=%08lx ", (long) ®s->esp);
-+ printk("\n");
-+ printk(" DS=%08x ", regs->xds);
-+ printk(" ES=%08x ", regs->xes);
-+ printk(" SS=%08x ", __KERNEL_DS);
-+ printk(" FL=%08lx ", regs->eflags);
-+ printk("\n");
-+ printk(" CS=%08x ", regs->xcs);
-+ printk(" IP=%08lx ", regs->eip);
-+#if 0
-+ printk(" FS=%08x ", regs->fs);
-+ printk(" GS=%08x ", regs->gs);
-+#endif
-+ printk("\n");
-+
-+} /* print_regs */
-+
-+#define NEW_esp fn_call_lookaside[trap_cpu].esp
-+
-+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;
-+ /* Note, as we are a debugging the kernel, we will always
-+ * trap in kernel code, this means no priviledge change,
-+ * and so the pt_regs structure is not completely valid. In a non
-+ * privilege change trap, only EFLAGS, CS and EIP are put on the stack,
-+ * SS and ESP are not stacked, this means that the last 2 elements of
-+ * pt_regs is not valid (they would normally refer to the user stack)
-+ * also, using regs+1 is no good because you end up will a value that is
-+ * 2 longs (8) too high. This used to cause stepping over functions
-+ * to fail, so my fix is to use the address of regs->esp, which
-+ * should point at the end of the stack frame. Note I have ignored
-+ * completely exceptions that cause an error code to be stacked, such
-+ * as double fault. Stuart Hughes, Zentropix.
-+ * original code: gdb_regs[_ESP] = (int) (regs + 1) ;
-+
-+ * this is now done on entry and moved to OLD_esp (as well as NEW_esp).
-+ */
-+ gdb_regs[_ESP] = NEW_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];
-+ NEW_esp = gdb_regs[_ESP]; /* keep the value */
-+#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 */
-+
-+int thread_list = 0;
-+
-+void
-+get_gdb_regs(struct task_struct *p, struct pt_regs *regs, int *gdb_regs)
-+{
-+ unsigned long stack_page;
-+ int count = 0;
-+ IF_SMP(int i);
-+ if (!p || p == current) {
-+ regs_to_gdb_regs(gdb_regs, regs);
-+ return;
-+ }
-+#ifdef CONFIG_SMP
-+ for (i = 0; i < MAX_NO_CPUS; i++) {
-+ if (p == kgdb_info.cpus_waiting[i].task) {
-+ regs_to_gdb_regs(gdb_regs,
-+ kgdb_info.cpus_waiting[i].regs);
-+ gdb_regs[_ESP] =
-+ (int) &kgdb_info.cpus_waiting[i].regs->esp;
-+
-+ return;
-+ }
-+ }
-+#endif
-+ memset(gdb_regs, 0, NUMREGBYTES);
-+ gdb_regs[_ESP] = p->thread.esp;
-+ gdb_regs[_PC] = p->thread.eip;
-+ gdb_regs[_EBP] = *(int *) gdb_regs[_ESP];
-+ gdb_regs[_EDI] = *(int *) (gdb_regs[_ESP] + 4);
-+ gdb_regs[_ESI] = *(int *) (gdb_regs[_ESP] + 8);
-+
-+/*
-+ * This code is to give a more informative notion of where a process
-+ * is waiting. It is used only when the user asks for a thread info
-+ * list. If he then switches to the thread, s/he will find the task
-+ * is in schedule, but a back trace should show the same info we come
-+ * up with. This code was shamelessly purloined from process.c. It was
-+ * then enhanced to provide more registers than simply the program
-+ * counter.
-+ */
-+
-+ if (!thread_list) {
-+ return;
-+ }
-+
-+ if (p->state == TASK_RUNNING)
-+ return;
-+ stack_page = (unsigned long) p->thread_info;
-+ if (gdb_regs[_ESP] < stack_page || gdb_regs[_ESP] >
-+ THREAD_SIZE - sizeof(long) + stack_page)
-+ return;
-+ /* include/asm-i386/system.h:switch_to() pushes ebp last. */
-+ do {
-+ if (gdb_regs[_EBP] < stack_page ||
-+ gdb_regs[_EBP] > THREAD_SIZE - 2*sizeof(long) + stack_page)
-+ return;
-+ gdb_regs[_PC] = *(unsigned long *) (gdb_regs[_EBP] + 4);
-+ gdb_regs[_ESP] = gdb_regs[_EBP] + 8;
-+ gdb_regs[_EBP] = *(unsigned long *) gdb_regs[_EBP];
-+ if (!in_sched_functions(gdb_regs[_PC]))
-+ return;
-+ } while (count++ < 16);
-+ return;
-+}
-+
-+/* Indicate to caller of mem2hex or hex2mem that there has been an
-+ error. */
-+static volatile int mem_err = 0;
-+static volatile int mem_err_expected = 0;
-+static volatile int mem_err_cnt = 0;
-+static int garbage_loc = -1;
-+
-+int
-+get_char(char *addr)
-+{
-+ return *addr;
-+}
-+
-+void
-+set_char(char *addr, int val, int may_fault)
-+{
-+ /*
-+ * This code traps references to the area mapped to the kernel
-+ * stack as given by the regs and, instead, stores to the
-+ * fn_call_lookaside[cpu].array
-+ */
-+ if (may_fault &&
-+ (unsigned int) addr < OLD_esp &&
-+ ((unsigned int) addr > (OLD_esp - (unsigned int) LOOKASIDE_SIZE))) {
-+ addr = (char *) END_OF_LOOKASIDE - ((char *) OLD_esp - addr);
-+ }
-+ *addr = val;
-+}
-+
-+/* convert the memory pointed to by mem into hex, placing result in buf */
-+/* return a pointer to the last char put in buf (null) */
-+/* If MAY_FAULT is non-zero, then we should set mem_err 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) {
-+ mem_err_expected = 1;
-+ mem_err = 0;
-+ }
-+ for (i = 0; i < count; i++) {
-+ /* printk("%lx = ", mem) ; */
-+
-+ ch = get_char(mem++);
-+
-+ /* printk("%02x\n", ch & 0xFF) ; */
-+ if (may_fault && mem_err) {
-+ if (remote_debug)
-+ printk("Mem fault fetching from addr %lx\n",
-+ (long) (mem - 1));
-+ *buf = 0; /* truncate buffer */
-+ return (buf);
-+ }
-+ *buf++ = hexchars[ch >> 4];
-+ *buf++ = hexchars[ch % 16];
-+ }
-+ *buf = 0;
-+ if (may_fault)
-+ mem_err_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 */
-+/* NOTE: We use the may fault flag to also indicate if the write is to
-+ * the registers (0) or "other" memory (!=0)
-+ */
-+char *
-+hex2mem(char *buf, char *mem, int count, int may_fault)
-+{
-+ int i;
-+ unsigned char ch;
++Here is an example gdb script produced by loadmodule.sh script.
+
-+ if (may_fault) {
-+ mem_err_expected = 1;
-+ mem_err = 0;
-+ }
-+ for (i = 0; i < count; i++) {
-+ ch = hex(*buf++) << 4;
-+ ch = ch + hex(*buf++);
-+ set_char(mem++, ch, may_fault);
++add-symbol-file foo 0xd082c060 -s .text.lock 0xd08cbfb5
++-s .fixup 0xd08cfbdf -s .rodata 0xd08cfde0 -s __ex_table 0xd08e3b38
++-s .data 0xd08e3d00 -s .bss 0xd08ec8c0 -s __ksymtab 0xd08ee838
+
-+ if (may_fault && mem_err) {
-+ if (remote_debug)
-+ printk("Mem fault storing to addr %lx\n",
-+ (long) (mem - 1));
-+ return (mem);
-+ }
-+ }
-+ if (may_fault)
-+ mem_err_expected = 0;
-+ return (mem);
-+}
++With this command gdb can calculate addresses of symbols in ANY segment
++in a module file.
+
-+/**********************************************/
-+/* 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;
++Regards.
++--
++Amit Kale
++Veritas Software ( http://www.veritas.com )
+Index: linux/Documentation/i386/kgdb/gdbinit
+===================================================================
+--- linux.orig/Documentation/i386/kgdb/gdbinit
++++ linux/Documentation/i386/kgdb/gdbinit
+@@ -0,0 +1,14 @@
++shell echo -e "\003" >/dev/ttyS0
++set remotebaud 38400
++target remote /dev/ttyS0
++define si
++stepi
++printf "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n", $eax, $ebx, $ecx, $edx
++printf "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n", $esi, $edi, $ebp, $esp
++x/i $eip
++end
++define ni
++nexti
++printf "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n", $eax, $ebx, $ecx, $edx
++printf "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n", $esi, $edi, $ebp, $esp
++x/i $eip
+Index: linux/Documentation/i386/kgdb/gdbinit-modules
+===================================================================
+--- linux.orig/Documentation/i386/kgdb/gdbinit-modules
++++ linux/Documentation/i386/kgdb/gdbinit-modules
+@@ -0,0 +1,149 @@
++#
++# Usefull GDB user-command to debug Linux Kernel Modules with gdbstub.
++#
++# This don't work for Linux-2.0 or older.
++#
++# Author Edouard G. Parmelan <Edouard.Parmelan@quadratec.fr>
++#
++#
++# Fri Apr 30 20:33:29 CEST 1999
++# First public release.
++#
++# Major cleanup after experiment Linux-2.0 kernel without success.
++# Symbols of a module are not in the correct order, I can't explain
++# why :(
++#
++# Fri Mar 19 15:41:40 CET 1999
++# Initial version.
++#
++# Thu Jan 6 16:29:03 CST 2000
++# A little fixing by Dave Grothe <dave@gcom.com>
++#
++# Mon Jun 19 09:33:13 CDT 2000
++# Alignment changes from Edouard Parmelan
++#
++# The basic idea is to find where insmod load the module and inform
++# GDB to load the symbol table of the module with the GDB command
++# ``add-symbol-file <object> <address>''.
++#
++# The Linux kernel holds the list of all loaded modules in module_list,
++# this list end with &kernel_module (exactly with module->next == NULL,
++# but the last module is not a real module).
++#
++# Insmod allocates the struct module before the object file. Since
++# Linux-2.1, this structure contain his size. The real address of
++# the object file is then (char*)module + module->size_of_struct.
++#
++# You can use three user functions ``mod-list'', ``mod-print-symbols''
++# and ``add-module-symbols''.
++#
++# mod-list list all loaded modules with the format:
++# <module-address> <module-name>
++#
++# As soon as you have found the address of your module, you can
++# print its exported symbols (mod-print-symbols) or inform GDB to add
++# symbols from your module file (mod-add-symbols).
++#
++# The argument that you give to mod-print-symbols or mod-add-symbols
++# is the <module-address> from the mod-list command.
++#
++# When using the mod-add-symbols command you must also give the full
++# pathname of the modules object code file.
++#
++# The command mod-add-lis is an example of how to make this easier.
++# You can edit this macro to contain the path name of your own
++# favorite module and then use it as a shorthand to load it. You
++# still need the module-address, however.
++#
++# The internal function ``mod-validate'' set the GDB variable $mod
++# as a ``struct module*'' if the kernel known the module otherwise
++# $mod is set to NULL. This ensure to not add symbols for a wrong
++# address.
++#
++#
++# Sat Feb 12 20:05:47 CET 2005
++#
++# Adapted to the 2.6.* module data structure.
++# (Getting miffed at gdb for not having "offsetof" in the process :-/ )
++#
++# Autogenerate add-symbol-file statements from the module list instead
++# of relying on a no-longer-working loadmodule.sh program.
++#
++# Matthias Urlichs <smurf@debian.org>
++#
++#
++# Have a nice hacking day !
++#
++#
++define mod-list
++ set $lmod = modules->next
++ # This is a circular data structure
++ while $lmod != &modules
++ set $mod = (struct module *)(((char *)$lmod) - ((int)&(((struct module *)0) -> list)))
++ printf "%p\t%s\n", $mod, $mod->name
++ set $lmod = $lmod->next
++ end
++end
++document mod-list
++mod-list
++List all modules in the form: <module-address> <module-name>
++Use the <module-address> as the argument for the other
++mod-commands: mod-print-symbols, mod-add-symbols.
++end
+
-+ *intValue = 0;
++define mod-list-syms
++ set $lmod = modules->next
++ # This is a circular data structure
++ while $lmod != &modules
++ set $mod = (struct module *)(((char *)$lmod) - ((int)&(((struct module *)0) -> list)))
++ printf "add-symbol-file %s.ko %p\n", $mod->name, $mod->module_core
++ set $lmod = $lmod->next
++ end
++end
++document mod-list-syms
++mod-list-syms
++List all modules in the form: add-symbol-file <module-path> <module-core>
++for adding modules' symbol tables without loadmodule.sh.
++end
+
-+ while (**ptr) {
-+ hexValue = hex(**ptr);
-+ if (hexValue >= 0) {
-+ *intValue = (*intValue << 4) | hexValue;
-+ numChars++;
-+ } else
-+ break;
++define mod-validate
++ set $lmod = modules->next
++ set $mod = (struct module *)(((char *)$lmod) - ((int)&(((struct module *)0) -> list)))
++ while ($lmod != &modules) && ($mod != $arg0)
++ set $lmod = $lmod->next
++ set $mod = (struct module *)(((char *)$lmod) - ((int)&(((struct module *)0) -> list)))
++ end
++ if $lmod == &modules
++ set $mod = 0
++ printf "%p is not a module\n", $arg0
++ end
++end
++document mod-validate
++mod-validate <module-address>
++Internal user-command used to validate the module parameter.
++If <module> is a real loaded module, set $mod to it, otherwise set $mod
++to 0.
++end
+
-+ (*ptr)++;
-+ }
++define mod-print-symbols
++ mod-validate $arg0
++ if $mod != 0
++ set $i = 0
++ while $i < $mod->num_syms
++ set $sym = $mod->syms[$i]
++ printf "%p\t%s\n", $sym->value, $sym->name
++ set $i = $i + 1
++ end
++ set $i = 0
++ while $i < $mod->num_gpl_syms
++ set $sym = $mod->gpl_syms[$i]
++ printf "%p\t%s\n", $sym->value, $sym->name
++ set $i = $i + 1
++ end
++ end
++end
++document mod-print-symbols
++mod-print-symbols <module-address>
++Print all exported symbols of the module. See mod-list
++end
+
-+ return (numChars);
-+}
+Index: linux/Documentation/i386/kgdb/gdbinit.hw
+===================================================================
+--- linux.orig/Documentation/i386/kgdb/gdbinit.hw
++++ linux/Documentation/i386/kgdb/gdbinit.hw
+@@ -0,0 +1,117 @@
+
-+#define stubhex(h) hex(h)
-+#ifdef old_thread_list
++#Using ia-32 hardware breakpoints.
++#
++#4 hardware breakpoints are available in ia-32 processors. These breakpoints
++#do not need code modification. They are set using debug registers.
++#
++#Each hardware breakpoint can be of one of the
++#three types: execution, write, access.
++#1. An Execution breakpoint is triggered when code at the breakpoint address is
++#executed.
++#2. A write breakpoint ( aka watchpoints ) is triggered when memory location
++#at the breakpoint address is written.
++#3. An access breakpoint is triggered when memory location at the breakpoint
++#address is either read or written.
++#
++#As hardware breakpoints are available in limited number, use software
++#breakpoints ( br command in gdb ) instead of execution hardware breakpoints.
++#
++#Length of an access or a write breakpoint defines length of the datatype to
++#be watched. Length is 1 for char, 2 short , 3 int.
++#
++#For placing execution, write and access breakpoints, use commands
++#hwebrk, hwwbrk, hwabrk
++#To remove a breakpoint use hwrmbrk command.
++#
++#These commands take following types of arguments. For arguments associated
++#with each command, use help command.
++#1. breakpointno: 0 to 3
++#2. length: 1 to 3
++#3. address: Memory location in hex ( without 0x ) e.g c015e9bc
++#
++#Use the command exinfo to find which hardware breakpoint occured.
+
-+static int
-+stub_unpack_int(char *buff, int fieldlength)
-+{
-+ int nibble;
-+ int retval = 0;
++#hwebrk breakpointno address
++define hwebrk
++ maintenance packet Y$arg0,0,0,$arg1
++end
++document hwebrk
++ hwebrk <breakpointno> <address>
++ Places a hardware execution breakpoint
++ <breakpointno> = 0 - 3
++ <address> = Hex digits without leading "0x".
++end
+
-+ 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;
-+}
++#hwwbrk breakpointno length address
++define hwwbrk
++ maintenance packet Y$arg0,1,$arg1,$arg2
++end
++document hwwbrk
++ hwwbrk <breakpointno> <length> <address>
++ Places a hardware write breakpoint
++ <breakpointno> = 0 - 3
++ <length> = 1 (1 byte), 2 (2 byte), 3 (4 byte)
++ <address> = Hex digits without leading "0x".
++end
+
-+#define BUF_THREAD_ID_SIZE 16
++#hwabrk breakpointno length address
++define hwabrk
++ maintenance packet Y$arg0,1,$arg1,$arg2
++end
++document hwabrk
++ hwabrk <breakpointno> <length> <address>
++ Places a hardware access breakpoint
++ <breakpointno> = 0 - 3
++ <length> = 1 (1 byte), 2 (2 byte), 3 (4 byte)
++ <address> = Hex digits without leading "0x".
++end
+
-+static char *
-+pack_threadid(char *pkt, threadref * id)
-+{
-+ char *limit;
-+ unsigned char *altid;
++#hwrmbrk breakpointno
++define hwrmbrk
++ maintenance packet y$arg0
++end
++document hwrmbrk
++ hwrmbrk <breakpointno>
++ <breakpointno> = 0 - 3
++ Removes a hardware breakpoint
++end
+
-+ altid = (unsigned char *) id;
-+ limit = pkt + BUF_THREAD_ID_SIZE;
-+ while (pkt < limit)
-+ pkt = pack_hex_byte(pkt, *altid++);
-+ return pkt;
-+}
++define reboot
++ maintenance packet r
++end
++#exinfo
++define exinfo
++ maintenance packet qE
++end
++document exinfo
++ exinfo
++ Gives information about a breakpoint.
++end
++define get_th
++ p $th=(struct thread_info *)((int)$esp & ~8191)
++end
++document get_th
++ get_tu
++ Gets and prints the current thread_info pointer, Defines th to be it.
++end
++define get_cu
++ p $cu=((struct thread_info *)((int)$esp & ~8191))->task
++end
++document get_cu
++ get_cu
++ Gets and print the "current" value. Defines $cu to be it.
++end
++define int_off
++ set var $flags=$eflags
++ set $eflags=$eflags&~0x200
++ end
++define int_on
++ set var $eflags|=$flags&0x200
++ end
++document int_off
++ saves the current interrupt state and clears the processor interrupt
++ flag. Use int_on to restore the saved flag.
++end
++document int_on
++ Restores the interrupt flag saved by int_off.
++end
+Index: linux/Documentation/i386/kgdb/kgdb.txt
+===================================================================
+--- linux.orig/Documentation/i386/kgdb/kgdb.txt
++++ linux/Documentation/i386/kgdb/kgdb.txt
+@@ -0,0 +1,775 @@
++Last edit: <20030806.1637.12>
++This file has information specific to the i386 kgdb option. Other
++platforms with the kgdb option may behave in a similar fashion.
+
-+#ifdef old_thread_list
-+static char *
-+unpack_byte(char *buf, int *value)
-+{
-+ *value = stub_unpack_int(buf, 2);
-+ return buf + 2;
-+}
++New features:
++============
++20030806.1557.37
++This version was made against the 2.6.0-test2 kernel. We have made the
++following changes:
+
-+static char *
-+unpack_threadid(char *inbuf, threadref * id)
-+{
-+ char *altref;
-+ char *limit = inbuf + BUF_THREAD_ID_SIZE;
-+ int x, y;
++- The getthread() code in the stub calls find_task_by_pid(). It fails
++ if we are early in the bring up such that the pid arrays have yet to
++ be allocated. We have added a line to kernel/pid.c to make
++ "kgdb_pid_init_done" true once the arrays are allocated. This way the
++ getthread() code knows not to call. This is only used by the thread
++ debugging stuff and threads will not yet exist at this point in the
++ boot.
+
-+ altref = (char *) id;
++- For some reason, gdb was not asking for a new thread list when the
++ "info thread" command was given. We changed to the newer version of
++ the thread info command and gdb now seems to ask when needed. Result,
++ we now get all threads in the thread list.
+
-+ 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;
++- We now respond to the ThreadExtraInfo request from gdb with the thread
++ name from task_struct .comm. This then appears in the thread list.
++ Thoughts on additional options for this are welcome. Things such as
++ "has BKL" and "Preempted" come to mind. I think we could have a flag
++ word that could enable different bits of info here.
+
-+ 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);
-+}
-+int
-+int_to_hex_v(unsigned char * id, int value)
-+{
-+ unsigned char *start = id;
-+ int shift;
-+ int ch;
++- We now honor, sort of, the C and S commands. These are continue and
++ single set after delivering a signal. We ignore the signal and do the
++ requested action. This only happens when we told gdb that a signal
++ was the reason for entry, which is only done on memory faults. The
++ result is that you can now continue into the Oops.
+
-+ for (shift = 28; shift >= 0; shift -= 4) {
-+ if ((ch = (value >> shift) & 0xf) || (id != start)) {
-+ *id = hexchars[ch];
-+ id++;
-+ }
-+ }
-+ if (id == start)
-+ *id++ = '0';
-+ return id - start;
-+}
-+#ifdef old_thread_list
++- We changed the -g to -gdwarf-2. This seems to be the same as -ggdb,
++ but it is more exact on what language to use.
+
-+static int
-+threadref_to_int(threadref * ref)
-+{
-+ int i, value = 0;
-+ unsigned char *scan;
++- We added two dwarf2 include files and a bit of code at the end of
++ entry.S. This does not yet work, so it is disabled. Still we want to
++ keep track of the code and "maybe" someone out there can fix it.
+
-+ scan = (char *) ref;
-+ scan += 4;
-+ i = 4;
-+ while (i-- > 0)
-+ value = (value << 8) | ((*scan++) & 0xff);
-+ return value;
-+}
-+#endif
-+static int
-+cmp_str(char *s1, char *s2, int count)
-+{
-+ while (count--) {
-+ if (*s1++ != *s2++)
-+ return 0;
-+ }
-+ return 1;
-+}
++- Randy Dunlap sent some fix ups for this file which are now merged.
+
-+#if 1 /* this is a hold over from 2.4 where O(1) was "sometimes" */
-+extern struct task_struct *kgdb_get_idle(int cpu);
-+#define idle_task(cpu) kgdb_get_idle(cpu)
-+#else
-+#define idle_task(cpu) init_tasks[cpu]
-+#endif
++- Hugh Dickins sent a fix to a bit of code in traps.c that prevents a
++ compiler warning if CONFIG_KGDB is off (now who would do that :).
+
-+extern int kgdb_pid_init_done;
++- Andrew Morton sent a fix for the serial driver which is now merged.
+
-+struct task_struct *
-+getthread(int pid)
-+{
-+ struct task_struct *thread;
-+ if (pid >= PID_MAX && pid <= (PID_MAX + MAX_NO_CPUS)) {
++- Andrew also sent a change to the stub around the cpu managment code
++ which is also merged.
+
-+ return idle_task(pid - PID_MAX);
-+ } else {
-+ /*
-+ * find_task_by_pid is relatively safe all the time
-+ * Other pid functions require lock downs which imply
-+ * that we may be interrupting them (as we get here
-+ * in the middle of most any lock down).
-+ * Still we don't want to call until the table exists!
-+ */
-+ if (kgdb_pid_init_done){
-+ thread = find_task_by_pid(pid);
-+ if (thread) {
-+ return thread;
-+ }
-+ }
-+ }
-+ return NULL;
-+}
-+/* *INDENT-OFF* */
-+struct hw_breakpoint {
-+ unsigned enabled;
-+ unsigned type;
-+ unsigned len;
-+ unsigned addr;
-+} breakinfo[4] = { {enabled:0},
-+ {enabled:0},
-+ {enabled:0},
-+ {enabled:0}};
-+/* *INDENT-ON* */
-+unsigned hw_breakpoint_status;
-+void
-+correct_hw_break(void)
-+{
-+ int breakno;
-+ int correctit;
-+ int breakbit;
-+ unsigned dr7;
++- Andrew also sent a patch to make "f" as well as "g" work as SysRq
++ commands to enter kgdb, merged.
+
-+ asm volatile ("movl %%db7, %0\n":"=r" (dr7)
-+ :);
-+ /* *INDENT-OFF* */
-+ 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);
-+ /* *INDENT-ON* */
-+ 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;
++- If CONFIG_KGDB and CONFIG_DEBUG_SPINLOCKS are both set we added a
++ "who" field to the spinlock data struct. This is filled with
++ "current" when ever the spinlock suceeds. Useful if you want to know
++ who has the lock.
+
-+ case 1:
-+ asm volatile ("movl %0, %%dr1\n"::"r"
-+ (breakinfo[breakno].addr));
-+ break;
++_ And last, but not least, we fixed the "get_cu" macro to properly get
++ the current value of "current".
+
-+ case 2:
-+ asm volatile ("movl %0, %%dr2\n"::"r"
-+ (breakinfo[breakno].addr));
-+ break;
++New features:
++============
++20030505.1827.27
++We are starting to align with the sourceforge version, at least in
++commands. To this end, the boot command string to start kgdb at
++boot time has been changed from "kgdb" to "gdb".
+
-+ 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));
-+ }
-+}
++Andrew Morton sent a couple of patches which are now included as follows:
++1.) We now return a flag to the interrupt handler.
++2.) We no longer use smp_num_cpus (a conflict with the lock meter).
++3.) And from William Lee Irwin III <wli@holomorphy.com> code to make
++ sure high-mem is set up before we attempt to register our interrupt
++ handler.
++We now include asm/kgdb.h from config.h so you will most likely never
++have to include it. It also 'NULLS' the kgdb macros you might have in
++your code when CONFIG_KGDB is not defined. This allows you to just
++turn off CONFIG_KGDB to turn off all the kgdb_ts() calls and such.
++This include is conditioned on the machine being an x86 so as to not
++mess with other archs.
+
-+int
-+remove_hw_break(unsigned breakno)
-+{
-+ if (!breakinfo[breakno].enabled) {
-+ return -1;
-+ }
-+ breakinfo[breakno].enabled = 0;
-+ return 0;
-+}
++20020801.1129.03
++This is currently the version for the 2.4.18 (and beyond?) kernel.
+
-+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;
-+}
++We have several new "features" beginning with this version:
+
-+#ifdef CONFIG_SMP
-+static int in_kgdb_console = 0;
++1.) Kgdb now syncs the "other" CPUs with a cross-CPU NMI. No more
++ waiting and it will pull that guy out of an IRQ off spin lock :)
+
-+int
-+in_kgdb(struct pt_regs *regs)
-+{
-+ unsigned flags;
-+ int cpu = smp_processor_id();
-+ in_kgdb_called = 1;
-+ if (!spin_is_locked(&kgdb_spinlock)) {
-+ if (in_kgdb_here_log[cpu] || /* we are holding this cpu */
-+ in_kgdb_console) { /* or we are doing slow i/o */
-+ return 1;
-+ }
-+ return 0;
-+ }
++2.) We doctored up the code that tells where a task is waiting and
++ included it so that the "info thread" command will show a bit more
++ than "schedule()". Try it...
++
++3.) Added the ability to call a function from gdb. All the standard gdb
++ issues apply, i.e. if you hit a breakpoint in the function, you are
++ not allowed to call another (gdb limitation, not kgdb). To help
++ this capability we added a memory allocation function. Gdb does not
++ return this memory (it is used for strings that you pass to that function
++ you are calling from gdb) so we fixed up a way to allow you to
++ manually return the memory (see below).
++
++4.) Kgdb time stamps (kgdb_ts()) are enhanced to expand what was the
++ interrupt flag to now also include the preemption count and the
++ "in_interrupt" info. The flag is now called "with_pif" to indicate
++ the order, preempt_count, in_interrupt, flag. The preempt_count is
++ shifted left by 4 bits so you can read the count in hex by dropping
++ the low order digit. In_interrupt is in bit 1, and the flag is in
++ bit 0.
++
++5.) The command: "p kgdb_info" is now expanded and prints something
++ like:
++(gdb) p kgdb_info
++$2 = {used_malloc = 0, called_from = 0xc0107506, entry_tsc = 67468627259,
++ errcode = 0, vector = 3, print_debug_info = 0, hold_on_sstep = 1,
++ cpus_waiting = {{task = 0xc027a000, pid = 32768, hold = 0,
++ regs = 0xc027bf84}, {task = 0x0, pid = 0, hold = 0, regs = 0x0}}}
++
++ Things to note here: a.) used_malloc is the amount of memory that
++ has been malloc'ed to do calls from gdb. You can reclaim this
++ memory like this: "p kgdb_info.used_malloc=0" Cool, huh? b.)
++ cpus_waiting is now "sized" by the number of CPUs you enter at
++ configure time in the kgdb configure section. This is NOT used
++ anywhere else in the system, but it is "nice" here. c.) The task's
++ "pid" is now in the structure. This is the pid you will need to use
++ to decode to the thread id to get gdb to look at that thread.
++ Remember that the "info thread" command prints a list of threads
++ wherein it numbers each thread with its reference number followed
++ by the thread's pid. Note that the per-CPU idle threads actually
++ have pids of 0 (yes, there is more than one pid 0 in an SMP system).
++ To avoid confusion, kgdb numbers these threads with numbers beyond
++ the MAX_PID. That is why you see 32768 and above.
+
-+ /* As I see it the only reason not to let all cpus spin on
-+ * the same spin_lock is to allow selected ones to proceed.
-+ * This would be a good thing, so we leave it this way.
-+ * Maybe someday.... Done !
++6.) A subtle change, we now provide the complete register set for tasks
++ that are active on the other CPUs. This allows better trace back on
++ those tasks.
+
-+ * in_kgdb() is called from an NMI so we don't pretend
-+ * to have any resources, like printk() for example.
-+ */
++ And, let's mention what we could not fix. Back-trace from all but the
++ thread that we trapped will, most likely, have a bogus entry in it.
++ The problem is that gdb does not recognize the entry code for
++ functions that use "current" near (at all?) the entry. The compiler
++ is putting the "current" decode as the first two instructions of the
++ function where gdb expects to find %ebp changing code. Back trace
++ also has trouble with interrupt frames. I am talking with Daniel
++ Jacobowitz about some way to fix this, but don't hold your breath.
+
-+ kgdb_local_irq_save(flags); /* only local here, to avoid hanging */
-+ /*
-+ * log arival of this cpu
-+ * The NMI keeps on ticking. Protect against recurring more
-+ * than once, and ignor the cpu that has the kgdb lock
-+ */
-+ in_kgdb_entry_log[cpu]++;
-+ in_kgdb_here_log[cpu] = regs;
-+ if (cpu == spinlock_cpu || waiting_cpus[cpu].task) {
-+ goto exit_in_kgdb;
-+ }
-+ /*
-+ * For protection of the initilization of the spin locks by kgdb
-+ * it locks the kgdb spinlock before it gets the wait locks set
-+ * up. We wait here for the wait lock to be taken. If the
-+ * kgdb lock goes away first?? Well, it could be a slow exit
-+ * sequence where the wait lock is removed prior to the kgdb lock
-+ * so if kgdb gets unlocked, we just exit.
-+ */
-+ while (spin_is_locked(&kgdb_spinlock) &&
-+ !spin_is_locked(waitlocks + cpu)) ;
-+ if (!spin_is_locked(&kgdb_spinlock)) {
-+ goto exit_in_kgdb;
-+ }
-+ waiting_cpus[cpu].task = current;
-+ waiting_cpus[cpu].pid = (current->pid) ? : (PID_MAX + cpu);
-+ waiting_cpus[cpu].regs = regs;
++20011220.0050.35
++Major enhancement with this version is the ability to hold one or more
++CPUs in an SMP system while allowing the others to continue. Also, by
++default only the current CPU is enabled on single-step commands (please
++note that gdb issues single-step commands at times other than when you
++use the si command).
+
-+ spin_unlock_wait(waitlocks + cpu);
-+ /*
-+ * log departure of this cpu
-+ */
-+ waiting_cpus[cpu].task = 0;
-+ waiting_cpus[cpu].pid = 0;
-+ waiting_cpus[cpu].regs = 0;
-+ correct_hw_break();
-+ exit_in_kgdb:
-+ in_kgdb_here_log[cpu] = 0;
-+ kgdb_local_irq_restore(flags);
-+ return 1;
-+ /*
-+ spin_unlock(continuelocks + smp_processor_id());
-+ */
-+}
++Another change is to collect some useful information in
++a global structure called "kgdb_info". You should be able to just:
+
-+void
-+smp__in_kgdb(struct pt_regs regs)
-+{
-+ ack_APIC_irq();
-+ in_kgdb(®s);
-+}
-+#else
-+int
-+in_kgdb(struct pt_regs *regs)
-+{
-+ return (kgdb_spinlock);
-+}
-+#endif
++p kgdb_info
+
-+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;
-+}
++although I have seen cases where the first time this is done gdb just
++prints the first member but prints the whole structure if you then enter
++CR (carriage return or enter). This also works:
+
-+/*
-+ * 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 kgdb_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
-+kgdb_handle_exception(int exceptionVector,
-+ int signo, int err_code, struct pt_regs *linux_regs)
-+{
-+ struct task_struct *usethread = NULL;
-+ struct task_struct *thread_list_start = 0, *thread = NULL;
-+ int addr, length;
-+ int breakno, breaktype;
-+ char *ptr;
-+ int newPC;
-+ threadref thref;
-+ int threadid;
-+ int thread_min = PID_MAX + MAX_NO_CPUS;
-+#ifdef old_thread_list
-+ int maxthreads;
-+#endif
-+ int nothreads;
-+ unsigned long flags;
-+ int gdb_regs[NUMREGBYTES / 4];
-+ int dr6;
-+ IF_SMP(int entry_state = 0); /* 0, ok, 1, no nmi, 2 sync failed */
-+#define NO_NMI 1
-+#define NO_SYNC 2
-+#define regs (*linux_regs)
-+#define NUMREGS NUMREGBYTES/4
-+ /*
-+ * 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)) {
-+ printk("ignoring non-kernel exception\n");
-+ print_regs(®s);
-+ return (0);
-+ }
++p *&kgdb_info
+
-+ kgdb_local_irq_save(flags);
++Here is a sample:
++(gdb) p kgdb_info
++$4 = {called_from = 0xc010732c, entry_tsc = 32804123790856, errcode = 0,
++ vector = 3, print_debug_info = 0}
+
-+ /* Get kgdb spinlock */
++"Called_from" is the return address from the current entry into kgdb.
++Sometimes it is useful to know why you are in kgdb, for example, was
++it an NMI or a real breakpoint? The simple way to interrogate this
++return address is:
+
-+ KGDB_SPIN_LOCK(&kgdb_spinlock);
-+ rdtscll(kgdb_info.entry_tsc);
-+ /*
-+ * We depend on this spinlock and the NMI watch dog to control the
-+ * other cpus. They will arrive at "in_kgdb()" as a result of the
-+ * NMI and will wait there for the following spin locks to be
-+ * released.
-+ */
-+#ifdef CONFIG_SMP
++l *0xc010732c
+
-+#if 0
-+ if (cpu_callout_map & ~MAX_CPU_MASK) {
-+ printk("kgdb : too many cpus, possibly not mapped"
-+ " in contiguous space, change MAX_NO_CPUS"
-+ " in kgdb_stub and make new kernel.\n"
-+ " cpu_callout_map is %lx\n", cpu_callout_map);
-+ goto exit_just_unlock;
-+ }
-+#endif
-+ if (spinlock_count == 1) {
-+ int time = 0, end_time, dum = 0;
-+ int i;
-+ int cpu_logged_in[MAX_NO_CPUS] = {[0 ... MAX_NO_CPUS - 1] = (0)
-+ };
-+ if (remote_debug) {
-+ printk("kgdb : cpu %d entry, syncing others\n",
-+ smp_processor_id());
-+ }
-+ for (i = 0; i < MAX_NO_CPUS; i++) {
-+ /*
-+ * Use trylock as we may already hold the lock if
-+ * we are holding the cpu. Net result is all
-+ * locked.
-+ */
-+ spin_trylock(&waitlocks[i]);
-+ }
-+ for (i = 0; i < MAX_NO_CPUS; i++)
-+ cpu_logged_in[i] = 0;
-+ /*
-+ * Wait for their arrival. We know the watch dog is active if
-+ * in_kgdb() has ever been called, as it is always called on a
-+ * watchdog tick.
-+ */
-+ rdtsc(dum, time);
-+ end_time = time + 2; /* Note: we use the High order bits! */
-+ i = 1;
-+ if (num_online_cpus() > 1) {
-+ int me_in_kgdb = in_kgdb_entry_log[smp_processor_id()];
-+ smp_send_nmi_allbutself();
-+ while (i < num_online_cpus() && time != end_time) {
-+ int j;
-+ for (j = 0; j < MAX_NO_CPUS; j++) {
-+ if (waiting_cpus[j].task &&
-+ !cpu_logged_in[j]) {
-+ i++;
-+ cpu_logged_in[j] = 1;
-+ if (remote_debug) {
-+ printk
-+ ("kgdb : cpu %d arrived at kgdb\n",
-+ j);
-+ }
-+ break;
-+ } else if (!waiting_cpus[j].task &&
-+ !cpu_online(j)) {
-+ waiting_cpus[j].task = NOCPU;
-+ cpu_logged_in[j] = 1;
-+ waiting_cpus[j].hold = 1;
-+ break;
-+ }
-+ if (!waiting_cpus[j].task &&
-+ in_kgdb_here_log[j]) {
++which will print the surrounding few lines of source code.
++
++"Entry_tsc" is the CPU TSC on entry to kgdb (useful to compare to the
++kgdb_ts entries).
++
++"errcode" and "vector" are other entry parameters which may be helpful on
++some traps.
+
-+ int wait = 100000;
-+ while (wait--) ;
-+ if (!waiting_cpus[j].task &&
-+ in_kgdb_here_log[j]) {
-+ printk
-+ ("kgdb : cpu %d stall"
-+ " in in_kgdb\n",
-+ j);
-+ i++;
-+ cpu_logged_in[j] = 1;
-+ waiting_cpus[j].task =
-+ (struct task_struct
-+ *) 1;
-+ }
-+ }
-+ }
++"print_debug_info" is the internal debugging kgdb print enable flag. Yes,
++you can modify it.
+
-+ if (in_kgdb_entry_log[smp_processor_id()] >
-+ (me_in_kgdb + 10)) {
-+ break;
-+ }
++In SMP systems kgdb_info also includes the "cpus_waiting" structure and
++"hold_on_step":
+
-+ rdtsc(dum, time);
-+ }
-+ if (i < num_online_cpus()) {
-+ printk
-+ ("kgdb : time out, proceeding without sync\n");
-+#if 0
-+ printk("kgdb : Waiting_cpus: 0 = %d, 1 = %d\n",
-+ waiting_cpus[0].task != 0,
-+ waiting_cpus[1].task != 0);
-+ printk("kgdb : Cpu_logged in: 0 = %d, 1 = %d\n",
-+ cpu_logged_in[0], cpu_logged_in[1]);
-+ printk
-+ ("kgdb : in_kgdb_here_log in: 0 = %d, 1 = %d\n",
-+ in_kgdb_here_log[0] != 0,
-+ in_kgdb_here_log[1] != 0);
-+#endif
-+ entry_state = NO_SYNC;
-+ } else {
-+#if 0
-+ int ent =
-+ in_kgdb_entry_log[smp_processor_id()] -
-+ me_in_kgdb;
-+ printk("kgdb : sync after %d entries\n", ent);
-+#endif
-+ }
-+ } else {
-+ if (remote_debug) {
-+ printk
-+ ("kgdb : %d cpus, but watchdog not active\n"
-+ "proceeding without locking down other cpus\n",
-+ num_online_cpus());
-+ entry_state = NO_NMI;
-+ }
-+ }
-+ }
-+#endif
++(gdb) p kgdb_info
++$7 = {called_from = 0xc0112739, entry_tsc = 1034936624074, errcode = 0,
++ vector = 2, print_debug_info = 0, hold_on_sstep = 1, cpus_waiting = {{
++ task = 0x0, hold = 0, regs = 0x0}, {task = 0xc71b8000, hold = 0,
++ regs = 0xc71b9f70}, {task = 0x0, hold = 0, regs = 0x0}, {task = 0x0,
++ hold = 0, regs = 0x0}, {task = 0x0, hold = 0, regs = 0x0}, {task = 0x0,
++ hold = 0, regs = 0x0}, {task = 0x0, hold = 0, regs = 0x0}, {task = 0x0,
++ hold = 0, regs = 0x0}}}
+
-+ if (remote_debug) {
-+ unsigned long *lp = (unsigned long *) &linux_regs;
++"Cpus_waiting" has an entry for each CPU other than the current one that
++has been stopped. Each entry contains the task_struct address for that
++CPU, the address of the regs for that task and a hold flag. All these
++have the proper typing so that, for example:
+
-+ printk("handle_exception(exceptionVector=%d, "
-+ "signo=%d, err_code=%d, linux_regs=%p)\n",
-+ exceptionVector, signo, err_code, linux_regs);
-+ if (debug_regs) {
-+ print_regs(®s);
-+ printk("Stk: %8lx %8lx %8lx %8lx"
-+ " %8lx %8lx %8lx %8lx\n",
-+ lp[0], lp[1], lp[2], lp[3],
-+ lp[4], lp[5], lp[6], lp[7]);
-+ printk(" %8lx %8lx %8lx %8lx"
-+ " %8lx %8lx %8lx %8lx\n",
-+ lp[8], lp[9], lp[10], lp[11],
-+ lp[12], lp[13], lp[14], lp[15]);
-+ printk(" %8lx %8lx %8lx %8lx "
-+ "%8lx %8lx %8lx %8lx\n",
-+ lp[16], lp[17], lp[18], lp[19],
-+ lp[20], lp[21], lp[22], lp[23]);
-+ printk(" %8lx %8lx %8lx %8lx "
-+ "%8lx %8lx %8lx %8lx\n",
-+ lp[24], lp[25], lp[26], lp[27],
-+ lp[28], lp[29], lp[30], lp[31]);
-+ }
-+ }
++p *kgdb_info.cpus_waiting[1].regs
+
-+ /* Disable hardware debugging while we are in kgdb */
-+ /* Get the debug register status register */
-+/* *INDENT-OFF* */
-+ __asm__("movl %0,%%db7"
-+ : /* no output */
-+ :"r"(0));
++will print the registers for CPU 1.
+
-+ asm volatile ("movl %%db6, %0\n"
-+ :"=r" (hw_breakpoint_status)
-+ :);
++"Hold_on_sstep" is a new feature with this version and comes up set or
++true. What this means is that whenever kgdb is asked to single-step all
++other CPUs are held (i.e. not allowed to execute). The flag applies to
++all but the current CPU and, again, can be changed:
+
-+/* *INDENT-ON* */
-+ switch (exceptionVector) {
-+ case 0: /* divide error */
-+ case 1: /* debug exception */
-+ case 2: /* NMI */
-+ case 3: /* breakpoint */
-+ case 4: /* overflow */
-+ case 5: /* bounds check */
-+ case 6: /* invalid opcode */
-+ case 7: /* device not available */
-+ case 8: /* double fault (errcode) */
-+ case 10: /* invalid TSS (errcode) */
-+ case 12: /* stack fault (errcode) */
-+ case 16: /* floating point error */
-+ case 17: /* alignment check (errcode) */
-+ default: /* any undocumented */
-+ break;
-+ case 11: /* segment not present (errcode) */
-+ case 13: /* general protection (errcode) */
-+ case 14: /* page fault (special errcode) */
-+ case 19: /* cache flush denied */
-+ if (mem_err_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.
-+ */
-+ mem_err = 1; /* set mem error flag */
-+ mem_err_expected = 0;
-+ mem_err_cnt++; /* helps in debugging */
-+ /* make valid address */
-+ regs.eax = (long) &garbage_loc;
-+ /* make valid address */
-+ regs.edx = (long) &garbage_loc;
-+ if (remote_debug)
-+ printk("Return after memory error: "
-+ "mem_err_cnt=%d\n", mem_err_cnt);
-+ if (debug_regs)
-+ print_regs(®s);
-+ goto exit_kgdb;
-+ }
-+ break;
-+ }
-+ if (remote_debug)
-+ printk("kgdb : entered kgdb on cpu %d\n", smp_processor_id());
++p kgdb_info.hold_on_sstep=0
+
-+ gdb_i386vector = exceptionVector;
-+ gdb_i386errcode = err_code;
-+ kgdb_info.called_from = __builtin_return_address(0);
-+#ifdef CONFIG_SMP
-+ /*
-+ * OK, we can now communicate, lets tell gdb about the sync.
-+ * but only if we had a problem.
-+ */
-+ switch (entry_state) {
-+ case NO_NMI:
-+ to_gdb("NMI not active, other cpus not stopped\n");
-+ break;
-+ case NO_SYNC:
-+ to_gdb("Some cpus not stopped, see 'kgdb_info' for details\n");
-+ default:;
-+ }
++restores the old behavior of letting all CPUs run during single-stepping.
+
-+#endif
-+/*
-+ * Set up the gdb function call area.
-+ */
-+ trap_cpu = smp_processor_id();
-+ OLD_esp = NEW_esp = (int) (&linux_regs->esp);
++Likewise, each CPU has a "hold" flag, which if set, locks that CPU out
++of execution. Note that this has some risk in cases where the CPUs need
++to communicate with each other. If kgdb finds no CPU available on exit,
++it will push a message thru gdb and stay in kgdb. Note that it is legal
++to hold the current CPU as long as at least one CPU can execute.
+
-+ IF_SMP(once_again:)
-+ /* reply to host that an exception has occurred */
-+ remcomOutBuffer[0] = 'S';
-+ remcomOutBuffer[1] = hexchars[signo >> 4];
-+ remcomOutBuffer[2] = hexchars[signo % 16];
-+ remcomOutBuffer[3] = 0;
++20010621.1117.09
++This version implements an event queue. Events are signaled by calling
++a function in the kgdb stub and may be examined from gdb. See EVENTS
++below for details. This version also tightens up the interrupt and SMP
++handling to not allow interrupts on the way to kgdb from a breakpoint
++trap. It is fine to allow these interrupts for user code, but not
++system debugging.
+
-+ putpacket(remcomOutBuffer);
++Version
++=======
+
-+ 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 'd':
-+ remote_debug = !(remote_debug); /* toggle debug flag */
-+ printk("Remote debug %s\n",
-+ remote_debug ? "on" : "off");
-+ break;
-+ case 'g': /* return the value of the CPU registers */
-+ get_gdb_regs(usethread, ®s, gdb_regs);
-+ 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;
++This version of the kgdb package was developed and tested on
++kernel version 2.4.16. It will not install on any earlier kernels.
++It is possible that it will continue to work on later versions
++of 2.4 and then versions of 2.5 (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 the
++appropriate modem eliminator (null modem) cable(s) for this.
+
-+ case 'P':{ /* set the value of a single CPU register -
-+ return OK */
-+ /*
-+ * For some reason, gdb wants to talk about psudo
-+ * registers (greater than 15). These may have
-+ * meaning for ptrace, but for us it is safe to
-+ * ignor them. We do this by dumping them into
-+ * _GS which we also ignor, but do have memory for.
-+ */
-+ int regno;
++Decide on which tty port you want the machines to communicate, then
++connect them up back-to-back using the null modem cable. COM1 is
++/dev/ttyS0 and COM2 is /dev/ttyS1. You should test this connection
++with the two machines prior to trying to debug a kernel. Once you
++have it working, on the TARGET machine, enter:
+
-+ ptr = &remcomInBuffer[1];
-+ regs_to_gdb_regs(gdb_regs, ®s);
-+ if ((!usethread || usethread == current) &&
-+ hexToInt(&ptr, ®no) &&
-+ *ptr++ == '=' && (regno >= 0)) {
-+ regno =
-+ (regno >= NUMREGS ? _GS : regno);
-+ hex2mem(ptr, (char *) &gdb_regs[regno],
-+ 4, 0);
-+ gdb_regs_to_regs(gdb_regs, ®s);
-+ strcpy(remcomOutBuffer, "OK");
-+ break;
-+ }
-+ strcpy(remcomOutBuffer, "E01");
-+ break;
-+ }
++setserial /dev/ttyS0 (or what ever tty you are using)
+
-+ /* 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) &&
-+ (*(ptr++) == ',') && (hexToInt(&ptr, &length))) {
-+ ptr = 0;
-+ /*
-+ * hex doubles the byte count
-+ */
-+ if (length > (BUFMAX / 2))
-+ length = BUFMAX / 2;
-+ mem2hex((char *) addr,
-+ remcomOutBuffer, length, 1);
-+ if (mem_err) {
-+ strcpy(remcomOutBuffer, "E03");
-+ debug_error("memory fault\n", NULL);
-+ }
-+ }
++and record the port address and the IRQ number.
+
-+ if (ptr) {
-+ strcpy(remcomOutBuffer, "E01");
-+ debug_error
-+ ("malformed read memory command: %s\n",
-+ remcomInBuffer);
-+ }
-+ break;
++On the DEVELOPMENT machine you need to apply the patch for the kgdb
++hooks. You have probably already done that if you are reading this
++file.
+
-+ /* 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) &&
-+ (*(ptr++) == ',') &&
-+ (hexToInt(&ptr, &length)) && (*(ptr++) == ':')) {
-+ hex2mem(ptr, (char *) addr, length, 1);
++On your DEVELOPMENT machine, go to your kernel source directory and do
++"make Xconfig" where X is one of "x", "menu", or "". If you are
++configuring in the standard serial driver, it must not be a module.
++Either yes or no is ok, but making the serial driver a module means it
++will initialize after kgdb has set up the UART interrupt code and may
++cause a failure of the control-C option discussed below. The configure
++question for the serial driver is under the "Character devices" heading
++and is:
+
-+ if (mem_err) {
-+ strcpy(remcomOutBuffer, "E03");
-+ debug_error("memory fault\n", NULL);
-+ } else {
-+ strcpy(remcomOutBuffer, "OK");
-+ }
++"Standard/generic (8250/16550 and compatible UARTs) serial support"
+
-+ ptr = 0;
-+ }
-+ if (ptr) {
-+ strcpy(remcomOutBuffer, "E02");
-+ debug_error
-+ ("malformed write memory command: %s\n",
-+ remcomInBuffer);
-+ }
-+ break;
-+ case 'S':
-+ remcomInBuffer[0] = 's';
-+ case 'C':
-+ /* Csig;AA..AA where ;AA..AA is optional
-+ * continue with signal
-+ * Since signals are meaning less to us, delete that
-+ * part and then fall into the 'c' code.
-+ */
-+ ptr = &remcomInBuffer[1];
-+ length = 2;
-+ while (*ptr && *ptr != ';') {
-+ length++;
-+ ptr++;
-+ }
-+ if (*ptr) {
-+ do {
-+ ptr++;
-+ *(ptr - length++) = *ptr;
-+ } while (*ptr);
-+ } else {
-+ remcomInBuffer[1] = 0;
-+ }
++Go down to the kernel debugging menu item and open it up. Enable the
++kernel kgdb stub code by selecting that item. You can also choose to
++turn on the "-ggdb -O1" compile options. The -ggdb causes the compiler
++to put more debug info (like local symbols) in the object file. On the
++i386 -g and -ggdb are the same so this option just reduces to "O1". The
++-O1 reduces the optimization level. This may be helpful in some cases,
++be aware, however, that this may also mask the problem you are looking
++for.
+
-+ /* cAA..AA Continue at address AA..AA(optional) */
-+ /* sAA..AA Step one instruction from AA..AA(optional) */
-+ /* D detach, reply OK and then continue */
-+ case 'c':
-+ case 's':
-+ case 'D':
++The baud rate. Default is 115200. What ever you choose be sure that
++the host machine is set to the same speed. I recommend the default.
+
-+ /* try to read optional parameter,
-+ pc unchanged if no parm */
-+ ptr = &remcomInBuffer[1];
-+ if (hexToInt(&ptr, &addr)) {
-+ if (remote_debug)
-+ printk("Changing EIP to 0x%x\n", addr);
++The port. This is the I/O address of the serial UART that you should
++have gotten using setserial as described above. The standard COM1 port
++(3f8) using IRQ 4 is default. COM2 is 2f8 which by convention uses IRQ
++3.
+
-+ regs.eip = addr;
-+ }
++The port IRQ (see above).
+
-+ newPC = regs.eip;
++Stack overflow test. This option makes a minor change in the trap,
++system call and interrupt code to detect stack overflow and transfer
++control to kgdb if it happens. (Some platforms have this in the
++baseline code, but the i386 does not.)
+
-+ /* clear the trace bit */
-+ regs.eflags &= 0xfffffeff;
++You can also configure the system to recognize the boot option
++"console=kgdb" which if given will cause all console output during
++booting to be put thru gdb as well as other consoles. This option
++requires that gdb and kgdb be connected prior to sending console output
++so, if they are not, a breakpoint is executed to force the connection.
++This will happen before any kernel output (it is going thru gdb, right),
++and will stall the boot until the connection is made.
+
-+ /* set the trace bit if we're stepping */
-+ if (remcomInBuffer[0] == 's')
-+ regs.eflags |= 0x100;
++You can also configure in a patch to SysRq to enable the kGdb SysRq.
++This request generates a breakpoint. Since the serial port IRQ line is
++set up after any serial drivers, it is possible that this command will
++work when the control-C will not.
+
-+ /* detach is a friendly version of continue. Note that
-+ debugging is still enabled (e.g hit control C)
-+ */
-+ if (remcomInBuffer[0] == 'D') {
-+ strcpy(remcomOutBuffer, "OK");
-+ putpacket(remcomOutBuffer);
-+ }
++Save and exit the Xconfig program. Then do "make clean" , "make dep"
++and "make bzImage" (or whatever target you want to make). This gets the
++kernel compiled with the "-g" option set -- necessary for debugging.
+
-+ if (remote_debug) {
-+ printk("Resuming execution\n");
-+ print_regs(®s);
-+ }
-+ asm volatile ("movl %%db6, %0\n":"=r" (dr6)
-+ :);
-+ if (!(dr6 & 0x4000)) {
-+ for (breakno = 0; breakno < 4; ++breakno) {
-+ if (dr6 & (1 << breakno) &&
-+ (breakinfo[breakno].type == 0)) {
-+ /* Set restore flag */
-+ regs.eflags |= 0x10000;
-+ break;
-+ }
-+ }
-+ }
-+ correct_hw_break();
-+ asm volatile ("movl %0, %%db6\n"::"r" (0));
-+ goto exit_kgdb;
++You have just built the kernel on your DEVELOPMENT machine that you
++intend to run on your TARGET machine.
+
-+ /* kill the program */
-+ case 'k': /* do nothing */
-+ break;
++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.
+
-+ /* query */
-+ case 'q':
-+ nothreads = 0;
-+ switch (remcomInBuffer[1]) {
-+ case 'f':
-+ threadid = 1;
-+ thread_list = 2;
-+ thread_list_start = (usethread ? : current);
-+ case 's':
-+ if (!cmp_str(&remcomInBuffer[2],
-+ "ThreadInfo", 10))
-+ break;
++Copy this kernel to your target machine using your usual procedures. I
++usually arrange to copy development:
++/usr/src/linux/arch/i386/boot/bzImage 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 (see "man
++lilo" for details on how to set this up) on the new kernel on the target
++machine so that it will boot! Then boot the kernel on the target
++machine.
+
-+ remcomOutBuffer[nothreads++] = 'm';
-+ for (; threadid < PID_MAX + MAX_NO_CPUS;
-+ threadid++) {
-+ thread = getthread(threadid);
-+ if (thread) {
-+ nothreads += int_to_hex_v(
-+ &remcomOutBuffer[
-+ nothreads],
-+ threadid);
-+ if (thread_min > threadid)
-+ thread_min = threadid;
-+ remcomOutBuffer[
-+ nothreads] = ',';
-+ nothreads++;
-+ if (nothreads > BUFMAX - 10)
-+ break;
-+ }
-+ }
-+ if (remcomOutBuffer[nothreads - 1] == 'm') {
-+ remcomOutBuffer[nothreads - 1] = 'l';
-+ } else {
-+ nothreads--;
-+ }
-+ remcomOutBuffer[nothreads] = 0;
-+ break;
++On the DEVELOPMENT machine, create a file called .gdbinit in the
++directory /usr/src/linux. An example .gdbinit file looks like this:
++
++shell echo -e "\003" >/dev/ttyS0
++set remotebaud 38400 (or what ever speed you have chosen)
++target remote /dev/ttyS0
+
-+#ifdef old_thread_list /* Old thread info request */
-+ case 'L':
-+ /* List threads */
-+ thread_list = 2;
-+ thread_list_start = (usethread ? : current);
-+ unpack_byte(remcomInBuffer + 3, &maxthreads);
-+ unpack_threadid(remcomInBuffer + 5, &thref);
-+ do {
-+ int buf_thread_limit =
-+ (BUFMAX - 22) / BUF_THREAD_ID_SIZE;
-+ if (maxthreads > buf_thread_limit) {
-+ maxthreads = buf_thread_limit;
-+ }
-+ } while (0);
-+ 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 + MAX_NO_CPUS;
-+ threadid++) {
-+ thread = getthread(threadid);
-+ if (thread) {
-+ int_to_threadref(&thref,
-+ threadid);
-+ pack_threadid(remcomOutBuffer +
-+ 21 +
-+ nothreads * 16,
-+ &thref);
-+ nothreads++;
-+ if (thread_min > threadid)
-+ thread_min = threadid;
-+ }
-+ }
++Change the "echo" and "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.
+
-+ if (threadid == PID_MAX + MAX_NO_CPUS) {
-+ remcomOutBuffer[4] = '1';
-+ }
-+ pack_hex_byte(remcomOutBuffer + 2, nothreads);
-+ remcomOutBuffer[21 + nothreads * 16] = '\0';
-+ break;
-+#endif
-+ case 'C':
-+ /* Current thread id */
-+ remcomOutBuffer[0] = 'Q';
-+ remcomOutBuffer[1] = 'C';
-+ threadid = current->pid;
-+ if (!threadid) {
-+ /*
-+ * idle thread
-+ */
-+ for (threadid = PID_MAX;
-+ threadid < PID_MAX + MAX_NO_CPUS;
-+ threadid++) {
-+ if (current ==
-+ idle_task(threadid -
-+ PID_MAX))
-+ break;
-+ }
-+ }
-+ int_to_threadref(&thref, threadid);
-+ pack_threadid(remcomOutBuffer + 2, &thref);
-+ remcomOutBuffer[18] = '\0';
-+ break;
++You are now ready to try it out.
+
-+ case 'E':
-+ /* Print exception info */
-+ printexceptioninfo(exceptionVector,
-+ err_code, remcomOutBuffer);
-+ break;
-+ case 'T':{
-+ char * nptr;
-+ /* Thread extra info */
-+ if (!cmp_str(&remcomInBuffer[2],
-+ "hreadExtraInfo,", 15)) {
-+ break;
-+ }
-+ ptr = &remcomInBuffer[17];
-+ hexToInt(&ptr, &threadid);
-+ thread = getthread(threadid);
-+ nptr = &thread->comm[0];
-+ length = 0;
-+ ptr = &remcomOutBuffer[0];
-+ do {
-+ length++;
-+ ptr = pack_hex_byte(ptr, *nptr++);
-+ } while (*nptr && length < 16);
-+ /*
-+ * would like that 16 to be the size of
-+ * task_struct.comm but don't know the
-+ * syntax..
-+ */
-+ *ptr = 0;
-+ }
-+ }
-+ break;
++Boot your target machine with "kgdb" in the boot command i.e. something
++like:
+
-+ /* 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;
-+ }
-+ /*
-+ * Just in case I forget what this is all about,
-+ * the "thread info" command to gdb causes it
-+ * to ask for a thread list. It then switches
-+ * to each thread and asks for the registers.
-+ * For this (and only this) usage, we want to
-+ * fudge the registers of tasks not on the run
-+ * list (i.e. waiting) to show the routine that
-+ * called schedule. Also, gdb, is a minimalist
-+ * in that if the current thread is the last
-+ * it will not re-read the info when done.
-+ * This means that in this case we must show
-+ * the real registers. So here is how we do it:
-+ * Each entry we keep track of the min
-+ * thread in the list (the last that gdb will)
-+ * get info for. We also keep track of the
-+ * starting thread.
-+ * "thread_list" is cleared when switching back
-+ * to the min thread if it is was current, or
-+ * if it was not current, thread_list is set
-+ * to 1. When the switch to current comes,
-+ * if thread_list is 1, clear it, else do
-+ * nothing.
-+ */
-+ usethread = thread;
-+ if ((thread_list == 1) &&
-+ (thread == thread_list_start)) {
-+ thread_list = 0;
-+ }
-+ if (thread_list && (threadid == thread_min)) {
-+ if (thread == thread_list_start) {
-+ thread_list = 0;
-+ } else {
-+ thread_list = 1;
-+ }
-+ }
-+ /* follow through */
-+ case 'c':
-+ remcomOutBuffer[0] = 'O';
-+ remcomOutBuffer[1] = 'K';
-+ remcomOutBuffer[2] = '\0';
-+ break;
-+ }
-+ break;
++lilo> test kgdb
+
-+ /* 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';
-+ if (thread_min > threadid)
-+ thread_min = threadid;
-+ } else {
-+ remcomOutBuffer[0] = 'E';
-+ remcomOutBuffer[1] = '\0';
-+ }
-+ break;
++or if you also want console output thru gdb:
+
-+ case 'Y': /* set up a hardware breakpoint */
-+ 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;
++lilo> test kgdb console=kgdb
+
-+ /* 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;
++You should see the lilo message saying it has loaded the kernel and then
++all output stops. The kgdb stub is trying to connect with gdb. Start
++gdb something like this:
++
++
++On your DEVELOPMENT machine, cd /usr/src/linux and enter "gdb vmlinux".
++When gdb gets the symbols loaded it will read your .gdbinit file and, 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 kgdb 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...
++ 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.
++
++If you have the kgdb console enabled when you continue, gdb will print
++out all the console messages.
++
++The above example caused a breakpoint relatively early in the boot
++process. For the i386 kgdb it is possible to code a break instruction
++as the first C-language point in init/main.c, i.e. as the first instruction
++in start_kernel(). This could be done as follows:
++
++#include <asm/kgdb.h>
++ breakpoint();
++
++This breakpoint() is really a function that sets up the breakpoint and
++single-step hardware trap cells and then executes a breakpoint. Any
++early hard coded breakpoint will need to use this function. Once the
++trap cells are set up they need not be set again, but doing it again
++does not hurt anything, so you don't need to be concerned about which
++breakpoint is hit first. Once the trap cells are set up (and the kernel
++sets them up in due course even if breakpoint() is never called) the
++macro:
++
++BREAKPOINT;
+
-+ case 'r': /* reboot */
-+ strcpy(remcomOutBuffer, "OK");
-+ putpacket(remcomOutBuffer);
-+ /*to_gdb("Rebooting\n"); */
-+ /* triplefault no return from here */
-+ {
-+ static long no_idt[2];
-+ __asm__ __volatile__("lidt %0"::"m"(no_idt[0]));
-+ BREAKPOINT;
-+ }
++will generate an inline breakpoint. This may be more useful as it stops
++the processor at the instruction instead of in a function a step removed
++from the location of interest. In either case <asm/kgdb.h> must be
++included to define both breakpoint() and BREAKPOINT.
+
-+ } /* switch */
++Triggering kgdbstub at other times
++==================================
+
-+ /* reply to the request */
-+ putpacket(remcomOutBuffer);
-+ } /* while(1==1) */
-+ /*
-+ * reached by goto only.
-+ */
-+ exit_kgdb:
-+ /*
-+ * Here is where we set up to trap a gdb function call. NEW_esp
-+ * will be changed if we are trying to do this. We handle both
-+ * adding and subtracting, thus allowing gdb to put grung on
-+ * the stack which it removes later.
-+ */
-+ if (NEW_esp != OLD_esp) {
-+ int *ptr = END_OF_LOOKASIDE;
-+ if (NEW_esp < OLD_esp)
-+ ptr -= (OLD_esp - NEW_esp) / sizeof (int);
-+ *--ptr = linux_regs->eflags;
-+ *--ptr = linux_regs->xcs;
-+ *--ptr = linux_regs->eip;
-+ *--ptr = linux_regs->ecx;
-+ *--ptr = linux_regs->ebx;
-+ *--ptr = linux_regs->eax;
-+ linux_regs->ecx = NEW_esp - (sizeof (int) * 6);
-+ linux_regs->ebx = (unsigned int) END_OF_LOOKASIDE;
-+ if (NEW_esp < OLD_esp) {
-+ linux_regs->eip = (unsigned int) fn_call_stub;
-+ } else {
-+ linux_regs->eip = (unsigned int) fn_rtn_stub;
-+ linux_regs->eax = NEW_esp;
-+ }
-+ linux_regs->eflags &= ~(IF_BIT | TF_BIT);
-+ }
-+#ifdef CONFIG_SMP
-+ /*
-+ * Release gdb wait locks
-+ * Sanity check time. Must have at least one cpu to run. Also single
-+ * step must not be done if the current cpu is on hold.
-+ */
-+ if (spinlock_count == 1) {
-+ int ss_hold = (regs.eflags & 0x100) && kgdb_info.hold_on_sstep;
-+ int cpu_avail = 0;
-+ int i;
++Often you don't need to enter the debugger until much later in the boot
++or even after the machine has been running for some time. Once the
++kernel is booted and interrupts are on, you can force the system to
++enter the debugger by sending a control-C to the debug port. This is
++what the first line of the recommended .gdbinit file does. This allows
++you to start gdb any time after the system is up as well as when the
++system is already at a breakpoint. (In the case where the system is
++already at a breakpoint the control-C is not needed, however, it will
++be ignored by the target so no harm is done. Also note the the echo
++command assumes that the port speed is already set. This will be true
++once gdb has connected, but it is best to set the port speed before you
++run gdb.)
+
-+ for (i = 0; i < MAX_NO_CPUS; i++) {
-+ if (!cpu_online(i))
-+ break;
-+ if (!hold_cpu(i)) {
-+ cpu_avail = 1;
-+ }
-+ }
-+ /*
-+ * Early in the bring up there will be NO cpus on line...
-+ */
-+ if (!cpu_avail && !cpus_empty(cpu_online_map)) {
-+ to_gdb("No cpus unblocked, see 'kgdb_info.hold_cpu'\n");
-+ goto once_again;
-+ }
-+ if (hold_cpu(smp_processor_id()) && (regs.eflags & 0x100)) {
-+ to_gdb
-+ ("Current cpu must be unblocked to single step\n");
-+ goto once_again;
-+ }
-+ if (!(ss_hold)) {
-+ int i;
-+ for (i = 0; i < MAX_NO_CPUS; i++) {
-+ if (!hold_cpu(i)) {
-+ spin_unlock(&waitlocks[i]);
-+ }
-+ }
-+ } else {
-+ spin_unlock(&waitlocks[smp_processor_id()]);
-+ }
-+ /* Release kgdb spinlock */
-+ KGDB_SPIN_UNLOCK(&kgdb_spinlock);
-+ /*
-+ * If this cpu is on hold, this is where we
-+ * do it. Note, the NMI will pull us out of here,
-+ * but will return as the above lock is not held.
-+ * We will stay here till another cpu releases the lock for us.
-+ */
-+ spin_unlock_wait(waitlocks + smp_processor_id());
-+ kgdb_local_irq_restore(flags);
-+ return (0);
-+ }
-+#if 0
-+exit_just_unlock:
-+#endif
-+#endif
-+ /* Release kgdb spinlock */
-+ KGDB_SPIN_UNLOCK(&kgdb_spinlock);
-+ kgdb_local_irq_restore(flags);
-+ return (0);
-+}
++Another simple way to do this is to put the following file in you ~/bin
++directory:
+
-+/* this function is used to set up exception handlers for tracing and
-+ * breakpoints.
-+ * This function is not needed as the above line does all that is needed.
-+ * We leave it for backward compatitability...
-+ */
-+void
-+set_debug_traps(void)
-+{
-+ /*
-+ * linux_debug_hook is defined in traps.c. We store a pointer
-+ * to our own exception handler into it.
++#!/bin/bash
++echo -e "\003" > /dev/ttyS0
+
-+ * But really folks, every hear of labeled common, an old Fortran
-+ * concept. Lots of folks can reference it and it is define if
-+ * anyone does. Only one can initialize it at link time. We do
-+ * this with the hook. See the statement above. No need for any
-+ * executable code and it is ready as soon as the kernel is
-+ * loaded. Very desirable in kernel debugging.
++Here, the ttyS0 should be replaced with what ever port you are using.
++The "\003" is control-C. Once you are connected with gdb, you can enter
++control-C at the command prompt.
+
-+ linux_debug_hook = handle_exception ;
-+ */
++An alternative way to get control to the debugger is to enable the kGdb
++SysRq command. Then you would enter Alt-SysRq-g (all three keys at the
++same time, but push them down in the order given). To refresh your
++memory of the available SysRq commands try Alt-SysRq-=. Actually any
++undefined command could replace the "=", but I like to KNOW that what I
++am pushing will never be defined.
+
-+ /* In case GDB is started before us, ack any packets (presumably
-+ "$?#xx") sitting there.
-+ putDebugChar ('+');
++Debugging hints
++===============
+
-+ initialized = 1;
-+ */
-+}
++You can break into the target machine at any time from the development
++machine by typing ^C (see above paragraph). If the target machine has
++interrupts enabled this will stop it in the kernel and enter the
++debugger.
+
-+/* 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. */
-+/* But really, just use the BREAKPOINT macro. We will handle the int stuff
-+ */
++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. The exploratory breakpoints can be
++entered either thru gdb or hard coded into the source. This is very
++handy if you do something like:
+
-+#ifdef later
-+/*
-+ * possibly we should not go thru the traps.c code at all? Someday.
-+ */
-+void
-+do_kgdb_int3(struct pt_regs *regs, long error_code)
-+{
-+ kgdb_handle_exception(3, 5, error_code, regs);
-+ return;
-+}
-+#endif
-+#undef regs
-+#ifdef CONFIG_TRAP_BAD_SYSCALL_EXITS
-+asmlinkage void
-+bad_sys_call_exit(int stuff)
-+{
-+ struct pt_regs *regs = (struct pt_regs *) &stuff;
-+ printk("Sys call %d return with %x preempt_count\n",
-+ (int) regs->orig_eax, preempt_count());
-+}
-+#endif
-+#ifdef CONFIG_STACK_OVERFLOW_TEST
-+#include <asm/kgdb.h>
-+asmlinkage void
-+stack_overflow(void)
-+{
-+#ifdef BREAKPOINT
-+ BREAKPOINT;
-+#else
-+ printk("Kernel stack overflow, looping forever\n");
-+#endif
-+ while (1) {
-+ }
-+}
-+#endif
++if (<it hurts>) BREAKPOINT;
+
-+#if defined(CONFIG_SMP) || defined(CONFIG_KGDB_CONSOLE)
-+char gdbconbuf[BUFMAX];
+
-+static void
-+kgdb_gdb_message(const char *s, unsigned count)
-+{
-+ int i;
-+ int wcount;
-+ char *bufptr;
-+ /*
-+ * This takes care of NMI while spining out chars to gdb
-+ */
-+ IF_SMP(in_kgdb_console = 1);
-+ 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;
++There is a copy of an e-mail in the Documentation/i386/kgdb/ directory
++(debug-nmi.txt) 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.
+
-+ putpacket(gdbconbuf);
++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, first clear all breakpoints and
++continue, then 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. Make sure it works
++in both directions. There is no point in tearing out your hair in the
++kernel if the line doesn't work.
+
-+ }
-+ IF_SMP(in_kgdb_console = 0);
-+}
-+#endif
-+#ifdef CONFIG_SMP
-+static void
-+to_gdb(const char *s)
-+{
-+ int count = 0;
-+ while (s[count] && (count++ < BUFMAX)) ;
-+ kgdb_gdb_message(s, count);
-+}
-+#endif
-+#ifdef CONFIG_KGDB_CONSOLE
-+#include <linux/console.h>
-+#include <linux/init.h>
-+#include <linux/fs.h>
-+#include <asm/uaccess.h>
-+#include <asm/semaphore.h>
++All of the real action takes place in the file
++/usr/src/linux/arch/i386/kernel/kgdb_stub.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:
+
-+void
-+kgdb_console_write(struct console *co, const char *s, unsigned count)
-+{
++ set remotedebug
+
-+ if (gdb_i386vector == -1) {
-+ /*
-+ * We have not yet talked to gdb. What to do...
-+ * lets break, on continue we can do the write.
-+ * But first tell him whats up. Uh, well no can do,
-+ * as this IS the console. Oh well...
-+ * We do need to wait or the messages will be lost.
-+ * Other option would be to tell the above code to
-+ * ignore this breakpoint and do an auto return,
-+ * but that might confuse gdb. Also this happens
-+ * early enough in boot up that we don't have the traps
-+ * set up yet, so...
-+ */
-+ breakpoint();
-+ }
-+ kgdb_gdb_message(s, count);
-+}
++This will print out the protocol messages that gdb is exchanging with
++the target machine.
+
-+/*
-+ * ------------------------------------------------------------
-+ * Serial KGDB driver
-+ * ------------------------------------------------------------
-+ */
++Another place to look is /usr/src/arch/i386/lib/kgdb_serial.c. This is
++the code that talks to the serial port on the target side. There might
++be a problem there. In particular there is a section of this code that
++tests the UART which will tell you what UART you have if you define
++"PRNT" (just remove "_off" from the #define PRNT_off). To view this
++report you will need to boot the system without any beakpoints. This
++allows the kernel to run to the point where it calls kgdb to set up
++interrupts. At this time kgdb will test the UART and print out the type
++it finds. (You need to wait so that the printks are actually being
++printed. Early in the boot they are cached, waiting for the console to
++be enabled. Also, if kgdb is entered thru a breakpoint it is possible
++to cause a dead lock by calling printk when the console is locked. The
++stub thus avoids doing printks from breakpoints, especially in the
++serial code.) At this time, if the UART fails to do the expected thing,
++kgdb will print out (using printk) information on what failed. (These
++messages will be buried in all the other boot up messages. Look for
++lines that start with "gdb_hook_interrupt:". You may want to use dmesg
++once the system is up to view the log. If this fails or if you still
++don't connect, review your answers for the port address. Use:
+
-+static struct console kgdbcons = {
-+ name:"kgdb",
-+ write:kgdb_console_write,
-+#ifdef CONFIG_KGDB_USER_CONSOLE
-+ device:kgdb_console_device,
-+#endif
-+ flags:CON_PRINTBUFFER | CON_ENABLED,
-+ index:-1,
-+};
++setserial /dev/ttyS0
+
-+/*
-+ * The trick here is that this file gets linked before printk.o
-+ * That means we get to peer at the console info in the command
-+ * line before it does. If we are up, we register, otherwise,
-+ * do nothing. By returning 0, we allow printk to look also.
-+ */
-+static int kgdb_console_enabled;
++to get the current port and IRQ information. This command will also
++tell you what the system found for the UART type. The stub recognizes
++the following UART types:
+
-+int __init
-+kgdb_console_init(char *str)
-+{
-+ if ((strncmp(str, "kgdb", 4) == 0) || (strncmp(str, "gdb", 3) == 0)) {
-+ register_console(&kgdbcons);
-+ kgdb_console_enabled = 1;
-+ }
-+ return 0; /* let others look at the string */
-+}
++16450, 16550, and 16550A
+
-+__setup("console=", kgdb_console_init);
++If you are really desperate you can use printk debugging in the
++kgdbstub code in the target kernel until you get it working. In particular,
++there is a global variable in /usr/src/linux/arch/i386/kernel/kgdb_stub.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. Likewise there are debug printks in the kgdb_serial.c
++code that can be turned on with simple changes in the macro defines.
+
-+#ifdef CONFIG_KGDB_USER_CONSOLE
-+static kdev_t kgdb_console_device(struct console *c);
-+/* This stuff sort of works, but it knocks out telnet devices
-+ * we are leaving it here in case we (or you) find time to figure it out
-+ * better..
-+ */
+
-+/*
-+ * We need a real char device as well for when the console is opened for user
-+ * space activities.
-+ */
++Debugging Loadable Modules
++==========================
+
-+static int
-+kgdb_consdev_open(struct inode *inode, struct file *file)
-+{
-+ return 0;
-+}
++This technique comes courtesy of Edouard Parmelan
++<Edouard.Parmelan@quadratec.fr>
+
-+static ssize_t
-+kgdb_consdev_write(struct file *file, const char *buf,
-+ size_t count, loff_t * ppos)
-+{
-+ int size, ret = 0;
-+ static char kbuf[128];
-+ static DECLARE_MUTEX(sem);
++When you run gdb, enter the command
+
-+ /* We are not reentrant... */
-+ if (down_interruptible(&sem))
-+ return -ERESTARTSYS;
++source gdbinit-modules
+
-+ while (count > 0) {
-+ /* need to copy the data from user space */
-+ size = count;
-+ if (size > sizeof (kbuf))
-+ size = sizeof (kbuf);
-+ if (copy_from_user(kbuf, buf, size)) {
-+ ret = -EFAULT;
-+ break;;
-+ }
-+ kgdb_console_write(&kgdbcons, kbuf, size);
-+ count -= size;
-+ ret += size;
-+ buf += size;
-+ }
++This will read in a file of gdb macros that was installed in your
++kernel source directory when kgdb was installed. This file implements
++the following commands:
+
-+ up(&sem);
++mod-list
++ Lists the loaded modules in the form <module-address> <module-name>
+
-+ return ret;
-+}
++mod-print-symbols <module-address>
++ Prints all the symbols in the indicated module.
+
-+struct file_operations kgdb_consdev_fops = {
-+ open:kgdb_consdev_open,
-+ write:kgdb_consdev_write
-+};
-+static kdev_t
-+kgdb_console_device(struct console *c)
-+{
-+ return MKDEV(TTYAUX_MAJOR, 1);
-+}
++mod-add-symbols <module-address> <object-file-path-name>
++ Loads the symbols from the object file and associates them
++ with the indicated module.
+
-+/*
-+ * This routine gets called from the serial stub in the i386/lib
-+ * This is so it is done late in bring up (just before the console open).
-+ */
-+void
-+kgdb_console_finit(void)
-+{
-+ if (kgdb_console_enabled) {
-+ char *cptr = cdevname(MKDEV(TTYAUX_MAJOR, 1));
-+ char *cp = cptr;
-+ while (*cptr && *cptr != '(')
-+ cptr++;
-+ *cptr = 0;
-+ unregister_chrdev(TTYAUX_MAJOR, cp);
-+ register_chrdev(TTYAUX_MAJOR, "kgdb", &kgdb_consdev_fops);
-+ }
-+}
-+#endif
-+#endif
-+#ifdef CONFIG_KGDB_TS
-+#include <asm/msr.h> /* time stamp code */
-+#include <asm/hardirq.h> /* in_interrupt */
-+#ifdef CONFIG_KGDB_TS_64
-+#define DATA_POINTS 64
-+#endif
-+#ifdef CONFIG_KGDB_TS_128
-+#define DATA_POINTS 128
-+#endif
-+#ifdef CONFIG_KGDB_TS_256
-+#define DATA_POINTS 256
-+#endif
-+#ifdef CONFIG_KGDB_TS_512
-+#define DATA_POINTS 512
-+#endif
-+#ifdef CONFIG_KGDB_TS_1024
-+#define DATA_POINTS 1024
-+#endif
-+#ifndef DATA_POINTS
-+#define DATA_POINTS 128 /* must be a power of two */
-+#endif
-+#define INDEX_MASK (DATA_POINTS - 1)
-+#if (INDEX_MASK & DATA_POINTS)
-+#error "CONFIG_KGDB_TS_COUNT must be a power of 2"
-+#endif
-+struct kgdb_and_then_struct {
-+#ifdef CONFIG_SMP
-+ int on_cpu;
-+#endif
-+ struct task_struct *task;
-+ long long at_time;
-+ int from_ln;
-+ char *in_src;
-+ void *from;
-+ int *with_shpf;
-+ int data0;
-+ int data1;
-+};
-+struct kgdb_and_then_struct2 {
-+#ifdef CONFIG_SMP
-+ int on_cpu;
-+#endif
-+ struct task_struct *task;
-+ long long at_time;
-+ int from_ln;
-+ char *in_src;
-+ void *from;
-+ int *with_shpf;
-+ struct task_struct *t1;
-+ struct task_struct *t2;
-+};
-+struct kgdb_and_then_struct kgdb_data[DATA_POINTS];
++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.
+
-+struct kgdb_and_then_struct *kgdb_and_then = &kgdb_data[0];
-+int kgdb_and_then_count;
++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.
+
-+void
-+kgdb_tstamp(int line, char *source, int data0, int data1)
-+{
-+ static spinlock_t ts_spin = SPIN_LOCK_UNLOCKED;
-+ int flags;
-+ kgdb_local_irq_save(flags);
-+ spin_lock(&ts_spin);
-+ rdtscll(kgdb_and_then->at_time);
-+#ifdef CONFIG_SMP
-+ kgdb_and_then->on_cpu = smp_processor_id();
-+#endif
-+ kgdb_and_then->task = current;
-+ kgdb_and_then->from_ln = line;
-+ kgdb_and_then->in_src = source;
-+ kgdb_and_then->from = __builtin_return_address(0);
-+ kgdb_and_then->with_shpf = (int *) (((flags & IF_BIT) >> 9) |
-+ (preempt_count() << 8));
-+ kgdb_and_then->data0 = data0;
-+ kgdb_and_then->data1 = data1;
-+ kgdb_and_then = &kgdb_data[++kgdb_and_then_count & INDEX_MASK];
-+ spin_unlock(&ts_spin);
-+ kgdb_local_irq_restore(flags);
-+#ifdef CONFIG_PREEMPT
++Threads
++=======
+
-+#endif
-+ return;
-+}
-+#endif
-+typedef int gdb_debug_hook(int exceptionVector,
-+ int signo, int err_code, struct pt_regs *linux_regs);
-+gdb_debug_hook *linux_debug_hook = &kgdb_handle_exception; /* histerical reasons... */
-diff -puN arch/i386/kernel/Makefile~kgdb-ga arch/i386/kernel/Makefile
---- 25/arch/i386/kernel/Makefile~kgdb-ga 2004-10-21 14:54:15.259603680 -0700
-+++ 25-akpm/arch/i386/kernel/Makefile 2004-10-21 14:54:15.308596232 -0700
-@@ -14,6 +14,7 @@ obj-y += timers/
- obj-$(CONFIG_ACPI_BOOT) += acpi/
- obj-$(CONFIG_X86_BIOS_REBOOT) += reboot.o
- obj-$(CONFIG_MCA) += mca.o
-+obj-$(CONFIG_KGDB) += kgdb_stub.o
- obj-$(CONFIG_X86_MSR) += msr.o
- obj-$(CONFIG_X86_CPUID) += cpuid.o
- obj-$(CONFIG_MICROCODE) += microcode.o
-diff -puN arch/i386/kernel/nmi.c~kgdb-ga arch/i386/kernel/nmi.c
---- 25/arch/i386/kernel/nmi.c~kgdb-ga 2004-10-21 14:54:15.261603376 -0700
-+++ 25-akpm/arch/i386/kernel/nmi.c 2004-10-21 14:54:15.308596232 -0700
-@@ -34,7 +34,17 @@
-
- #include "mach_traps.h"
-
-+#ifdef CONFIG_KGDB
-+#include <asm/kgdb.h>
-+#ifdef CONFIG_SMP
-+unsigned int nmi_watchdog = NMI_IO_APIC;
-+#else
-+unsigned int nmi_watchdog = NMI_LOCAL_APIC;
-+#endif
-+#else
- unsigned int nmi_watchdog = NMI_NONE;
-+#endif
++Each process in a target machine is seen as a gdb thread. gdb thread
++related commands (info threads, thread n) can be used.
+
- extern int unknown_nmi_panic;
- static unsigned int nmi_hz = HZ;
- static unsigned int nmi_perfctr_msr; /* the MSR to reset in NMI handler */
-@@ -466,6 +476,9 @@ void touch_nmi_watchdog (void)
- for (i = 0; i < NR_CPUS; i++)
- alert_counter[i] = 0;
- }
-+#ifdef CONFIG_KGDB
-+int tune_watchdog = 5*HZ;
-+#endif
-
- extern void die_nmi(struct pt_regs *, const char *msg);
-
-@@ -481,12 +494,24 @@ void nmi_watchdog_tick (struct pt_regs *
- */
- sum = irq_stat[cpu].apic_timer_irqs;
-
-+#ifdef CONFIG_KGDB
-+ if (!in_kgdb(regs) && last_irq_sums[cpu] == sum) {
++ia-32 hardware breakpoints
++==========================
+
-+#else
- if (last_irq_sums[cpu] == sum) {
-+#endif
- /*
- * Ayiee, looks like this CPU is stuck ...
- * wait a few IRQs (5 seconds) before doing the oops ...
- */
- alert_counter[cpu]++;
-+#ifdef CONFIG_KGDB
-+ if (alert_counter[cpu] == tune_watchdog) {
-+ kgdb_handle_exception(2, SIGPWR, 0, regs);
-+ last_irq_sums[cpu] = sum;
-+ alert_counter[cpu] = 0;
-+ }
-+#endif
- if (alert_counter[cpu] == 30*nmi_hz)
- die_nmi(regs, "NMI Watchdog detected LOCKUP");
- } else {
-diff -puN arch/i386/kernel/smp.c~kgdb-ga arch/i386/kernel/smp.c
---- 25/arch/i386/kernel/smp.c~kgdb-ga 2004-10-21 14:54:15.262603224 -0700
-+++ 25-akpm/arch/i386/kernel/smp.c 2004-10-21 14:54:15.309596080 -0700
-@@ -466,7 +466,17 @@ void flush_tlb_all(void)
- {
- on_each_cpu(do_flush_tlb_all, NULL, 1, 1);
- }
--
-+#ifdef CONFIG_KGDB
-+/*
-+ * By using the NMI code instead of a vector we just sneak thru the
-+ * word generator coming out with just what we want. AND it does
-+ * not matter if clustered_apic_mode is set or not.
-+ */
-+void smp_send_nmi_allbutself(void)
-+{
-+ send_IPI_allbutself(APIC_DM_NMI);
-+}
-+#endif
- /*
- * this function sends a 'reschedule' IPI to another CPU.
- * it goes straight through and wastes no time serializing
-diff -puN arch/i386/kernel/traps.c~kgdb-ga arch/i386/kernel/traps.c
---- 25/arch/i386/kernel/traps.c~kgdb-ga 2004-10-21 14:54:15.264602920 -0700
-+++ 25-akpm/arch/i386/kernel/traps.c 2004-10-21 14:54:15.311595776 -0700
-@@ -105,6 +105,39 @@ int register_die_notifier(struct notifie
- return err;
- }
-
-+#ifdef CONFIG_KGDB
-+extern void sysenter_past_esp(void);
-+#include <asm/kgdb.h>
-+#include <linux/init.h>
-+void set_intr_gate(unsigned int n, void *addr);
-+static void set_intr_usr_gate(unsigned int n, void *addr);
-+/*
-+ * Should be able to call this breakpoint() very early in
-+ * bring up. Just hard code the call where needed.
-+ * The breakpoint() code is here because set_?_gate() functions
-+ * are local (static) to trap.c. They need be done only once,
-+ * but it does not hurt to do them over.
-+ */
-+void breakpoint(void)
-+{
-+ set_intr_usr_gate(3,&int3); /* disable ints on trap */
-+ set_intr_gate(1,&debug);
-+ set_intr_gate(14,&page_fault);
++kgdb 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.
+
-+ BREAKPOINT;
-+}
-+#define CHK_REMOTE_DEBUG(trapnr,signr,error_code,regs,after) \
-+ { \
-+ if (!user_mode(regs) ) \
-+ { \
-+ kgdb_handle_exception(trapnr, signr, error_code, regs); \
-+ after; \
-+ } else if ((trapnr == 3) && (regs->eflags &0x200)) local_irq_enable(); \
-+ }
-+#else
-+#define CHK_REMOTE_DEBUG(trapnr,signr,error_code,regs,after)
-+#endif
++Each hardware breakpoint can be of one of the following three types.
+
- static inline int valid_stack_ptr(struct thread_info *tinfo, void *p)
- {
- return p > (void *)tinfo &&
-@@ -332,6 +365,15 @@ void die(const char * str, struct pt_reg
- #endif
- if (nl)
- printk("\n");
-+#ifdef CONFIG_KGDB
-+ /* This is about the only place we want to go to kgdb even if in
-+ * user mode. But we must go in via a trap so within kgdb we will
-+ * always be in kernel mode.
-+ */
-+ if (user_mode(regs))
-+ BREAKPOINT;
-+#endif
-+ CHK_REMOTE_DEBUG(0,SIGTRAP,err,regs,)
- notify_die(DIE_OOPS, (char *)str, regs, err, 255, SIGSEGV);
- show_registers(regs);
- } else
-@@ -406,6 +448,7 @@ static inline void 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,) \
- if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \
- == NOTIFY_STOP) \
- return; \
-@@ -429,6 +472,7 @@ 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, return) \
- if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \
- == NOTIFY_STOP) \
- return; \
-@@ -512,7 +556,8 @@ gp_in_vm86:
-
- gp_in_kernel:
- if (!fixup_exception(regs)) {
- die:
-+ CHK_REMOTE_DEBUG(13,SIGSEGV,error_code,regs,)
- if (notify_die(DIE_GPF, "general protection fault", regs,
- error_code, 13, SIGSEGV) == NOTIFY_STOP)
- return;
-@@ -721,8 +766,18 @@ asmlinkage void do_debug(struct pt_regs
- * allowing programs to debug themselves without the ptrace()
- * interface.
- */
-+#ifdef CONFIG_KGDB
-+ /*
-+ * I think this is the only "real" case of a TF in the kernel
-+ * that really belongs to user space. Others are
-+ * "Ours all ours!"
-+ */
-+ if (((regs->xcs & 3) == 0) && ((void *)regs->eip == sysenter_past_esp))
-+ goto clear_TF_reenable;
-+#else
- if ((regs->xcs & 3) == 0)
- goto clear_TF_reenable;
-+#endif
- if ((tsk->ptrace & (PT_DTRACE|PT_PTRACED)) == PT_DTRACE)
- goto clear_TF;
- }
-@@ -734,6 +789,17 @@ asmlinkage void do_debug(struct pt_regs
- info.si_errno = 0;
- info.si_code = TRAP_BRKPT;
-
-+#ifdef CONFIG_KGDB
-+ /*
-+ * If this is a kernel mode trap, we need to reset db7 to allow us
-+ * to continue sanely ALSO skip the signal delivery
-+ */
-+ if ((regs->xcs & 3) == 0)
-+ goto clear_dr7;
++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 occurred.
++ Prints number of the hardware breakpoint if a hardware breakpoint has
++ occurred.
+
-+ /* if not kernel, allow ints but only if they were on */
-+ if ( regs->eflags & 0x200) local_irq_enable();
-+#endif
- /* 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.
- */
-@@ -748,6 +814,7 @@ clear_dr7:
- __asm__("movl %0,%%db7"
- : /* no output */
- : "r" (0));
-+ CHK_REMOTE_DEBUG(1,SIGTRAP,error_code,regs,)
- return;
-
- debug_vm86:
-@@ -1004,6 +1071,12 @@ static void __init set_task_gate(unsigne
- {
- _set_gate(idt_table+n,5,0,0,(gdt_entry<<3));
- }
-+#ifdef CONFIG_KGDB
-+void set_intr_usr_gate(unsigned int n, void *addr)
-+{
-+ _set_gate(idt_table+n,14,3,addr,__KERNEL_CS);
-+}
-+#endif
-
-
- void __init trap_init(void)
-@@ -1021,7 +1094,11 @@ void __init trap_init(void)
- set_trap_gate(0,÷_error);
- set_intr_gate(1,&debug);
- set_intr_gate(2,&nmi);
-+#ifndef CONFIG_KGDB
- set_system_intr_gate(3, &int3); /* int3-5 can be called from all */
-+#else
-+ set_intr_usr_gate(3,&int3); /* int3-5 can be called from all */
-+#endif
- set_system_gate(4,&overflow);
- set_system_gate(5,&bounds);
- set_trap_gate(6,&invalid_op);
-diff -puN /dev/null arch/i386/lib/kgdb_serial.c
---- /dev/null 2003-09-15 06:40:47.000000000 -0700
-+++ 25-akpm/arch/i386/lib/kgdb_serial.c 2004-10-21 14:54:15.313595472 -0700
-@@ -0,0 +1,485 @@
-+/*
-+ * Serial interface GDB stub
-+ *
-+ * Written (hacked together) by David Grothe (dave@gcom.com)
-+ * Modified to allow invokation early in boot see also
-+ * kgdb.h for instructions by George Anzinger(george@mvista.com)
-+ *
-+ */
++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
+
-+#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/config.h>
-+#include <linux/major.h>
-+#include <linux/string.h>
-+#include <linux/fcntl.h>
-+#include <linux/ptrace.h>
-+#include <linux/ioport.h>
-+#include <linux/mm.h>
-+#include <linux/init.h>
-+#include <linux/highmem.h>
-+#include <asm/system.h>
-+#include <asm/io.h>
-+#include <asm/segment.h>
-+#include <asm/bitops.h>
-+#include <asm/system.h>
-+#include <asm/kgdb_local.h>
-+#ifdef CONFIG_KGDB_USER_CONSOLE
-+extern void kgdb_console_finit(void);
-+#endif
-+#define PRNT_off
-+#define TEST_EXISTANCE
-+#ifdef PRNT
-+#define dbprintk(s) printk s
-+#else
-+#define dbprintk(s)
-+#endif
-+#define TEST_INTERRUPT_off
-+#ifdef TEST_INTERRUPT
-+#define intprintk(s) printk s
-+#else
-+#define intprintk(s)
-+#endif
++SMP support
++==========
+
-+#define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT)
++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 occurred. Threads running on other processor(s) appear
++similar to other non-running threads in the 'info threads' output.
++Within the kgdb stub there is a structure "waiting_cpus" in which kgdb
++records the values of "current" and "regs" for each CPU other than the
++one that hit the breakpoint. "current" is a pointer to the task
++structure for the task that CPU is running, while "regs" points to the
++saved registers for the task. This structure can be examined with the
++gdb "p" command.
+
-+#define GDB_BUF_SIZE 512 /* power of 2, please */
++ia-32 hardware debugging registers on all processors are set to same
++values. Hence any hardware breakpoints may occur on any processor.
+
-+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;
++gdb troubleshooting
++===================
+
-+struct async_struct *gdb_async_info;
-+static int gdb_async_irq;
++1. gdb hangs
++Kill it. restart gdb. Connect to target machine.
+
-+#define outb_px(a,b) outb_p(b,a)
++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) to the serial line.
++e.g. echo -e "\003" > /dev/ttyS1
++This forces that target machine into the debugger, after which you
++can connect.
+
-+static void program_uart(struct async_struct *info);
-+static void write_char(struct async_struct *info, int chr);
-+/*
-+ * Get a byte from the hardware data buffer and return it
-+ */
-+static int
-+read_data_bfr(struct async_struct *info)
-+{
-+ char it = inb_p(info->port + UART_LSR);
++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
+
-+ if (it & UART_LSR_DR)
-+ return (inb_p(info->port + UART_RX));
-+ /*
-+ * If we have a framing error assume somebody messed with
-+ * our uart. Reprogram it and send '-' both ways...
-+ */
-+ if (it & 0xc) {
-+ program_uart(info);
-+ write_char(info, '-');
-+ return ('-');
-+ }
-+ return (-1);
++Check serial line speed and set it to correct value if required
++e.g. stty ispeed 115200 ospeed 115200 < /dev/ttyS1
+
-+} /* read_data_bfr */
++EVENTS
++======
+
-+/*
-+ * Get a char if available, return -1 if nothing available.
-+ * Empty the receive buffer first, then look at the interface hardware.
++Ever want to know the order of things happening? Which CPU did what and
++when? How did the spinlock get the way it is? Then events are for
++you. Events are defined by calls to an event collection interface and
++saved for later examination. In this case, kgdb events are saved by a
++very fast bit of code in kgdb which is fully SMP and interrupt protected
++and they are examined by using gdb to display them. Kgdb keeps only
++the last N events, where N must be a power of two and is defined at
++configure time.
+
-+ * Locking here is a bit of a problem. We MUST not lock out communication
-+ * if we are trying to talk to gdb about a kgdb entry. ON the other hand
-+ * we can loose chars in the console pass thru if we don't lock. It is also
-+ * possible that we could hold the lock or be waiting for it when kgdb
-+ * NEEDS to talk. Since kgdb locks down the world, it does not need locks.
-+ * We do, of course have possible issues with interrupting a uart operation,
-+ * but we will just depend on the uart status to help keep that straight.
+
-+ */
-+static spinlock_t uart_interrupt_lock = SPIN_LOCK_UNLOCKED;
-+#ifdef CONFIG_SMP
-+extern spinlock_t kgdb_spinlock;
-+#endif
++Events are signaled to kgdb by calling:
+
-+static int
-+read_char(struct async_struct *info)
-+{
-+ int chr;
-+ unsigned long flags;
-+ local_irq_save(flags);
++kgdb_ts(data0,data1)
++
++For each call kgdb records each call in an array along with other info.
++Here is the array definition:
++
++struct kgdb_and_then_struct {
+#ifdef CONFIG_SMP
-+ if (!spin_is_locked(&kgdb_spinlock)) {
-+ spin_lock(&uart_interrupt_lock);
-+ }
++ int on_cpu;
+#endif
-+ if (atomic_read(&gdb_buf_in_cnt) != 0) { /* intr routine has q'd chars */
-+ chr = gdb_buf[gdb_buf_out_inx++];
-+ gdb_buf_out_inx &= (GDB_BUF_SIZE - 1);
-+ atomic_dec(&gdb_buf_in_cnt);
-+ } else {
-+ chr = read_data_bfr(info);
-+ }
++ long long at_time;
++ int from_ln;
++ char * in_src;
++ void *from;
++ int with_if;
++ int data0;
++ int data1;
++};
++
++For SMP machines the CPU is recorded, for all machines the TSC is
++recorded (gets a time stamp) as well as the line number and source file
++the call was made from. The address of the (from), the "if" (interrupt
++flag) and the two data items are also recorded. The macro kgdb_ts casts
++the types to int, so you can put any 32-bit values here. There is a
++configure option to select the number of events you want to keep. A
++nice number might be 128, but you can keep up to 1024 if you want. The
++number must be a power of two. An "andthen" macro library is provided
++for gdb to help you look at these events. It is also possible to define
++a different structure for the event storage and cast the data to this
++structure. For example the following structure is defined in kgdb:
++
++struct kgdb_and_then_struct2 {
+#ifdef CONFIG_SMP
-+ if (!spin_is_locked(&kgdb_spinlock)) {
-+ spin_unlock(&uart_interrupt_lock);
-+ }
++ int on_cpu;
+#endif
-+ local_irq_restore(flags);
-+ return (chr);
-+}
++ long long at_time;
++ int from_ln;
++ char * in_src;
++ void *from;
++ int with_if;
++ struct task_struct *t1;
++ struct task_struct *t2;
++};
++
++If you use this for display, the data elements will be displayed as
++pointers to task_struct entries. You may want to define your own
++structure to use in casting. You should only change the last two items
++and you must keep the structure size the same. Kgdb will handle these
++as 32-bit ints, but within that constraint you can define a structure to
++cast to any 32-bit quantity. This need only be available to gdb and is
++only used for casting in the display code.
++
++Final Items
++===========
+
-+/*
-+ * Wait until the interface can accept a char, then write it.
-+ */
-+static void
-+write_char(struct async_struct *info, int chr)
-+{
-+ while (!(inb_p(info->port + UART_LSR) & UART_LSR_THRE)) ;
++I picked up this code from Amit S. Kale and enhanced it.
+
-+ outb_p(chr, info->port + UART_TX);
++If you make some really cool modification to this stuff, or if you
++fix a bug, please let me know.
+
-+} /* write_char */
++George Anzinger
++<george@mvista.com>
+
-+/*
-+ * Mostly we don't need a spinlock, but since the console goes
-+ * thru here with interrutps on, well, we need to catch those
-+ * chars.
-+ */
-+/*
-+ * 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 irqreturn_t
-+gdb_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-+{
-+ struct async_struct *info;
-+ unsigned long flags;
++Amit S. Kale
++<akale@veritas.com>
+
-+ info = gdb_async_info;
-+ if (!info || !info->tty || irq != gdb_async_irq)
-+ return IRQ_NONE;
++(First kgdb by David Grothe <dave@gcom.com>)
+
-+ local_irq_save(flags);
-+ spin_lock(&uart_interrupt_lock);
-+ do {
-+ int chr = read_data_bfr(info);
-+ intprintk(("Debug char on int: %x hex\n", chr));
-+ if (chr < 0)
-+ continue;
++(modified by Tigran Aivazian <tigran@sco.com>)
++ Putting gdbstub into the kernel config menu.
+
-+ if (chr == 3) { /* Ctrl-C means remote interrupt */
-+ BREAKPOINT;
-+ continue;
-+ }
++(modified by Scott Foehner <sfoehner@engr.sgi.com>)
++ Hooks for entering gdbstub at boot time.
+
-+ if (atomic_read(&gdb_buf_in_cnt) >= GDB_BUF_SIZE) {
-+ /* buffer overflow tosses early char */
-+ read_char(info);
-+ }
-+ gdb_buf[gdb_buf_in_inx++] = chr;
-+ gdb_buf_in_inx &= (GDB_BUF_SIZE - 1);
-+ } while (inb_p(info->port + UART_IIR) & UART_IIR_RDI);
-+ spin_unlock(&uart_interrupt_lock);
-+ local_irq_restore(flags);
-+ return IRQ_HANDLED;
-+} /* gdb_interrupt */
++(modified by Amit S. Kale <akale@veritas.com>)
++ Threads, ia-32 hw debugging, mp support, console support,
++ nmi watchdog handling.
+
-+/*
-+ * Just a NULL routine for testing.
-+ */
-+void
-+gdb_null(void)
-+{
-+} /* gdb_null */
++(modified by George Anzinger <george@mvista.com>)
++ Extended threads to include the idle threads.
++ Enhancements to allow breakpoint() at first C code.
++ Use of module_init() and __setup() to automate the configure.
++ Enhanced the cpu "collection" code to work in early bring-up.
++ Added ability to call functions from gdb
++ Print info thread stuff without going back to schedule()
++ Now collect the "other" cpus with an IPI/ NMI.
+Index: linux/Documentation/i386/kgdb/loadmodule.sh
+===================================================================
+--- linux.orig/Documentation/i386/kgdb/loadmodule.sh
++++ linux/Documentation/i386/kgdb/loadmodule.sh
+@@ -0,0 +1,78 @@
++#/bin/sh
++# This script loads a module on a target machine and generates a gdb script.
++# source generated gdb script to load the module file at appropriate addresses
++# in gdb.
++#
++# Usage:
++# Loading the module on target machine and generating gdb script)
++# [foo]$ loadmodule.sh <modulename>
++#
++# Loading the module file into gdb
++# (gdb) source <gdbscriptpath>
++#
++# Modify following variables according to your setup.
++# TESTMACHINE - Name of the target machine
++# GDBSCRIPTS - The directory where a gdb script will be generated
++#
++# Author: Amit S. Kale (akale@veritas.com).
++#
++# If you run into problems, please check files pointed to by following
++# variables.
++# ERRFILE - /tmp/<modulename>.errs contains stderr output of insmod
++# MAPFILE - /tmp/<modulename>.map contains stdout output of insmod
++# GDBSCRIPT - $GDBSCRIPTS/load<modulename> gdb script.
+
-+/* These structure are filled in with values defined in asm/kgdb_local.h
-+ */
-+static struct serial_state state = SB_STATE;
-+static struct async_struct local_info = SB_INFO;
-+static int ok_to_enable_ints = 0;
-+static void kgdb_enable_ints_now(void);
++TESTMACHINE=foo
++GDBSCRIPTS=/home/bar
+
-+extern char *kgdb_version;
-+/*
-+ * Hook an IRQ for KGDB.
-+ *
-+ * This routine is called from putDebugChar, below.
-+ */
-+static int ints_disabled = 1;
-+int
-+gdb_hook_interrupt(struct async_struct *info, int verb)
-+{
-+ struct serial_state *state = info->state;
-+ unsigned long flags;
-+ int port;
-+#ifdef TEST_EXISTANCE
-+ int scratch, scratch2;
-+#endif
++if [ $# -lt 1 ] ; then {
++ echo Usage: $0 modulefile
++ exit
++} ; fi
+
-+ /* The above fails if memory managment is not set up yet.
-+ * Rather than fail the set up, just keep track of the fact
-+ * and pick up the interrupt thing later.
-+ */
-+ gdb_async_info = info;
-+ port = gdb_async_info->port;
-+ gdb_async_irq = state->irq;
-+ if (verb) {
-+ printk("kgdb %s : port =%x, IRQ=%d, divisor =%d\n",
-+ kgdb_version,
-+ port,
-+ gdb_async_irq, gdb_async_info->state->custom_divisor);
-+ }
-+ local_irq_save(flags);
-+#ifdef TEST_EXISTANCE
-+ /* Existance test */
-+ /* Should not need all this, but just in case.... */
++MODULEFILE=$1
++MODULEFILEBASENAME=`basename $1`
+
-+ scratch = inb_p(port + UART_IER);
-+ outb_px(port + UART_IER, 0);
-+ outb_px(0xff, 0x080);
-+ scratch2 = inb_p(port + UART_IER);
-+ outb_px(port + UART_IER, scratch);
-+ if (scratch2) {
-+ printk
-+ ("gdb_hook_interrupt: Could not clear IER, not a UART!\n");
-+ local_irq_restore(flags);
-+ return 1; /* We failed; there's nothing here */
-+ }
-+ scratch2 = inb_p(port + UART_LCR);
-+ outb_px(port + UART_LCR, 0xBF); /* set up for StarTech test */
-+ outb_px(port + UART_EFR, 0); /* EFR is the same as FCR */
-+ outb_px(port + UART_LCR, 0);
-+ outb_px(port + UART_FCR, UART_FCR_ENABLE_FIFO);
-+ scratch = inb_p(port + UART_IIR) >> 6;
-+ if (scratch == 1) {
-+ printk("gdb_hook_interrupt: Undefined UART type!"
-+ " Not a UART! \n");
-+ local_irq_restore(flags);
-+ return 1;
-+ } else {
-+ dbprintk(("gdb_hook_interrupt: UART type "
-+ "is %d where 0=16450, 2=16550 3=16550A\n", scratch));
-+ }
-+ scratch = inb_p(port + UART_MCR);
-+ outb_px(port + UART_MCR, UART_MCR_LOOP | scratch);
-+ outb_px(port + UART_MCR, UART_MCR_LOOP | 0x0A);
-+ scratch2 = inb_p(port + UART_MSR) & 0xF0;
-+ outb_px(port + UART_MCR, scratch);
-+ if (scratch2 != 0x90) {
-+ printk("gdb_hook_interrupt: "
-+ "Loop back test failed! Not a UART!\n");
-+ local_irq_restore(flags);
-+ return scratch2 + 1000; /* force 0 to fail */
++if [ $MODULEFILE = $MODULEFILEBASENAME ] ; then {
++ MODULEFILE=`pwd`/$MODULEFILE
++} fi
++
++ERRFILE=/tmp/$MODULEFILEBASENAME.errs
++MAPFILE=/tmp/$MODULEFILEBASENAME.map
++GDBSCRIPT=$GDBSCRIPTS/load$MODULEFILEBASENAME
++
++function findaddr() {
++ local ADDR=0x$(echo "$SEGMENTS" | \
++ grep "$1" | sed 's/^[^ ]*[ ]*[^ ]*[ ]*//' | \
++ sed 's/[ ]*[^ ]*$//')
++ echo $ADDR
++}
++
++function checkerrs() {
++ if [ "`cat $ERRFILE`" != "" ] ; then {
++ cat $ERRFILE
++ exit
++ } fi
++}
++
++#load the module
++echo Copying $MODULEFILE to $TESTMACHINE
++rcp $MODULEFILE root@${TESTMACHINE}:
++
++echo Loading module $MODULEFILE
++rsh -l root $TESTMACHINE /sbin/insmod -m ./`basename $MODULEFILE` \
++ > $MAPFILE 2> $ERRFILE
++checkerrs
++
++SEGMENTS=`head -n 11 $MAPFILE | tail -n 10`
++TEXTADDR=$(findaddr "\\.text[^.]")
++LOADSTRING="add-symbol-file $MODULEFILE $TEXTADDR"
++SEGADDRS=`echo "$SEGMENTS" | awk '//{
++ if ($1 != ".text" && $1 != ".this" &&
++ $1 != ".kstrtab" && $1 != ".kmodtab") {
++ print " -s " $1 " 0x" $3 " "
+ }
-+#endif /* test existance */
-+ program_uart(info);
-+ local_irq_restore(flags);
++}'`
++LOADSTRING="$LOADSTRING $SEGADDRS"
++echo Generating script $GDBSCRIPT
++echo $LOADSTRING > $GDBSCRIPT
+Index: linux/MAINTAINERS
+===================================================================
+--- linux.orig/MAINTAINERS
++++ linux/MAINTAINERS
+@@ -1242,6 +1242,12 @@ W: http://sf.net/projects/kernel-janitor
+ W: http://developer.osdl.org/rddunlap/kj-patches/
+ S: Maintained
+
++KGDB FOR I386 PLATFORM
++P: George Anzinger
++M: george@mvista.com
++L: linux-net@vger.kernel.org
++S: Supported
+
-+ return (0);
+ KERNEL NFSD
+ P: Neil Brown
+ M: neilb@cse.unsw.edu.au
+Index: linux/arch/i386/Kconfig
+===================================================================
+--- linux.orig/arch/i386/Kconfig
++++ linux/arch/i386/Kconfig
+@@ -1250,6 +1250,14 @@ menu "Executable file formats"
+
+ source "fs/Kconfig.binfmt"
+
++config TRAP_BAD_SYSCALL_EXITS
++ bool "Debug bad system call exits"
++ depends on KGDB
++ help
++ If you say Y here the kernel will check for system calls which
++ return without clearing preempt.
++ default n
+
-+} /* gdb_hook_interrupt */
+ endmenu
+
+ source "drivers/Kconfig"
+Index: linux/arch/i386/Kconfig.debug
+===================================================================
+--- linux.orig/arch/i386/Kconfig.debug
++++ linux/arch/i386/Kconfig.debug
+@@ -77,4 +77,6 @@ config X86_MPPARSE
+ depends on X86_LOCAL_APIC && !X86_VISWS
+ default y
+
++source "arch/i386/Kconfig.kgdb"
+
-+static void
-+program_uart(struct async_struct *info)
-+{
-+ int port = info->port;
+ endmenu
+Index: linux/arch/i386/Kconfig.kgdb
+===================================================================
+--- linux.orig/arch/i386/Kconfig.kgdb
++++ linux/arch/i386/Kconfig.kgdb
+@@ -0,0 +1,175 @@
++config KGDB
++ bool "Include kgdb kernel debugger"
++ depends on DEBUG_KERNEL
++ help
++ If you say Y here, the system will be compiled with the debug
++ option (-g) and a debugging stub will be included in the
++ kernel. This stub communicates with gdb on another (host)
++ computer via a serial port. The host computer should have
++ access to the kernel binary file (vmlinux) and a serial port
++ that is connected to the target machine. Gdb can be made to
++ configure the serial port or you can use stty and setserial to
++ do this. See the 'target' command in gdb. This option also
++ configures in the ability to request a breakpoint early in the
++ boot process. To request the breakpoint just include 'kgdb'
++ as a boot option when booting the target machine. The system
++ will then break as soon as it looks at the boot options. This
++ option also installs a breakpoint in panic and sends any
++ kernel faults to the debugger. For more information see the
++ Documentation/i386/kgdb/kgdb.txt file.
+
-+ (void) inb_p(port + UART_RX);
-+ outb_px(port + UART_IER, 0);
++choice
++ depends on KGDB
++ prompt "Debug serial port BAUD"
++ default KGDB_115200BAUD
++ help
++ Gdb and the kernel stub need to agree on the baud rate to be
++ used. Some systems (x86 family at this writing) allow this to
++ be configured.
+
-+ (void) inb_p(port + UART_RX); /* serial driver comments say */
-+ (void) inb_p(port + UART_IIR); /* this clears the interrupt regs */
-+ (void) inb_p(port + UART_MSR);
-+ outb_px(port + UART_LCR, UART_LCR_WLEN8 | UART_LCR_DLAB);
-+ outb_px(port + UART_DLL, info->state->custom_divisor & 0xff); /* LS */
-+ outb_px(port + UART_DLM, info->state->custom_divisor >> 8); /* MS */
-+ outb_px(port + UART_MCR, info->MCR);
++config KGDB_9600BAUD
++ bool "9600"
+
-+ outb_px(port + UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1 | UART_FCR_CLEAR_XMIT | UART_FCR_CLEAR_RCVR); /* set fcr */
-+ outb_px(port + UART_LCR, UART_LCR_WLEN8); /* reset DLAB */
-+ outb_px(port + UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1); /* set fcr */
-+ if (!ints_disabled) {
-+ intprintk(("KGDB: Sending %d to port %x offset %d\n",
-+ gdb_async_info->IER,
-+ (int) gdb_async_info->port, UART_IER));
-+ outb_px(gdb_async_info->port + UART_IER, gdb_async_info->IER);
-+ }
-+ return;
-+}
++config KGDB_19200BAUD
++ bool "19200"
+
-+/*
-+ * 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. In the
-+ */
-+int kgdb_in_isr = 0;
-+int kgdb_in_lsr = 0;
-+extern spinlock_t kgdb_spinlock;
++config KGDB_38400BAUD
++ bool "38400"
+
-+/* Caller takes needed protections */
++config KGDB_57600BAUD
++ bool "57600"
+
-+int
-+getDebugChar(void)
-+{
-+ volatile int chr, dum, time, end_time;
++config KGDB_115200BAUD
++ bool "115200"
++endchoice
+
-+ dbprintk(("getDebugChar(port %x): ", gdb_async_info->port));
++config KGDB_PORT
++ hex "hex I/O port address of the debug serial port"
++ depends on KGDB
++ default 3f8
++ help
++ Some systems (x86 family at this writing) allow the port
++ address to be configured. The number entered is assumed to be
++ hex, don't put 0x in front of it. The standard address are:
++ COM1 3f8 , irq 4 and COM2 2f8 irq 3. Setserial /dev/ttySx
++ will tell you what you have. It is good to test the serial
++ connection with a live system before trying to debug.
+
-+ if (gdb_async_info == NULL) {
-+ gdb_hook_interrupt(&local_info, 0);
-+ }
-+ /*
-+ * This trick says if we wait a very long time and get
-+ * no char, return the -1 and let the upper level deal
-+ * with it.
-+ */
-+ rdtsc(dum, time);
-+ end_time = time + 2;
-+ while (((chr = read_char(gdb_async_info)) == -1) &&
-+ (end_time - time) > 0) {
-+ rdtsc(dum, time);
-+ };
-+ /*
-+ * This covers our butts if some other code messes with
-+ * our uart, hay, it happens :o)
-+ */
-+ if (chr == -1)
-+ program_uart(gdb_async_info);
++config KGDB_IRQ
++ int "IRQ of the debug serial port"
++ depends on KGDB
++ default 4
++ help
++ This is the irq for the debug port. If everything is working
++ correctly and the kernel has interrupts on a control C to the
++ port should cause a break into the kernel debug stub.
+
-+ dbprintk(("%c\n", chr > ' ' && chr < 0x7F ? chr : ' '));
-+ return (chr);
++config DEBUG_INFO
++ bool
++ depends on KGDB
++ default y
+
-+} /* getDebugChar */
++config KGDB_MORE
++ bool "Add any additional compile options"
++ depends on KGDB
++ default n
++ help
++ Saying yes here turns on the ability to enter additional
++ compile options.
+
-+static int count = 3;
-+static spinlock_t one_at_atime = SPIN_LOCK_UNLOCKED;
+
-+static int __init
-+kgdb_enable_ints(void)
-+{
-+ if (gdb_async_info == NULL) {
-+ gdb_hook_interrupt(&local_info, 1);
-+ }
-+ ok_to_enable_ints = 1;
-+ kgdb_enable_ints_now();
-+#ifdef CONFIG_KGDB_USER_CONSOLE
-+ kgdb_console_finit();
-+#endif
-+ return 0;
-+}
++config KGDB_OPTIONS
++ depends on KGDB_MORE
++ string "Additional compile arguments"
++ default "-O1"
++ help
++ This option allows you enter additional compile options for
++ the whole kernel compile. Each platform will have a default
++ that seems right for it. For example on PPC "-ggdb -O1", and
++ for i386 "-O1". Note that by configuring KGDB "-g" is already
++ turned on. In addition, on i386 platforms
++ "-fomit-frame-pointer" is deleted from the standard compile
++ options.
+
-+#ifdef CONFIG_SERIAL_8250
-+void shutdown_for_kgdb(struct async_struct *gdb_async_info);
-+#endif
++config NO_KGDB_CPUS
++ int "Number of CPUs"
++ depends on KGDB && SMP
++ default NR_CPUS
++ help
+
-+#ifdef CONFIG_DISCONTIGMEM
-+static inline int kgdb_mem_init_done(void)
-+{
-+ return highmem_start_page != NULL;
-+}
-+#else
-+static inline int kgdb_mem_init_done(void)
-+{
-+ return max_mapnr != 0;
-+}
-+#endif
++ This option sets the number of cpus for kgdb ONLY. It is used
++ to prune some internal structures so they look "nice" when
++ displayed with gdb. This is to overcome possibly larger
++ numbers that may have been entered above. Enter the real
++ number to get nice clean kgdb_info displays.
+
-+static void
-+kgdb_enable_ints_now(void)
-+{
-+ if (!spin_trylock(&one_at_atime))
-+ return;
-+ if (!ints_disabled)
-+ goto exit;
-+ if (kgdb_mem_init_done() &&
-+ ints_disabled) { /* don't try till mem init */
-+#ifdef CONFIG_SERIAL_8250
-+ /*
-+ * The ifdef here allows the system to be configured
-+ * without the serial driver.
-+ * Don't make it a module, however, it will steal the port
-+ */
-+ shutdown_for_kgdb(gdb_async_info);
-+#endif
-+ ints_disabled = request_irq(gdb_async_info->state->irq,
-+ gdb_interrupt,
-+ IRQ_T(gdb_async_info),
-+ "KGDB-stub", NULL);
-+ intprintk(("KGDB: request_irq returned %d\n", ints_disabled));
-+ }
-+ if (!ints_disabled) {
-+ intprintk(("KGDB: Sending %d to port %x offset %d\n",
-+ gdb_async_info->IER,
-+ (int) gdb_async_info->port, UART_IER));
-+ outb_px(gdb_async_info->port + UART_IER, gdb_async_info->IER);
-+ }
-+ exit:
-+ spin_unlock(&one_at_atime);
-+}
++config KGDB_TS
++ bool "Enable kgdb time stamp macros?"
++ depends on KGDB
++ default n
++ help
++ Kgdb event macros allow you to instrument your code with calls
++ to the kgdb event recording function. The event log may be
++ examined with gdb at a break point. Turning on this
++ capability also allows you to choose how many events to
++ keep. Kgdb always keeps the lastest events.
++
++choice
++ depends on KGDB_TS
++ prompt "Max number of time stamps to save?"
++ default KGDB_TS_128
+
-+/*
-+ * 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. Caller takes needed protections.
-+ */
-+void
-+putDebugChar(int chr)
-+{
-+ dbprintk(("putDebugChar(port %x): chr=%02x '%c', ints_on=%d\n",
-+ gdb_async_info->port,
-+ chr,
-+ chr > ' ' && chr < 0x7F ? chr : ' ', ints_disabled ? 0 : 1));
++config KGDB_TS_64
++ bool "64"
+
-+ if (gdb_async_info == NULL) {
-+ gdb_hook_interrupt(&local_info, 0);
-+ }
++config KGDB_TS_128
++ bool "128"
+
-+ write_char(gdb_async_info, chr); /* this routine will wait */
-+ count = (chr == '#') ? 0 : count + 1;
-+ if ((count == 2)) { /* try to enable after */
-+ if (ints_disabled & ok_to_enable_ints)
-+ kgdb_enable_ints_now(); /* try to enable after */
++config KGDB_TS_256
++ bool "256"
+
-+ /* We do this a lot because, well we really want to get these
-+ * interrupts. The serial driver will clear these bits when it
-+ * initializes the chip. Every thing else it does is ok,
-+ * but this.
-+ */
-+ if (!ints_disabled) {
-+ outb_px(gdb_async_info->port + UART_IER,
-+ gdb_async_info->IER);
-+ }
-+ }
++config KGDB_TS_512
++ bool "512"
+
-+} /* putDebugChar */
++config KGDB_TS_1024
++ bool "1024"
+
-+module_init(kgdb_enable_ints);
-diff -puN arch/i386/lib/Makefile~kgdb-ga arch/i386/lib/Makefile
---- 25/arch/i386/lib/Makefile~kgdb-ga 2004-10-21 14:54:15.265602768 -0700
-+++ 25-akpm/arch/i386/lib/Makefile 2004-10-21 14:54:15.313595472 -0700
-@@ -8,3 +8,4 @@ lib-y = checksum.o delay.o usercopy.o ge
-
- lib-$(CONFIG_X86_USE_3DNOW) += mmx.o
- lib-$(CONFIG_HAVE_DEC_LOCK) += dec_and_lock.o
-+lib-$(CONFIG_KGDB) += kgdb_serial.o
-diff -puN arch/i386/Makefile~kgdb-ga arch/i386/Makefile
---- 25/arch/i386/Makefile~kgdb-ga 2004-10-21 14:54:15.266602616 -0700
-+++ 25-akpm/arch/i386/Makefile 2004-10-21 14:54:15.314595320 -0700
-@@ -99,6 +99,9 @@ core-$(CONFIG_X86_ES7000) := arch/i386/m
++endchoice
++
++config STACK_OVERFLOW_TEST
++ bool "Turn on kernel stack overflow testing?"
++ depends on KGDB
++ default n
++ help
++ This option enables code in the front line interrupt handlers
++ to check for kernel stack overflow on interrupts and system
++ calls. This is part of the kgdb code on x86 systems.
++
++config KGDB_CONSOLE
++ bool "Enable serial console thru kgdb port"
++ depends on KGDB
++ default n
++ help
++ This option enables the command line "console=kgdb" option.
++ When the system is booted with this option in the command line
++ all kernel printk output is sent to gdb (as well as to other
++ consoles). For this to work gdb must be connected. For this
++ reason, this command line option will generate a breakpoint if
++ gdb has not yet connected. After the gdb continue command is
++ given all pent up console output will be printed by gdb on the
++ host machine. Neither this option, nor KGDB require the
++ serial driver to be configured.
++
++config KGDB_SYSRQ
++ bool "Turn on SysRq 'G' command to do a break?"
++ depends on KGDB
++ default y
++ help
++ This option includes an option in the SysRq code that allows
++ you to enter SysRq G which generates a breakpoint to the KGDB
++ stub. This will work if the keyboard is alive and can
++ interrupt the system. Because of constraints on when the
++ serial port interrupt can be enabled, this code may allow you
++ to interrupt the system before the serial port control C is
++ available. Just say yes here.
++
+Index: linux/arch/i386/Makefile
+===================================================================
+--- linux.orig/arch/i386/Makefile
++++ linux/arch/i386/Makefile
+@@ -98,6 +98,9 @@ core-$(CONFIG_X86_ES7000) := arch/i386/m
# default subarch .h files
mflags-y += -Iinclude/asm-i386/mach-default
head-y := arch/i386/kernel/head.o arch/i386/kernel/init_task.o
libs-y += arch/i386/lib/
-diff -puN arch/i386/mm/fault.c~kgdb-ga arch/i386/mm/fault.c
---- 25/arch/i386/mm/fault.c~kgdb-ga 2004-10-21 14:54:15.268602312 -0700
-+++ 25-akpm/arch/i386/mm/fault.c 2004-10-21 14:54:15.314595320 -0700
-@@ -430,6 +430,12 @@ no_context:
- * Oops. The kernel tried to access some bad page. We'll have to
- * terminate things with extreme prejudice.
- */
-+#ifdef CONFIG_KGDB
-+ if (!user_mode(regs)){
-+ kgdb_handle_exception(14,SIGBUS, error_code, regs);
-+ return;
-+ }
+Index: linux/arch/i386/kernel/Makefile
+===================================================================
+--- linux.orig/arch/i386/kernel/Makefile
++++ linux/arch/i386/kernel/Makefile
+@@ -14,6 +14,7 @@ obj-y += timers/
+ obj-$(CONFIG_ACPI_BOOT) += acpi/
+ obj-$(CONFIG_X86_BIOS_REBOOT) += reboot.o
+ obj-$(CONFIG_MCA) += mca.o
++obj-$(CONFIG_KGDB) += kgdb_stub.o
+ obj-$(CONFIG_X86_MSR) += msr.o
+ obj-$(CONFIG_X86_CPUID) += cpuid.o
+ obj-$(CONFIG_MICROCODE) += microcode.o
+Index: linux/arch/i386/kernel/entry.S
+===================================================================
+--- linux.orig/arch/i386/kernel/entry.S
++++ linux/arch/i386/kernel/entry.S
+@@ -50,6 +50,18 @@
+ #include <asm/smp.h>
+ #include <asm/page.h>
+ #include "irq_vectors.h"
++ /* We do not recover from a stack overflow, but at least
++ * we know it happened and should be able to track it down.
++ */
++#ifdef CONFIG_STACK_OVERFLOW_TEST
++#define STACK_OVERFLOW_TEST \
++ testl $(THREAD_SIZE - 512),%esp; \
++ jnz 10f; \
++ call stack_overflow; \
++10:
++#else
++#define STACK_OVERFLOW_TEST
+#endif
- bust_spinlocks(1);
-
-diff -puN arch/x86_64/boot/compressed/head.S~kgdb-ga arch/x86_64/boot/compressed/head.S
---- 25/arch/x86_64/boot/compressed/head.S~kgdb-ga 2004-10-21 14:54:15.269602160 -0700
-+++ 25-akpm/arch/x86_64/boot/compressed/head.S 2004-10-21 14:54:15.315595168 -0700
-@@ -26,6 +26,7 @@
- .code32
- .text
-
-+#define IN_BOOTLOADER
- #include <linux/linkage.h>
- #include <asm/segment.h>
+ #define nr_syscalls ((syscall_table_size)/4)
-diff -puN arch/x86_64/boot/compressed/misc.c~kgdb-ga arch/x86_64/boot/compressed/misc.c
---- 25/arch/x86_64/boot/compressed/misc.c~kgdb-ga 2004-10-21 14:54:15.270602008 -0700
-+++ 25-akpm/arch/x86_64/boot/compressed/misc.c 2004-10-21 14:54:15.315595168 -0700
-@@ -9,6 +9,7 @@
- * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
- */
+@@ -191,7 +203,8 @@ int80_ret_end_marker: \
+ pushl %ebx; \
+ movl $(__USER_DS), %edx; \
+ movl %edx, %ds; \
+- movl %edx, %es;
++ movl %edx, %es; \
++ STACK_OVERFLOW_TEST
-+#define IN_BOOTLOADER
- #include "miscsetup.h"
- #include <asm/io.h>
+ #define __RESTORE_INT_REGS \
+ popl %ebx; \
+@@ -357,6 +370,7 @@ need_resched:
+ # sysenter call handler stub
+ ENTRY(sysenter_entry)
+ movl TSS_sysenter_esp0(%esp),%esp
++ .globl sysenter_past_esp
+ sysenter_past_esp:
+ sti
+ pushl $(__USER_DS)
+@@ -437,6 +451,19 @@ syscall_exit:
+ testw $_TIF_ALLWORK_MASK, %cx # current->work
+ jne syscall_exit_work
+ restore_all:
++#ifdef CONFIG_TRAP_BAD_SYSCALL_EXITS
++ movl EFLAGS(%esp), %eax # mix EFLAGS and CS
++ movb CS(%esp), %al
++ testl $(VM_MASK | 3), %eax
++ jz resume_kernelX # returning to kernel or vm86-space
++
++ cmpl $0,TI_preempt_count(%ebp) # non-zero preempt_count ?
++ jz resume_kernelX
++
++ int $3
++
++resume_kernelX:
++#endif
+ RESTORE_ALL
-diff -puN /dev/null Documentation/i386/kgdb/andthen
---- /dev/null 2003-09-15 06:40:47.000000000 -0700
-+++ 25-akpm/Documentation/i386/kgdb/andthen 2004-10-21 14:54:15.316595016 -0700
-@@ -0,0 +1,100 @@
+ # perform work that needs to be done immediately before resumption
+Index: linux/arch/i386/kernel/kgdb_stub.c
+===================================================================
+--- linux.orig/arch/i386/kernel/kgdb_stub.c
++++ linux/arch/i386/kernel/kgdb_stub.c
+@@ -0,0 +1,2330 @@
++/*
++ *
++ * 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 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: David Grothe <dave@gcom.com>
++ * ModuleState: Experimental $
++ *
++ * NOTES: See Below $
++ *
++ * Modified for 386 by Jim Kingdon, Cygnus Support.
++ * Compatibility with 2.1.xx kernel by David Grothe <dave@gcom.com>
++ *
++ * Changes to allow auto initilization. All that is needed is that it
++ * be linked with the kernel and a break point (int 3) be executed.
++ * The header file <asm/kgdb.h> defines BREAKPOINT to allow one to do
++ * this. It should also be possible, once the interrupt system is up, to
++ * call putDebugChar("+"). Once this is done, the remote debugger should
++ * get our attention by sending a ^C in a packet. George Anzinger
++ * <george@mvista.com>
++ * Integrated into 2.2.5 kernel by Tigran Aivazian <tigran@sco.com>
++ * Added thread support, support for multiple processors,
++ * support for ia-32(x86) hardware debugging.
++ * 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
++ *
++ ****************************************************************************/
++#define KGDB_VERSION "<20030915.1651.33>"
++#include <linux/config.h>
++#include <linux/types.h>
++#include <asm/string.h> /* for strcpy */
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <asm/vm86.h>
++#include <asm/system.h>
++#include <asm/ptrace.h> /* for linux pt_regs struct */
++#include <asm/kgdb_local.h>
++#include <linux/list.h>
++#include <asm/atomic.h>
++#include <asm/processor.h>
++#include <linux/irq.h>
++#include <asm/desc.h>
+
-+define set_andthen
-+ set var $thp=0
-+ set var $thp=(struct kgdb_and_then_struct *)&kgdb_data[0]
-+ set var $at_size = (sizeof kgdb_data)/(sizeof *$thp)
-+ set var $at_oc=kgdb_and_then_count
-+ set var $at_cc=$at_oc
-+end
++/************************************************************************
++ *
++ * external low-level support routines
++ */
++typedef void (*Function) (void); /* pointer to a function */
+
-+define andthen_next
-+ set var $at_cc=$arg0
-+end
++/* Thread reference */
++typedef unsigned char threadref[8];
+
-+define andthen
-+ andthen_set_edge
-+ if ($at_cc >= $at_oc)
-+ printf "Outside window. Window size is %d\n",($at_oc-$at_low)
-+ else
-+ printf "%d: ",$at_cc
-+ output *($thp+($at_cc++ % $at_size ))
-+ printf "\n"
-+ end
-+end
-+define andthen_set_edge
-+ set var $at_oc=kgdb_and_then_count
-+ set var $at_low = $at_oc - $at_size
-+ if ($at_low < 0 )
-+ set var $at_low = 0
-+ end
-+ if (( $at_cc > $at_oc) || ($at_cc < $at_low))
-+ printf "Count outside of window, setting count to "
-+ if ($at_cc >= $at_oc)
-+ set var $at_cc = $at_oc
-+ else
-+ set var $at_cc = $at_low
-+ end
-+ printf "%d\n",$at_cc
-+ end
-+end
++extern void putDebugChar(int); /* write a single character */
++extern int getDebugChar(void); /* read and return a single char */
+
-+define beforethat
-+ andthen_set_edge
-+ if ($at_cc <= $at_low)
-+ printf "Outside window. Window size is %d\n",($at_oc-$at_low)
-+ else
-+ printf "%d: ",$at_cc-1
-+ output *($thp+(--$at_cc % $at_size ))
-+ printf "\n"
-+ end
-+end
++/************************************************************************/
++/* 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 400
+
-+document andthen_next
-+ andthen_next <count>
-+ . sets the number of the event to display next. If this event
-+ . is not in the event pool, either andthen or beforethat will
-+ . correct it to the nearest event pool edge. The event pool
-+ . ends at the last event recorded and begins <number of events>
-+ . prior to that. If beforethat is used next, it will display
-+ . event <count> -1.
-+.
-+ andthen commands are: set_andthen, andthen_next, andthen and beforethat
-+end
++char *kgdb_version = KGDB_VERSION;
+
++/* debug > 0 prints ill-formed commands in valid packets & checksum errors */
++int debug_regs = 0; /* set to non-zero to print registers */
+
-+document andthen
-+ andthen
-+. displays the next event in the list. <set_andthen> sets up to display
-+. the oldest saved event first.
-+. <count> (optional) count of the event to display.
-+. note the number of events saved is specified at configure time.
-+. if events are saved between calls to andthen the index will change
-+. but the displayed event will be the next one (unless the event buffer
-+. is overrun).
-+.
-+. andthen commands are: set_andthen, andthen_next, andthen and beforethat
-+end
++/* filled in by an external module */
++char *gdb_module_offsets;
+
-+document set_andthen
-+ set_andthen
-+. sets up to use the <andthen> and <beforethat> commands.
-+. if you have defined your own struct, use the above and
-+. then enter the following:
-+. p $thp=(struct kgdb_and_then_structX *)&kgdb_data[0]
-+. where <kgdb_and_then_structX> is the name of your structure.
-+.
-+. andthen commands are: set_andthen, andthen_next, andthen and beforethat
-+end
++static const char hexchars[] = "0123456789abcdef";
+
-+document beforethat
-+ beforethat
-+. displays the next prior event in the list. <set_andthen> sets up to
-+. display the last occuring event first.
-+.
-+. note the number of events saved is specified at configure time.
-+. if events are saved between calls to beforethat the index will change
-+. but the displayed event will be the next one (unless the event buffer
-+. is overrun).
-+.
-+. andthen commands are: set_andthen, andthen_next, andthen and beforethat
-+end
-diff -puN /dev/null Documentation/i386/kgdb/debug-nmi.txt
---- /dev/null 2003-09-15 06:40:47.000000000 -0700
-+++ 25-akpm/Documentation/i386/kgdb/debug-nmi.txt 2004-10-21 14:54:15.316595016 -0700
-@@ -0,0 +1,37 @@
-+Subject: Debugging with NMI
-+Date: Mon, 12 Jul 1999 11:28:31 -0500
-+From: David Grothe <dave@gcom.com>
-+Organization: Gcom, Inc
-+To: David Grothe <dave@gcom.com>
++/* 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 */
++};
+
-+Kernel hackers:
++/*************************** ASSEMBLY CODE MACROS *************************/
++/*
++ * Put the error code here just in case the user cares.
++ * Likewise, the vector number here (since GDB only gets the signal
++ * number through the usual means, and that's not very specific).
++ * The called_from is the return address so he can tell how we entered kgdb.
++ * This will allow him to seperate out the various possible entries.
++ */
++#define REMOTE_DEBUG 0 /* set != to turn on printing (also available in info) */
+
-+Maybe this is old hat, but it is new to me --
++#define PID_MAX PID_MAX_DEFAULT
+
-+On an ISA bus machine, if you short out the A1 and B1 pins of an ISA
-+slot you will generate an NMI to the CPU. This interrupts even a
-+machine that is hung in a loop with interrupts disabled. Used in
-+conjunction with kgdb <
-+ftp://ftp.gcom.com/pub/linux/src/kgdb-2.3.35/kgdb-2.3.35.tgz > you can
-+gain debugger control of a machine that is hung in the kernel! Even
-+without kgdb the kernel will print a stack trace so you can find out
-+where it was hung.
++#ifdef CONFIG_SMP
++void smp_send_nmi_allbutself(void);
++#define IF_SMP(x) x
++#undef MAX_NO_CPUS
++#ifndef CONFIG_NO_KGDB_CPUS
++#define CONFIG_NO_KGDB_CPUS 2
++#endif
++#if CONFIG_NO_KGDB_CPUS > NR_CPUS
++#define MAX_NO_CPUS NR_CPUS
++#else
++#define MAX_NO_CPUS CONFIG_NO_KGDB_CPUS
++#endif
++#define hold_init hold_on_sstep: 1,
++#define MAX_CPU_MASK (unsigned long)((1LL << MAX_NO_CPUS) - 1LL)
++#define NUM_CPUS num_online_cpus()
++#else
++#define IF_SMP(x)
++#define hold_init
++#undef MAX_NO_CPUS
++#define MAX_NO_CPUS 1
++#define NUM_CPUS 1
++#endif
++#define NOCPU (struct task_struct *)0xbad1fbad
++/* *INDENT-OFF* */
++struct kgdb_info {
++ int used_malloc;
++ void *called_from;
++ long long entry_tsc;
++ int errcode;
++ int vector;
++ int print_debug_info;
++#ifdef CONFIG_SMP
++ int hold_on_sstep;
++ struct {
++ volatile struct task_struct *task;
++ int pid;
++ int hold;
++ struct pt_regs *regs;
++ } cpus_waiting[MAX_NO_CPUS];
++#endif
++} kgdb_info = {hold_init print_debug_info:REMOTE_DEBUG, vector:-1};
+
-+The A1/B1 pins are directly opposite one another and the farthest pins
-+towards the bracket end of the ISA bus socket. You can stick a paper
-+clip or multi-meter probe between them to short them out.
++/* *INDENT-ON* */
+
-+I had a spare ISA bus to PC104 bus adapter around. The PC104 end of the
-+board consists of two rows of wire wrap pins. So I wired a push button
-+between the A1/B1 pins and now have an ISA board that I can stick into
-+any ISA bus slot for debugger entry.
++#define used_m kgdb_info.used_malloc
++/*
++ * This is little area we set aside to contain the stack we
++ * need to build to allow gdb to call functions. We use one
++ * per cpu to avoid locking issues. We will do all this work
++ * with interrupts off so that should take care of the protection
++ * issues.
++ */
++#define LOOKASIDE_SIZE 200 /* should be more than enough */
++#define MALLOC_MAX 200 /* Max malloc size */
++struct {
++ unsigned int esp;
++ int array[LOOKASIDE_SIZE];
++} fn_call_lookaside[MAX_NO_CPUS];
++
++static int trap_cpu;
++static unsigned int OLD_esp;
+
-+Microsoft has a circuit diagram of a PCI card at
-+http://www.microsoft.com/hwdev/DEBUGGING/DMPSW.HTM. If you want to
-+build one you will have to mail them and ask for the PAL equations.
-+Nobody makes one comercially.
++#define END_OF_LOOKASIDE &fn_call_lookaside[trap_cpu].array[LOOKASIDE_SIZE]
++#define IF_BIT 0x200
++#define TF_BIT 0x100
+
-+[THIS TIP COMES WITH NO WARRANTY WHATSOEVER. It works for me, but if
-+your machine catches fire, it is your problem, not mine.]
++#define MALLOC_ROUND 8-1
+
-+-- Dave (the kgdb guy)
-diff -puN /dev/null Documentation/i386/kgdb/gdb-globals.txt
---- /dev/null 2003-09-15 06:40:47.000000000 -0700
-+++ 25-akpm/Documentation/i386/kgdb/gdb-globals.txt 2004-10-21 14:54:15.317594864 -0700
-@@ -0,0 +1,71 @@
-+Sender: akale@veritas.com
-+Date: Fri, 23 Jun 2000 19:26:35 +0530
-+From: "Amit S. Kale" <akale@veritas.com>
-+Organization: Veritas Software (India)
-+To: Dave Grothe <dave@gcom.com>, linux-kernel@vger.rutgers.edu
-+CC: David Milburn <dmilburn@wirespeed.com>,
-+ "Edouard G. Parmelan" <Edouard.Parmelan@quadratec.fr>,
-+ ezannoni@cygnus.com, Keith Owens <kaos@ocs.com.au>
-+Subject: Re: Module debugging using kgdb
++static char malloc_array[MALLOC_MAX];
++IF_SMP(static void to_gdb(const char *mess));
++void *
++malloc(int size)
++{
+
-+Dave Grothe wrote:
-+>
-+> Amit:
-+>
-+> There is a 2.4.0 version of kgdb on our ftp site:
-+> ftp://ftp.gcom.com/pub/linux/src/kgdb. I mirrored your version of gdb
-+> and loadmodule.sh there.
-+>
-+> Have a look at the README file and see if I go it right. If not, send
-+> me some corrections and I will update it.
-+>
-+> Does your version of gdb solve the global variable problem?
++ if (size <= (MALLOC_MAX - used_m)) {
++ int old_used = used_m;
++ used_m += ((size + MALLOC_ROUND) & (~MALLOC_ROUND));
++ return &malloc_array[old_used];
++ } else {
++ return NULL;
++ }
++}
+
-+Yes.
-+Thanks to Elena Zanoni, gdb (developement version) can now calculate
-+correctly addresses of dynamically loaded object files. I have not been
-+following gdb developement for sometime and am not sure when symbol
-+address calculation fix is going to appear in a gdb stable version.
++/*
++ * Gdb calls functions by pushing agruments, including a return address
++ * on the stack and the adjusting EIP to point to the function. The
++ * whole assumption in GDB is that we are on a different stack than the
++ * one the "user" i.e. code that hit the break point, is on. This, of
++ * course is not true in the kernel. Thus various dodges are needed to
++ * do the call without directly messing with EIP (which we can not change
++ * as it is just a location and not a register. To adjust it would then
++ * require that we move every thing below EIP up or down as needed. This
++ * will not work as we may well have stack relative pointer on the stack
++ * (such as the pointer to regs, for example).
+
-+Elena, any idea when the fix will make it to a prebuilt gdb from a
-+redhat release?
++ * So here is what we do:
++ * We detect gdb attempting to store into the stack area and instead, store
++ * into the fn_call_lookaside.array at the same relative location as if it
++ * were the area ESP pointed at. We also trap ESP modifications
++ * and uses these to adjust fn_call_lookaside.esp. On entry
++ * fn_call_lookaside.esp will be set to point at the last entry in
++ * fn_call_lookaside.array. This allows us to check if it has changed, and
++ * if so, on exit, we add the registers we will use to do the move and a
++ * trap/ interrupt return exit sequence. We then adjust the eflags in the
++ * regs array (remember we now have a copy in the fn_call_lookaside.array) to
++ * kill the interrupt bit, AND we change EIP to point at our set up stub.
++ * As part of the register set up we preset the registers to point at the
++ * begining and end of the fn_call_lookaside.array, so all the stub needs to
++ * do is move words from the array to the stack until ESP= the desired value
++ * then do the rti. This will then transfer to the desired function with
++ * all the correct registers. Nifty huh?
++ */
++extern asmlinkage void fn_call_stub(void);
++extern asmlinkage void fn_rtn_stub(void);
++/* *INDENT-OFF* */
++__asm__("fn_rtn_stub:\n\t"
++ "movl %eax,%esp\n\t"
++ "fn_call_stub:\n\t"
++ "1:\n\t"
++ "addl $-4,%ebx\n\t"
++ "movl (%ebx), %eax\n\t"
++ "pushl %eax\n\t"
++ "cmpl %esp,%ecx\n\t"
++ "jne 1b\n\t"
++ "popl %eax\n\t"
++ "popl %ebx\n\t"
++ "popl %ecx\n\t"
++ "iret \n\t");
++/* *INDENT-ON* */
++#define gdb_i386vector kgdb_info.vector
++#define gdb_i386errcode kgdb_info.errcode
++#define waiting_cpus kgdb_info.cpus_waiting
++#define remote_debug kgdb_info.print_debug_info
++#define hold_cpu(cpu) kgdb_info.cpus_waiting[cpu].hold
++/* gdb locks */
+
-+For the time being I have built a gdb developement version. It can be
-+used for module debugging with loadmodule.sh script.
++#ifdef CONFIG_SMP
++static int in_kgdb_called;
++static spinlock_t waitlocks[MAX_NO_CPUS] =
++ {[0 ... MAX_NO_CPUS - 1] = SPIN_LOCK_UNLOCKED };
++/*
++ * The following array has the thread pointer of each of the "other"
++ * cpus. We make it global so it can be seen by gdb.
++ */
++volatile int in_kgdb_entry_log[MAX_NO_CPUS];
++volatile struct pt_regs *in_kgdb_here_log[MAX_NO_CPUS];
++/*
++static spinlock_t continuelocks[MAX_NO_CPUS];
++*/
++spinlock_t kgdb_spinlock = SPIN_LOCK_UNLOCKED;
++/* waiters on our spinlock plus us */
++static atomic_t spinlock_waiters = ATOMIC_INIT(1);
++static int spinlock_count = 0;
++static int spinlock_cpu = 0;
++/*
++ * Note we use nested spin locks to account for the case where a break
++ * point is encountered when calling a function by user direction from
++ * kgdb. Also there is the memory exception recursion to account for.
++ * Well, yes, but this lets other cpus thru too. Lets add a
++ * cpu id to the lock.
++ */
++#define KGDB_SPIN_LOCK(x) if( spinlock_count == 0 || \
++ spinlock_cpu != smp_processor_id()){\
++ atomic_inc(&spinlock_waiters); \
++ while (! spin_trylock(x)) {\
++ in_kgdb(®s);\
++ }\
++ atomic_dec(&spinlock_waiters); \
++ spinlock_count = 1; \
++ spinlock_cpu = smp_processor_id(); \
++ }else{ \
++ spinlock_count++; \
++ }
++#define KGDB_SPIN_UNLOCK(x) if( --spinlock_count == 0) spin_unlock(x)
++#else
++unsigned kgdb_spinlock = 0;
++#define KGDB_SPIN_LOCK(x) --*x
++#define KGDB_SPIN_UNLOCK(x) ++*x
++#endif
+
-+The problem with calculating of module addresses with previous versions
-+of gdb was as follows:
-+gdb did not use base address of a section while calculating address of
-+a symbol in the section in an object file loaded via 'add-symbol-file'.
-+It used address of .text segment instead. Due to this addresses of
-+symbols in .data, .bss etc. (e.g. global variables) were calculated incorrectly.
++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);
++}
+
-+Above mentioned fix allow gdb to use base address of a segment while
-+calculating address of a symbol in it. It adds a parameter '-s' to
-+'add-symbol-file' command for specifying base address of a segment.
++/* scan for the sequence $<data>#<checksum> */
++void
++getpacket(char *buffer)
++{
++ unsigned char checksum;
++ unsigned char xmitcsum;
++ int i;
++ int count;
++ char ch;
+
-+loadmodule.sh script works as follows.
++ do {
++ /* wait around for the start character, ignore all other characters */
++ while ((ch = (getDebugChar() & 0x7f)) != '$') ;
++ checksum = 0;
++ xmitcsum = -1;
+
-+1. Copy a module file to target machine.
-+2. Load the module on the target machine using insmod with -m parameter.
-+insmod produces a module load map which contains base addresses of all
-+sections in the module and addresses of symbols in the module file.
-+3. Find all sections and their base addresses in the module from
-+the module map.
-+4. Generate a script that loads the module file. The script uses
-+'add-symbol-file' and specifies address of text segment followed by
-+addresses of all segments in the module.
++ count = 0;
+
-+Here is an example gdb script produced by loadmodule.sh script.
++ /* 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;
+
-+add-symbol-file foo 0xd082c060 -s .text.lock 0xd08cbfb5
-+-s .fixup 0xd08cfbdf -s .rodata 0xd08cfde0 -s __ex_table 0xd08e3b38
-+-s .data 0xd08e3d00 -s .bss 0xd08ec8c0 -s __ksymtab 0xd08ee838
++ if (ch == '#') {
++ xmitcsum = hex(getDebugChar() & 0x7f) << 4;
++ xmitcsum += hex(getDebugChar() & 0x7f);
++ if ((remote_debug) && (checksum != xmitcsum)) {
++ printk
++ ("bad checksum. My count = 0x%x, sent=0x%x. buf=%s\n",
++ checksum, xmitcsum, buffer);
++ }
+
-+With this command gdb can calculate addresses of symbols in ANY segment
-+in a module file.
++ 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);
+
-+Regards.
-+--
-+Amit Kale
-+Veritas Software ( http://www.veritas.com )
-diff -puN /dev/null Documentation/i386/kgdb/gdbinit
---- /dev/null 2003-09-15 06:40:47.000000000 -0700
-+++ 25-akpm/Documentation/i386/kgdb/gdbinit 2004-10-21 14:54:15.317594864 -0700
-@@ -0,0 +1,14 @@
-+shell echo -e "\003" >/dev/ttyS0
-+set remotebaud 38400
-+target remote /dev/ttyS0
-+define si
-+stepi
-+printf "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n", $eax, $ebx, $ecx, $edx
-+printf "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n", $esi, $edi, $ebp, $esp
-+x/i $eip
-+end
-+define ni
-+nexti
-+printf "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n", $eax, $ebx, $ecx, $edx
-+printf "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n", $esi, $edi, $ebp, $esp
-+x/i $eip
-diff -puN /dev/null Documentation/i386/kgdb/gdbinit.hw
---- /dev/null 2003-09-15 06:40:47.000000000 -0700
-+++ 25-akpm/Documentation/i386/kgdb/gdbinit.hw 2004-10-21 14:54:15.318594712 -0700
-@@ -0,0 +1,117 @@
++ if (remote_debug)
++ printk("R:%s\n", buffer);
++}
+
-+#Using ia-32 hardware breakpoints.
-+#
-+#4 hardware breakpoints are available in ia-32 processors. These breakpoints
-+#do not need code modification. They are set using debug registers.
-+#
-+#Each hardware breakpoint can be of one of the
-+#three types: execution, write, access.
-+#1. An Execution breakpoint is triggered when code at the breakpoint address is
-+#executed.
-+#2. A write breakpoint ( aka watchpoints ) is triggered when memory location
-+#at the breakpoint address is written.
-+#3. An access breakpoint is triggered when memory location at the breakpoint
-+#address is either read or written.
-+#
-+#As hardware breakpoints are available in limited number, use software
-+#breakpoints ( br command in gdb ) instead of execution hardware breakpoints.
-+#
-+#Length of an access or a write breakpoint defines length of the datatype to
-+#be watched. Length is 1 for char, 2 short , 3 int.
-+#
-+#For placing execution, write and access breakpoints, use commands
-+#hwebrk, hwwbrk, hwabrk
-+#To remove a breakpoint use hwrmbrk command.
-+#
-+#These commands take following types of arguments. For arguments associated
-+#with each command, use help command.
-+#1. breakpointno: 0 to 3
-+#2. length: 1 to 3
-+#3. address: Memory location in hex ( without 0x ) e.g c015e9bc
-+#
-+#Use the command exinfo to find which hardware breakpoint occured.
++/* send the packet in buffer. */
+
-+#hwebrk breakpointno address
-+define hwebrk
-+ maintenance packet Y$arg0,0,0,$arg1
-+end
-+document hwebrk
-+ hwebrk <breakpointno> <address>
-+ Places a hardware execution breakpoint
-+ <breakpointno> = 0 - 3
-+ <address> = Hex digits without leading "0x".
-+end
++void
++putpacket(char *buffer)
++{
++ unsigned char checksum;
++ int count;
++ char ch;
+
-+#hwwbrk breakpointno length address
-+define hwwbrk
-+ maintenance packet Y$arg0,1,$arg1,$arg2
-+end
-+document hwwbrk
-+ hwwbrk <breakpointno> <length> <address>
-+ Places a hardware write breakpoint
-+ <breakpointno> = 0 - 3
-+ <length> = 1 (1 byte), 2 (2 byte), 3 (4 byte)
-+ <address> = Hex digits without leading "0x".
-+end
++ /* $<packet info>#<checksum>. */
++ do {
++ if (remote_debug)
++ printk("T:%s\n", buffer);
++ putDebugChar('$');
++ checksum = 0;
++ count = 0;
+
-+#hwabrk breakpointno length address
-+define hwabrk
-+ maintenance packet Y$arg0,1,$arg1,$arg2
-+end
-+document hwabrk
-+ hwabrk <breakpointno> <length> <address>
-+ Places a hardware access breakpoint
-+ <breakpointno> = 0 - 3
-+ <length> = 1 (1 byte), 2 (2 byte), 3 (4 byte)
-+ <address> = Hex digits without leading "0x".
-+end
++ while ((ch = buffer[count])) {
++ putDebugChar(ch);
++ checksum += ch;
++ count += 1;
++ }
+
-+#hwrmbrk breakpointno
-+define hwrmbrk
-+ maintenance packet y$arg0
-+end
-+document hwrmbrk
-+ hwrmbrk <breakpointno>
-+ <breakpointno> = 0 - 3
-+ Removes a hardware breakpoint
-+end
++ putDebugChar('#');
++ putDebugChar(hexchars[checksum >> 4]);
++ putDebugChar(hexchars[checksum % 16]);
+
-+define reboot
-+ maintenance packet r
-+end
-+#exinfo
-+define exinfo
-+ maintenance packet qE
-+end
-+document exinfo
-+ exinfo
-+ Gives information about a breakpoint.
-+end
-+define get_th
-+ p $th=(struct thread_info *)((int)$esp & ~8191)
-+end
-+document get_th
-+ get_tu
-+ Gets and prints the current thread_info pointer, Defines th to be it.
-+end
-+define get_cu
-+ p $cu=((struct thread_info *)((int)$esp & ~8191))->task
-+end
-+document get_cu
-+ get_cu
-+ Gets and print the "current" value. Defines $cu to be it.
-+end
-+define int_off
-+ set var $flags=$eflags
-+ set $eflags=$eflags&~0x200
-+ end
-+define int_on
-+ set var $eflags|=$flags&0x200
-+ end
-+document int_off
-+ saves the current interrupt state and clears the processor interrupt
-+ flag. Use int_on to restore the saved flag.
-+end
-+document int_on
-+ Restores the interrupt flag saved by int_off.
-+end
-diff -puN /dev/null Documentation/i386/kgdb/gdbinit-modules
---- /dev/null Thu Apr 11 07:25:15 2002
-+++ 25-akpm/Documentation/i386/kgdb/gdbinit-modules Fri Jan 13 17:54:25 2006
-@@ -0,0 +1,149 @@
-+#
-+# Usefull GDB user-command to debug Linux Kernel Modules with gdbstub.
-+#
-+# This don't work for Linux-2.0 or older.
-+#
-+# Author Edouard G. Parmelan <Edouard.Parmelan@quadratec.fr>
-+#
-+#
-+# Fri Apr 30 20:33:29 CEST 1999
-+# First public release.
-+#
-+# Major cleanup after experiment Linux-2.0 kernel without success.
-+# Symbols of a module are not in the correct order, I can't explain
-+# why :(
-+#
-+# Fri Mar 19 15:41:40 CET 1999
-+# Initial version.
-+#
-+# Thu Jan 6 16:29:03 CST 2000
-+# A little fixing by Dave Grothe <dave@gcom.com>
-+#
-+# Mon Jun 19 09:33:13 CDT 2000
-+# Alignment changes from Edouard Parmelan
-+#
-+# The basic idea is to find where insmod load the module and inform
-+# GDB to load the symbol table of the module with the GDB command
-+# ``add-symbol-file <object> <address>''.
-+#
-+# The Linux kernel holds the list of all loaded modules in module_list,
-+# this list end with &kernel_module (exactly with module->next == NULL,
-+# but the last module is not a real module).
-+#
-+# Insmod allocates the struct module before the object file. Since
-+# Linux-2.1, this structure contain his size. The real address of
-+# the object file is then (char*)module + module->size_of_struct.
-+#
-+# You can use three user functions ``mod-list'', ``mod-print-symbols''
-+# and ``add-module-symbols''.
-+#
-+# mod-list list all loaded modules with the format:
-+# <module-address> <module-name>
-+#
-+# As soon as you have found the address of your module, you can
-+# print its exported symbols (mod-print-symbols) or inform GDB to add
-+# symbols from your module file (mod-add-symbols).
-+#
-+# The argument that you give to mod-print-symbols or mod-add-symbols
-+# is the <module-address> from the mod-list command.
-+#
-+# When using the mod-add-symbols command you must also give the full
-+# pathname of the modules object code file.
-+#
-+# The command mod-add-lis is an example of how to make this easier.
-+# You can edit this macro to contain the path name of your own
-+# favorite module and then use it as a shorthand to load it. You
-+# still need the module-address, however.
-+#
-+# The internal function ``mod-validate'' set the GDB variable $mod
-+# as a ``struct module*'' if the kernel known the module otherwise
-+# $mod is set to NULL. This ensure to not add symbols for a wrong
-+# address.
-+#
-+#
-+# Sat Feb 12 20:05:47 CET 2005
-+#
-+# Adapted to the 2.6.* module data structure.
-+# (Getting miffed at gdb for not having "offsetof" in the process :-/ )
-+#
-+# Autogenerate add-symbol-file statements from the module list instead
-+# of relying on a no-longer-working loadmodule.sh program.
-+#
-+# Matthias Urlichs <smurf@debian.org>
-+#
-+#
-+# Have a nice hacking day !
-+#
-+#
-+define mod-list
-+ set $lmod = modules->next
-+ # This is a circular data structure
-+ while $lmod != &modules
-+ set $mod = (struct module *)(((char *)$lmod) - ((int)&(((struct module *)0) -> list)))
-+ printf "%p\t%s\n", $mod, $mod->name
-+ set $lmod = $lmod->next
-+ end
-+end
-+document mod-list
-+mod-list
-+List all modules in the form: <module-address> <module-name>
-+Use the <module-address> as the argument for the other
-+mod-commands: mod-print-symbols, mod-add-symbols.
-+end
++ } while ((getDebugChar() & 0x7f) != '+');
++
++}
++
++static char remcomInBuffer[BUFMAX];
++static char remcomOutBuffer[BUFMAX];
++static short error;
++
++void
++debug_error(char *format, char *parm)
++{
++ if (remote_debug)
++ printk(format, parm);
++}
++
++static void
++print_regs(struct pt_regs *regs)
++{
++ printk("EAX=%08lx ", regs->eax);
++ printk("EBX=%08lx ", regs->ebx);
++ printk("ECX=%08lx ", regs->ecx);
++ printk("EDX=%08lx ", regs->edx);
++ printk("\n");
++ printk("ESI=%08lx ", regs->esi);
++ printk("EDI=%08lx ", regs->edi);
++ printk("EBP=%08lx ", regs->ebp);
++ printk("ESP=%08lx ", (long) ®s->esp);
++ printk("\n");
++ printk(" DS=%08x ", regs->xds);
++ printk(" ES=%08x ", regs->xes);
++ printk(" SS=%08x ", __KERNEL_DS);
++ printk(" FL=%08lx ", regs->eflags);
++ printk("\n");
++ printk(" CS=%08x ", regs->xcs);
++ printk(" IP=%08lx ", regs->eip);
++#if 0
++ printk(" FS=%08x ", regs->fs);
++ printk(" GS=%08x ", regs->gs);
++#endif
++ printk("\n");
+
-+define mod-list-syms
-+ set $lmod = modules->next
-+ # This is a circular data structure
-+ while $lmod != &modules
-+ set $mod = (struct module *)(((char *)$lmod) - ((int)&(((struct module *)0) -> list)))
-+ printf "add-symbol-file %s.ko %p\n", $mod->name, $mod->module_core
-+ set $lmod = $lmod->next
-+ end
-+end
-+document mod-list-syms
-+mod-list-syms
-+List all modules in the form: add-symbol-file <module-path> <module-core>
-+for adding modules' symbol tables without loadmodule.sh.
-+end
++} /* print_regs */
+
-+define mod-validate
-+ set $lmod = modules->next
-+ set $mod = (struct module *)(((char *)$lmod) - ((int)&(((struct module *)0) -> list)))
-+ while ($lmod != &modules) && ($mod != $arg0)
-+ set $lmod = $lmod->next
-+ set $mod = (struct module *)(((char *)$lmod) - ((int)&(((struct module *)0) -> list)))
-+ end
-+ if $lmod == &modules
-+ set $mod = 0
-+ printf "%p is not a module\n", $arg0
-+ end
-+end
-+document mod-validate
-+mod-validate <module-address>
-+Internal user-command used to validate the module parameter.
-+If <module> is a real loaded module, set $mod to it, otherwise set $mod
-+to 0.
-+end
++#define NEW_esp fn_call_lookaside[trap_cpu].esp
+
-+define mod-print-symbols
-+ mod-validate $arg0
-+ if $mod != 0
-+ set $i = 0
-+ while $i < $mod->num_syms
-+ set $sym = $mod->syms[$i]
-+ printf "%p\t%s\n", $sym->value, $sym->name
-+ set $i = $i + 1
-+ end
-+ set $i = 0
-+ while $i < $mod->num_gpl_syms
-+ set $sym = $mod->gpl_syms[$i]
-+ printf "%p\t%s\n", $sym->value, $sym->name
-+ set $i = $i + 1
-+ end
-+ end
-+end
-+document mod-print-symbols
-+mod-print-symbols <module-address>
-+Print all exported symbols of the module. See mod-list
-+end
++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;
++ /* Note, as we are a debugging the kernel, we will always
++ * trap in kernel code, this means no priviledge change,
++ * and so the pt_regs structure is not completely valid. In a non
++ * privilege change trap, only EFLAGS, CS and EIP are put on the stack,
++ * SS and ESP are not stacked, this means that the last 2 elements of
++ * pt_regs is not valid (they would normally refer to the user stack)
++ * also, using regs+1 is no good because you end up will a value that is
++ * 2 longs (8) too high. This used to cause stepping over functions
++ * to fail, so my fix is to use the address of regs->esp, which
++ * should point at the end of the stack frame. Note I have ignored
++ * completely exceptions that cause an error code to be stacked, such
++ * as double fault. Stuart Hughes, Zentropix.
++ * original code: gdb_regs[_ESP] = (int) (regs + 1) ;
+
-diff -puN /dev/null Documentation/i386/kgdb/kgdb.txt
---- /dev/null 2003-09-15 06:40:47.000000000 -0700
-+++ 25-akpm/Documentation/i386/kgdb/kgdb.txt 2004-10-21 14:54:15.324593800 -0700
-@@ -0,0 +1,775 @@
-+Last edit: <20030806.1637.12>
-+This file has information specific to the i386 kgdb option. Other
-+platforms with the kgdb option may behave in a similar fashion.
++ * this is now done on entry and moved to OLD_esp (as well as NEW_esp).
++ */
++ gdb_regs[_ESP] = NEW_esp;
++ gdb_regs[_SS] = __KERNEL_DS;
++ gdb_regs[_FS] = 0xFFFF;
++ gdb_regs[_GS] = 0xFFFF;
++} /* regs_to_gdb_regs */
+
-+New features:
-+============
-+20030806.1557.37
-+This version was made against the 2.6.0-test2 kernel. We have made the
-+following changes:
++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];
++ NEW_esp = gdb_regs[_ESP]; /* keep the value */
++#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
+
-+- The getthread() code in the stub calls find_task_by_pid(). It fails
-+ if we are early in the bring up such that the pid arrays have yet to
-+ be allocated. We have added a line to kernel/pid.c to make
-+ "kgdb_pid_init_done" true once the arrays are allocated. This way the
-+ getthread() code knows not to call. This is only used by the thread
-+ debugging stuff and threads will not yet exist at this point in the
-+ boot.
++} /* gdb_regs_to_regs */
+
-+- For some reason, gdb was not asking for a new thread list when the
-+ "info thread" command was given. We changed to the newer version of
-+ the thread info command and gdb now seems to ask when needed. Result,
-+ we now get all threads in the thread list.
++int thread_list = 0;
+
-+- We now respond to the ThreadExtraInfo request from gdb with the thread
-+ name from task_struct .comm. This then appears in the thread list.
-+ Thoughts on additional options for this are welcome. Things such as
-+ "has BKL" and "Preempted" come to mind. I think we could have a flag
-+ word that could enable different bits of info here.
++void
++get_gdb_regs(struct task_struct *p, struct pt_regs *regs, int *gdb_regs)
++{
++ unsigned long stack_page;
++ int count = 0;
++ IF_SMP(int i);
++ if (!p || p == current) {
++ regs_to_gdb_regs(gdb_regs, regs);
++ return;
++ }
++#ifdef CONFIG_SMP
++ for (i = 0; i < MAX_NO_CPUS; i++) {
++ if (p == kgdb_info.cpus_waiting[i].task) {
++ regs_to_gdb_regs(gdb_regs,
++ kgdb_info.cpus_waiting[i].regs);
++ gdb_regs[_ESP] =
++ (int) &kgdb_info.cpus_waiting[i].regs->esp;
+
-+- We now honor, sort of, the C and S commands. These are continue and
-+ single set after delivering a signal. We ignore the signal and do the
-+ requested action. This only happens when we told gdb that a signal
-+ was the reason for entry, which is only done on memory faults. The
-+ result is that you can now continue into the Oops.
++ return;
++ }
++ }
++#endif
++ memset(gdb_regs, 0, NUMREGBYTES);
++ gdb_regs[_ESP] = p->thread.esp;
++ gdb_regs[_PC] = p->thread.eip;
++ gdb_regs[_EBP] = *(int *) gdb_regs[_ESP];
++ gdb_regs[_EDI] = *(int *) (gdb_regs[_ESP] + 4);
++ gdb_regs[_ESI] = *(int *) (gdb_regs[_ESP] + 8);
+
-+- We changed the -g to -gdwarf-2. This seems to be the same as -ggdb,
-+ but it is more exact on what language to use.
++/*
++ * This code is to give a more informative notion of where a process
++ * is waiting. It is used only when the user asks for a thread info
++ * list. If he then switches to the thread, s/he will find the task
++ * is in schedule, but a back trace should show the same info we come
++ * up with. This code was shamelessly purloined from process.c. It was
++ * then enhanced to provide more registers than simply the program
++ * counter.
++ */
+
-+- We added two dwarf2 include files and a bit of code at the end of
-+ entry.S. This does not yet work, so it is disabled. Still we want to
-+ keep track of the code and "maybe" someone out there can fix it.
++ if (!thread_list) {
++ return;
++ }
++
++ if (p->state == TASK_RUNNING)
++ return;
++ stack_page = (unsigned long) p->thread_info;
++ if (gdb_regs[_ESP] < stack_page || gdb_regs[_ESP] >
++ THREAD_SIZE - sizeof(long) + stack_page)
++ return;
++ /* include/asm-i386/system.h:switch_to() pushes ebp last. */
++ do {
++ if (gdb_regs[_EBP] < stack_page ||
++ gdb_regs[_EBP] > THREAD_SIZE - 2*sizeof(long) + stack_page)
++ return;
++ gdb_regs[_PC] = *(unsigned long *) (gdb_regs[_EBP] + 4);
++ gdb_regs[_ESP] = gdb_regs[_EBP] + 8;
++ gdb_regs[_EBP] = *(unsigned long *) gdb_regs[_EBP];
++ if (!in_sched_functions(gdb_regs[_PC]))
++ return;
++ } while (count++ < 16);
++ return;
++}
++
++/* Indicate to caller of mem2hex or hex2mem that there has been an
++ error. */
++static volatile int mem_err = 0;
++static volatile int mem_err_expected = 0;
++static volatile int mem_err_cnt = 0;
++static int garbage_loc = -1;
++
++int
++get_char(char *addr)
++{
++ return *addr;
++}
++
++void
++set_char(char *addr, int val, int may_fault)
++{
++ /*
++ * This code traps references to the area mapped to the kernel
++ * stack as given by the regs and, instead, stores to the
++ * fn_call_lookaside[cpu].array
++ */
++ if (may_fault &&
++ (unsigned int) addr < OLD_esp &&
++ ((unsigned int) addr > (OLD_esp - (unsigned int) LOOKASIDE_SIZE))) {
++ addr = (char *) END_OF_LOOKASIDE - ((char *) OLD_esp - addr);
++ }
++ *addr = val;
++}
++
++/* convert the memory pointed to by mem into hex, placing result in buf */
++/* return a pointer to the last char put in buf (null) */
++/* If MAY_FAULT is non-zero, then we should set mem_err 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;
+
-+- Randy Dunlap sent some fix ups for this file which are now merged.
++ if (may_fault) {
++ mem_err_expected = 1;
++ mem_err = 0;
++ }
++ for (i = 0; i < count; i++) {
++ /* printk("%lx = ", mem) ; */
+
-+- Hugh Dickins sent a fix to a bit of code in traps.c that prevents a
-+ compiler warning if CONFIG_KGDB is off (now who would do that :).
++ ch = get_char(mem++);
+
-+- Andrew Morton sent a fix for the serial driver which is now merged.
++ /* printk("%02x\n", ch & 0xFF) ; */
++ if (may_fault && mem_err) {
++ if (remote_debug)
++ printk("Mem fault fetching from addr %lx\n",
++ (long) (mem - 1));
++ *buf = 0; /* truncate buffer */
++ return (buf);
++ }
++ *buf++ = hexchars[ch >> 4];
++ *buf++ = hexchars[ch % 16];
++ }
++ *buf = 0;
++ if (may_fault)
++ mem_err_expected = 0;
++ return (buf);
++}
+
-+- Andrew also sent a change to the stub around the cpu managment code
-+ which is also merged.
++/* 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 */
++/* NOTE: We use the may fault flag to also indicate if the write is to
++ * the registers (0) or "other" memory (!=0)
++ */
++char *
++hex2mem(char *buf, char *mem, int count, int may_fault)
++{
++ int i;
++ unsigned char ch;
+
-+- Andrew also sent a patch to make "f" as well as "g" work as SysRq
-+ commands to enter kgdb, merged.
++ if (may_fault) {
++ mem_err_expected = 1;
++ mem_err = 0;
++ }
++ for (i = 0; i < count; i++) {
++ ch = hex(*buf++) << 4;
++ ch = ch + hex(*buf++);
++ set_char(mem++, ch, may_fault);
+
-+- If CONFIG_KGDB and CONFIG_DEBUG_SPINLOCKS are both set we added a
-+ "who" field to the spinlock data struct. This is filled with
-+ "current" when ever the spinlock suceeds. Useful if you want to know
-+ who has the lock.
++ if (may_fault && mem_err) {
++ if (remote_debug)
++ printk("Mem fault storing to addr %lx\n",
++ (long) (mem - 1));
++ return (mem);
++ }
++ }
++ if (may_fault)
++ mem_err_expected = 0;
++ return (mem);
++}
+
-+_ And last, but not least, we fixed the "get_cu" macro to properly get
-+ the current value of "current".
++/**********************************************/
++/* 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;
+
-+New features:
-+============
-+20030505.1827.27
-+We are starting to align with the sourceforge version, at least in
-+commands. To this end, the boot command string to start kgdb at
-+boot time has been changed from "kgdb" to "gdb".
++ *intValue = 0;
+
-+Andrew Morton sent a couple of patches which are now included as follows:
-+1.) We now return a flag to the interrupt handler.
-+2.) We no longer use smp_num_cpus (a conflict with the lock meter).
-+3.) And from William Lee Irwin III <wli@holomorphy.com> code to make
-+ sure high-mem is set up before we attempt to register our interrupt
-+ handler.
-+We now include asm/kgdb.h from config.h so you will most likely never
-+have to include it. It also 'NULLS' the kgdb macros you might have in
-+your code when CONFIG_KGDB is not defined. This allows you to just
-+turn off CONFIG_KGDB to turn off all the kgdb_ts() calls and such.
-+This include is conditioned on the machine being an x86 so as to not
-+mess with other archs.
++ while (**ptr) {
++ hexValue = hex(**ptr);
++ if (hexValue >= 0) {
++ *intValue = (*intValue << 4) | hexValue;
++ numChars++;
++ } else
++ break;
+
-+20020801.1129.03
-+This is currently the version for the 2.4.18 (and beyond?) kernel.
++ (*ptr)++;
++ }
+
-+We have several new "features" beginning with this version:
++ return (numChars);
++}
+
-+1.) Kgdb now syncs the "other" CPUs with a cross-CPU NMI. No more
-+ waiting and it will pull that guy out of an IRQ off spin lock :)
++#define stubhex(h) hex(h)
++#ifdef old_thread_list
+
-+2.) We doctored up the code that tells where a task is waiting and
-+ included it so that the "info thread" command will show a bit more
-+ than "schedule()". Try it...
++static int
++stub_unpack_int(char *buff, int fieldlength)
++{
++ int nibble;
++ int retval = 0;
+
-+3.) Added the ability to call a function from gdb. All the standard gdb
-+ issues apply, i.e. if you hit a breakpoint in the function, you are
-+ not allowed to call another (gdb limitation, not kgdb). To help
-+ this capability we added a memory allocation function. Gdb does not
-+ return this memory (it is used for strings that you pass to that function
-+ you are calling from gdb) so we fixed up a way to allow you to
-+ manually return the memory (see below).
++ 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;
++}
+
-+4.) Kgdb time stamps (kgdb_ts()) are enhanced to expand what was the
-+ interrupt flag to now also include the preemption count and the
-+ "in_interrupt" info. The flag is now called "with_pif" to indicate
-+ the order, preempt_count, in_interrupt, flag. The preempt_count is
-+ shifted left by 4 bits so you can read the count in hex by dropping
-+ the low order digit. In_interrupt is in bit 1, and the flag is in
-+ bit 0.
++#define BUF_THREAD_ID_SIZE 16
+
-+5.) The command: "p kgdb_info" is now expanded and prints something
-+ like:
-+(gdb) p kgdb_info
-+$2 = {used_malloc = 0, called_from = 0xc0107506, entry_tsc = 67468627259,
-+ errcode = 0, vector = 3, print_debug_info = 0, hold_on_sstep = 1,
-+ cpus_waiting = {{task = 0xc027a000, pid = 32768, hold = 0,
-+ regs = 0xc027bf84}, {task = 0x0, pid = 0, hold = 0, regs = 0x0}}}
++static char *
++pack_threadid(char *pkt, threadref * id)
++{
++ char *limit;
++ unsigned char *altid;
+
-+ Things to note here: a.) used_malloc is the amount of memory that
-+ has been malloc'ed to do calls from gdb. You can reclaim this
-+ memory like this: "p kgdb_info.used_malloc=0" Cool, huh? b.)
-+ cpus_waiting is now "sized" by the number of CPUs you enter at
-+ configure time in the kgdb configure section. This is NOT used
-+ anywhere else in the system, but it is "nice" here. c.) The task's
-+ "pid" is now in the structure. This is the pid you will need to use
-+ to decode to the thread id to get gdb to look at that thread.
-+ Remember that the "info thread" command prints a list of threads
-+ wherein it numbers each thread with its reference number followed
-+ by the thread's pid. Note that the per-CPU idle threads actually
-+ have pids of 0 (yes, there is more than one pid 0 in an SMP system).
-+ To avoid confusion, kgdb numbers these threads with numbers beyond
-+ the MAX_PID. That is why you see 32768 and above.
++ altid = (unsigned char *) id;
++ limit = pkt + BUF_THREAD_ID_SIZE;
++ while (pkt < limit)
++ pkt = pack_hex_byte(pkt, *altid++);
++ return pkt;
++}
+
-+6.) A subtle change, we now provide the complete register set for tasks
-+ that are active on the other CPUs. This allows better trace back on
-+ those tasks.
++#ifdef old_thread_list
++static char *
++unpack_byte(char *buf, int *value)
++{
++ *value = stub_unpack_int(buf, 2);
++ return buf + 2;
++}
+
-+ And, let's mention what we could not fix. Back-trace from all but the
-+ thread that we trapped will, most likely, have a bogus entry in it.
-+ The problem is that gdb does not recognize the entry code for
-+ functions that use "current" near (at all?) the entry. The compiler
-+ is putting the "current" decode as the first two instructions of the
-+ function where gdb expects to find %ebp changing code. Back trace
-+ also has trouble with interrupt frames. I am talking with Daniel
-+ Jacobowitz about some way to fix this, but don't hold your breath.
++static char *
++unpack_threadid(char *inbuf, threadref * id)
++{
++ char *altref;
++ char *limit = inbuf + BUF_THREAD_ID_SIZE;
++ int x, y;
+
-+20011220.0050.35
-+Major enhancement with this version is the ability to hold one or more
-+CPUs in an SMP system while allowing the others to continue. Also, by
-+default only the current CPU is enabled on single-step commands (please
-+note that gdb issues single-step commands at times other than when you
-+use the si command).
++ altref = (char *) id;
+
-+Another change is to collect some useful information in
-+a global structure called "kgdb_info". You should be able to just:
++ 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;
+
-+p kgdb_info
++ 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);
++}
++int
++int_to_hex_v(unsigned char * id, int value)
++{
++ unsigned char *start = id;
++ int shift;
++ int ch;
+
-+although I have seen cases where the first time this is done gdb just
-+prints the first member but prints the whole structure if you then enter
-+CR (carriage return or enter). This also works:
++ for (shift = 28; shift >= 0; shift -= 4) {
++ if ((ch = (value >> shift) & 0xf) || (id != start)) {
++ *id = hexchars[ch];
++ id++;
++ }
++ }
++ if (id == start)
++ *id++ = '0';
++ return id - start;
++}
++#ifdef old_thread_list
+
-+p *&kgdb_info
++static int
++threadref_to_int(threadref * ref)
++{
++ int i, value = 0;
++ unsigned char *scan;
+
-+Here is a sample:
-+(gdb) p kgdb_info
-+$4 = {called_from = 0xc010732c, entry_tsc = 32804123790856, errcode = 0,
-+ vector = 3, print_debug_info = 0}
++ scan = (char *) ref;
++ scan += 4;
++ i = 4;
++ while (i-- > 0)
++ value = (value << 8) | ((*scan++) & 0xff);
++ return value;
++}
++#endif
++static int
++cmp_str(char *s1, char *s2, int count)
++{
++ while (count--) {
++ if (*s1++ != *s2++)
++ return 0;
++ }
++ return 1;
++}
+
-+"Called_from" is the return address from the current entry into kgdb.
-+Sometimes it is useful to know why you are in kgdb, for example, was
-+it an NMI or a real breakpoint? The simple way to interrogate this
-+return address is:
++#if 1 /* this is a hold over from 2.4 where O(1) was "sometimes" */
++extern struct task_struct *kgdb_get_idle(int cpu);
++#define idle_task(cpu) kgdb_get_idle(cpu)
++#else
++#define idle_task(cpu) init_tasks[cpu]
++#endif
+
-+l *0xc010732c
++extern int kgdb_pid_init_done;
+
-+which will print the surrounding few lines of source code.
++struct task_struct *
++getthread(int pid)
++{
++ struct task_struct *thread;
++ if (pid >= PID_MAX && pid <= (PID_MAX + MAX_NO_CPUS)) {
+
-+"Entry_tsc" is the CPU TSC on entry to kgdb (useful to compare to the
-+kgdb_ts entries).
++ return idle_task(pid - PID_MAX);
++ } else {
++ /*
++ * find_task_by_pid is relatively safe all the time
++ * Other pid functions require lock downs which imply
++ * that we may be interrupting them (as we get here
++ * in the middle of most any lock down).
++ * Still we don't want to call until the table exists!
++ */
++ if (kgdb_pid_init_done){
++ thread = find_task_by_pid(pid);
++ if (thread) {
++ return thread;
++ }
++ }
++ }
++ return NULL;
++}
++/* *INDENT-OFF* */
++struct hw_breakpoint {
++ unsigned enabled;
++ unsigned type;
++ unsigned len;
++ unsigned addr;
++} breakinfo[4] = { {enabled:0},
++ {enabled:0},
++ {enabled:0},
++ {enabled:0}};
++/* *INDENT-ON* */
++unsigned hw_breakpoint_status;
++void
++correct_hw_break(void)
++{
++ int breakno;
++ int correctit;
++ int breakbit;
++ unsigned dr7;
+
-+"errcode" and "vector" are other entry parameters which may be helpful on
-+some traps.
++ asm volatile ("movl %%db7, %0\n":"=r" (dr7)
++ :);
++ /* *INDENT-OFF* */
++ 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);
++ /* *INDENT-ON* */
++ 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;
+
-+"print_debug_info" is the internal debugging kgdb print enable flag. Yes,
-+you can modify it.
++ case 1:
++ asm volatile ("movl %0, %%dr1\n"::"r"
++ (breakinfo[breakno].addr));
++ break;
+
-+In SMP systems kgdb_info also includes the "cpus_waiting" structure and
-+"hold_on_step":
++ case 2:
++ asm volatile ("movl %0, %%dr2\n"::"r"
++ (breakinfo[breakno].addr));
++ break;
+
-+(gdb) p kgdb_info
-+$7 = {called_from = 0xc0112739, entry_tsc = 1034936624074, errcode = 0,
-+ vector = 2, print_debug_info = 0, hold_on_sstep = 1, cpus_waiting = {{
-+ task = 0x0, hold = 0, regs = 0x0}, {task = 0xc71b8000, hold = 0,
-+ regs = 0xc71b9f70}, {task = 0x0, hold = 0, regs = 0x0}, {task = 0x0,
-+ hold = 0, regs = 0x0}, {task = 0x0, hold = 0, regs = 0x0}, {task = 0x0,
-+ hold = 0, regs = 0x0}, {task = 0x0, hold = 0, regs = 0x0}, {task = 0x0,
-+ hold = 0, regs = 0x0}}}
++ 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));
++ }
++}
+
-+"Cpus_waiting" has an entry for each CPU other than the current one that
-+has been stopped. Each entry contains the task_struct address for that
-+CPU, the address of the regs for that task and a hold flag. All these
-+have the proper typing so that, for example:
++int
++remove_hw_break(unsigned breakno)
++{
++ if (!breakinfo[breakno].enabled) {
++ return -1;
++ }
++ breakinfo[breakno].enabled = 0;
++ return 0;
++}
+
-+p *kgdb_info.cpus_waiting[1].regs
++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;
++}
+
-+will print the registers for CPU 1.
++#ifdef CONFIG_SMP
++static int in_kgdb_console = 0;
+
-+"Hold_on_sstep" is a new feature with this version and comes up set or
-+true. What this means is that whenever kgdb is asked to single-step all
-+other CPUs are held (i.e. not allowed to execute). The flag applies to
-+all but the current CPU and, again, can be changed:
++int
++in_kgdb(struct pt_regs *regs)
++{
++ unsigned flags;
++ int cpu = smp_processor_id();
++ in_kgdb_called = 1;
++ if (!spin_is_locked(&kgdb_spinlock)) {
++ if (in_kgdb_here_log[cpu] || /* we are holding this cpu */
++ in_kgdb_console) { /* or we are doing slow i/o */
++ return 1;
++ }
++ return 0;
++ }
+
-+p kgdb_info.hold_on_sstep=0
++ /* As I see it the only reason not to let all cpus spin on
++ * the same spin_lock is to allow selected ones to proceed.
++ * This would be a good thing, so we leave it this way.
++ * Maybe someday.... Done !
+
-+restores the old behavior of letting all CPUs run during single-stepping.
++ * in_kgdb() is called from an NMI so we don't pretend
++ * to have any resources, like printk() for example.
++ */
+
-+Likewise, each CPU has a "hold" flag, which if set, locks that CPU out
-+of execution. Note that this has some risk in cases where the CPUs need
-+to communicate with each other. If kgdb finds no CPU available on exit,
-+it will push a message thru gdb and stay in kgdb. Note that it is legal
-+to hold the current CPU as long as at least one CPU can execute.
++ kgdb_local_irq_save(flags); /* only local here, to avoid hanging */
++ /*
++ * log arival of this cpu
++ * The NMI keeps on ticking. Protect against recurring more
++ * than once, and ignor the cpu that has the kgdb lock
++ */
++ in_kgdb_entry_log[cpu]++;
++ in_kgdb_here_log[cpu] = regs;
++ if (cpu == spinlock_cpu || waiting_cpus[cpu].task) {
++ goto exit_in_kgdb;
++ }
++ /*
++ * For protection of the initilization of the spin locks by kgdb
++ * it locks the kgdb spinlock before it gets the wait locks set
++ * up. We wait here for the wait lock to be taken. If the
++ * kgdb lock goes away first?? Well, it could be a slow exit
++ * sequence where the wait lock is removed prior to the kgdb lock
++ * so if kgdb gets unlocked, we just exit.
++ */
++ while (spin_is_locked(&kgdb_spinlock) &&
++ !spin_is_locked(waitlocks + cpu)) ;
++ if (!spin_is_locked(&kgdb_spinlock)) {
++ goto exit_in_kgdb;
++ }
++ waiting_cpus[cpu].task = current;
++ waiting_cpus[cpu].pid = (current->pid) ? : (PID_MAX + cpu);
++ waiting_cpus[cpu].regs = regs;
+
-+20010621.1117.09
-+This version implements an event queue. Events are signaled by calling
-+a function in the kgdb stub and may be examined from gdb. See EVENTS
-+below for details. This version also tightens up the interrupt and SMP
-+handling to not allow interrupts on the way to kgdb from a breakpoint
-+trap. It is fine to allow these interrupts for user code, but not
-+system debugging.
++ spin_unlock_wait(waitlocks + cpu);
++ /*
++ * log departure of this cpu
++ */
++ waiting_cpus[cpu].task = 0;
++ waiting_cpus[cpu].pid = 0;
++ waiting_cpus[cpu].regs = 0;
++ correct_hw_break();
++ exit_in_kgdb:
++ in_kgdb_here_log[cpu] = 0;
++ kgdb_local_irq_restore(flags);
++ return 1;
++ /*
++ spin_unlock(continuelocks + smp_processor_id());
++ */
++}
+
-+Version
-+=======
++void
++smp__in_kgdb(struct pt_regs regs)
++{
++ ack_APIC_irq();
++ in_kgdb(®s);
++}
++#else
++int
++in_kgdb(struct pt_regs *regs)
++{
++ return (kgdb_spinlock);
++}
++#endif
+
-+This version of the kgdb package was developed and tested on
-+kernel version 2.4.16. It will not install on any earlier kernels.
-+It is possible that it will continue to work on later versions
-+of 2.4 and then versions of 2.5 (I hope).
++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 kgdb_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
++kgdb_handle_exception(int exceptionVector,
++ int signo, int err_code, struct pt_regs *linux_regs)
++{
++ struct task_struct *usethread = NULL;
++ struct task_struct *thread_list_start = 0, *thread = NULL;
++ int addr, length;
++ int breakno, breaktype;
++ char *ptr;
++ int newPC;
++ threadref thref;
++ int threadid;
++ int thread_min = PID_MAX + MAX_NO_CPUS;
++#ifdef old_thread_list
++ int maxthreads;
++#endif
++ int nothreads;
++ unsigned long flags;
++ int gdb_regs[NUMREGBYTES / 4];
++ int dr6;
++ IF_SMP(int entry_state = 0); /* 0, ok, 1, no nmi, 2 sync failed */
++#define NO_NMI 1
++#define NO_SYNC 2
++#define regs (*linux_regs)
++#define NUMREGS NUMREGBYTES/4
++ /*
++ * 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)) {
++ printk("ignoring non-kernel exception\n");
++ print_regs(®s);
++ return (0);
++ }
+
-+Debugging Setup
-+===============
++ kgdb_local_irq_save(flags);
+
-+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.
++ /* Get kgdb spinlock */
+
-+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 the
-+appropriate modem eliminator (null modem) cable(s) for this.
++ KGDB_SPIN_LOCK(&kgdb_spinlock);
++ rdtscll(kgdb_info.entry_tsc);
++ /*
++ * We depend on this spinlock and the NMI watch dog to control the
++ * other cpus. They will arrive at "in_kgdb()" as a result of the
++ * NMI and will wait there for the following spin locks to be
++ * released.
++ */
++#ifdef CONFIG_SMP
+
-+Decide on which tty port you want the machines to communicate, then
-+connect them up back-to-back using the null modem cable. COM1 is
-+/dev/ttyS0 and COM2 is /dev/ttyS1. You should test this connection
-+with the two machines prior to trying to debug a kernel. Once you
-+have it working, on the TARGET machine, enter:
++#if 0
++ if (cpu_callout_map & ~MAX_CPU_MASK) {
++ printk("kgdb : too many cpus, possibly not mapped"
++ " in contiguous space, change MAX_NO_CPUS"
++ " in kgdb_stub and make new kernel.\n"
++ " cpu_callout_map is %lx\n", cpu_callout_map);
++ goto exit_just_unlock;
++ }
++#endif
++ if (spinlock_count == 1) {
++ int time = 0, end_time, dum = 0;
++ int i;
++ int cpu_logged_in[MAX_NO_CPUS] = {[0 ... MAX_NO_CPUS - 1] = (0)
++ };
++ if (remote_debug) {
++ printk("kgdb : cpu %d entry, syncing others\n",
++ smp_processor_id());
++ }
++ for (i = 0; i < MAX_NO_CPUS; i++) {
++ /*
++ * Use trylock as we may already hold the lock if
++ * we are holding the cpu. Net result is all
++ * locked.
++ */
++ spin_trylock(&waitlocks[i]);
++ }
++ for (i = 0; i < MAX_NO_CPUS; i++)
++ cpu_logged_in[i] = 0;
++ /*
++ * Wait for their arrival. We know the watch dog is active if
++ * in_kgdb() has ever been called, as it is always called on a
++ * watchdog tick.
++ */
++ rdtsc(dum, time);
++ end_time = time + 2; /* Note: we use the High order bits! */
++ i = 1;
++ if (num_online_cpus() > 1) {
++ int me_in_kgdb = in_kgdb_entry_log[smp_processor_id()];
++ smp_send_nmi_allbutself();
++ while (i < num_online_cpus() && time != end_time) {
++ int j;
++ for (j = 0; j < MAX_NO_CPUS; j++) {
++ if (waiting_cpus[j].task &&
++ !cpu_logged_in[j]) {
++ i++;
++ cpu_logged_in[j] = 1;
++ if (remote_debug) {
++ printk
++ ("kgdb : cpu %d arrived at kgdb\n",
++ j);
++ }
++ break;
++ } else if (!waiting_cpus[j].task &&
++ !cpu_online(j)) {
++ waiting_cpus[j].task = NOCPU;
++ cpu_logged_in[j] = 1;
++ waiting_cpus[j].hold = 1;
++ break;
++ }
++ if (!waiting_cpus[j].task &&
++ in_kgdb_here_log[j]) {
+
-+setserial /dev/ttyS0 (or what ever tty you are using)
++ int wait = 100000;
++ while (wait--) ;
++ if (!waiting_cpus[j].task &&
++ in_kgdb_here_log[j]) {
++ printk
++ ("kgdb : cpu %d stall"
++ " in in_kgdb\n",
++ j);
++ i++;
++ cpu_logged_in[j] = 1;
++ waiting_cpus[j].task =
++ (struct task_struct
++ *) 1;
++ }
++ }
++ }
+
-+and record the port address and the IRQ number.
++ if (in_kgdb_entry_log[smp_processor_id()] >
++ (me_in_kgdb + 10)) {
++ break;
++ }
+
-+On the DEVELOPMENT machine you need to apply the patch for the kgdb
-+hooks. You have probably already done that if you are reading this
-+file.
++ rdtsc(dum, time);
++ }
++ if (i < num_online_cpus()) {
++ printk
++ ("kgdb : time out, proceeding without sync\n");
++#if 0
++ printk("kgdb : Waiting_cpus: 0 = %d, 1 = %d\n",
++ waiting_cpus[0].task != 0,
++ waiting_cpus[1].task != 0);
++ printk("kgdb : Cpu_logged in: 0 = %d, 1 = %d\n",
++ cpu_logged_in[0], cpu_logged_in[1]);
++ printk
++ ("kgdb : in_kgdb_here_log in: 0 = %d, 1 = %d\n",
++ in_kgdb_here_log[0] != 0,
++ in_kgdb_here_log[1] != 0);
++#endif
++ entry_state = NO_SYNC;
++ } else {
++#if 0
++ int ent =
++ in_kgdb_entry_log[smp_processor_id()] -
++ me_in_kgdb;
++ printk("kgdb : sync after %d entries\n", ent);
++#endif
++ }
++ } else {
++ if (remote_debug) {
++ printk
++ ("kgdb : %d cpus, but watchdog not active\n"
++ "proceeding without locking down other cpus\n",
++ num_online_cpus());
++ entry_state = NO_NMI;
++ }
++ }
++ }
++#endif
+
-+On your DEVELOPMENT machine, go to your kernel source directory and do
-+"make Xconfig" where X is one of "x", "menu", or "". If you are
-+configuring in the standard serial driver, it must not be a module.
-+Either yes or no is ok, but making the serial driver a module means it
-+will initialize after kgdb has set up the UART interrupt code and may
-+cause a failure of the control-C option discussed below. The configure
-+question for the serial driver is under the "Character devices" heading
-+and is:
++ if (remote_debug) {
++ unsigned long *lp = (unsigned long *) &linux_regs;
+
-+"Standard/generic (8250/16550 and compatible UARTs) serial support"
++ printk("handle_exception(exceptionVector=%d, "
++ "signo=%d, err_code=%d, linux_regs=%p)\n",
++ exceptionVector, signo, err_code, linux_regs);
++ if (debug_regs) {
++ print_regs(®s);
++ printk("Stk: %8lx %8lx %8lx %8lx"
++ " %8lx %8lx %8lx %8lx\n",
++ lp[0], lp[1], lp[2], lp[3],
++ lp[4], lp[5], lp[6], lp[7]);
++ printk(" %8lx %8lx %8lx %8lx"
++ " %8lx %8lx %8lx %8lx\n",
++ lp[8], lp[9], lp[10], lp[11],
++ lp[12], lp[13], lp[14], lp[15]);
++ printk(" %8lx %8lx %8lx %8lx "
++ "%8lx %8lx %8lx %8lx\n",
++ lp[16], lp[17], lp[18], lp[19],
++ lp[20], lp[21], lp[22], lp[23]);
++ printk(" %8lx %8lx %8lx %8lx "
++ "%8lx %8lx %8lx %8lx\n",
++ lp[24], lp[25], lp[26], lp[27],
++ lp[28], lp[29], lp[30], lp[31]);
++ }
++ }
+
-+Go down to the kernel debugging menu item and open it up. Enable the
-+kernel kgdb stub code by selecting that item. You can also choose to
-+turn on the "-ggdb -O1" compile options. The -ggdb causes the compiler
-+to put more debug info (like local symbols) in the object file. On the
-+i386 -g and -ggdb are the same so this option just reduces to "O1". The
-+-O1 reduces the optimization level. This may be helpful in some cases,
-+be aware, however, that this may also mask the problem you are looking
-+for.
++ /* Disable hardware debugging while we are in kgdb */
++ /* Get the debug register status register */
++/* *INDENT-OFF* */
++ __asm__("movl %0,%%db7"
++ : /* no output */
++ :"r"(0));
+
-+The baud rate. Default is 115200. What ever you choose be sure that
-+the host machine is set to the same speed. I recommend the default.
++ asm volatile ("movl %%db6, %0\n"
++ :"=r" (hw_breakpoint_status)
++ :);
+
-+The port. This is the I/O address of the serial UART that you should
-+have gotten using setserial as described above. The standard COM1 port
-+(3f8) using IRQ 4 is default. COM2 is 2f8 which by convention uses IRQ
-+3.
++/* *INDENT-ON* */
++ switch (exceptionVector) {
++ case 0: /* divide error */
++ case 1: /* debug exception */
++ case 2: /* NMI */
++ case 3: /* breakpoint */
++ case 4: /* overflow */
++ case 5: /* bounds check */
++ case 6: /* invalid opcode */
++ case 7: /* device not available */
++ case 8: /* double fault (errcode) */
++ case 10: /* invalid TSS (errcode) */
++ case 12: /* stack fault (errcode) */
++ case 16: /* floating point error */
++ case 17: /* alignment check (errcode) */
++ default: /* any undocumented */
++ break;
++ case 11: /* segment not present (errcode) */
++ case 13: /* general protection (errcode) */
++ case 14: /* page fault (special errcode) */
++ case 19: /* cache flush denied */
++ if (mem_err_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.
++ */
++ mem_err = 1; /* set mem error flag */
++ mem_err_expected = 0;
++ mem_err_cnt++; /* helps in debugging */
++ /* make valid address */
++ regs.eax = (long) &garbage_loc;
++ /* make valid address */
++ regs.edx = (long) &garbage_loc;
++ if (remote_debug)
++ printk("Return after memory error: "
++ "mem_err_cnt=%d\n", mem_err_cnt);
++ if (debug_regs)
++ print_regs(®s);
++ goto exit_kgdb;
++ }
++ break;
++ }
++ if (remote_debug)
++ printk("kgdb : entered kgdb on cpu %d\n", smp_processor_id());
+
-+The port IRQ (see above).
++ gdb_i386vector = exceptionVector;
++ gdb_i386errcode = err_code;
++ kgdb_info.called_from = __builtin_return_address(0);
++#ifdef CONFIG_SMP
++ /*
++ * OK, we can now communicate, lets tell gdb about the sync.
++ * but only if we had a problem.
++ */
++ switch (entry_state) {
++ case NO_NMI:
++ to_gdb("NMI not active, other cpus not stopped\n");
++ break;
++ case NO_SYNC:
++ to_gdb("Some cpus not stopped, see 'kgdb_info' for details\n");
++ default:;
++ }
+
-+Stack overflow test. This option makes a minor change in the trap,
-+system call and interrupt code to detect stack overflow and transfer
-+control to kgdb if it happens. (Some platforms have this in the
-+baseline code, but the i386 does not.)
++#endif
++/*
++ * Set up the gdb function call area.
++ */
++ trap_cpu = smp_processor_id();
++ OLD_esp = NEW_esp = (int) (&linux_regs->esp);
+
-+You can also configure the system to recognize the boot option
-+"console=kgdb" which if given will cause all console output during
-+booting to be put thru gdb as well as other consoles. This option
-+requires that gdb and kgdb be connected prior to sending console output
-+so, if they are not, a breakpoint is executed to force the connection.
-+This will happen before any kernel output (it is going thru gdb, right),
-+and will stall the boot until the connection is made.
++ IF_SMP(once_again:)
++ /* reply to host that an exception has occurred */
++ remcomOutBuffer[0] = 'S';
++ remcomOutBuffer[1] = hexchars[signo >> 4];
++ remcomOutBuffer[2] = hexchars[signo % 16];
++ remcomOutBuffer[3] = 0;
+
-+You can also configure in a patch to SysRq to enable the kGdb SysRq.
-+This request generates a breakpoint. Since the serial port IRQ line is
-+set up after any serial drivers, it is possible that this command will
-+work when the control-C will not.
++ putpacket(remcomOutBuffer);
+
-+Save and exit the Xconfig program. Then do "make clean" , "make dep"
-+and "make bzImage" (or whatever target you want to make). This gets the
-+kernel compiled with the "-g" option set -- necessary for debugging.
++ 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 'd':
++ remote_debug = !(remote_debug); /* toggle debug flag */
++ printk("Remote debug %s\n",
++ remote_debug ? "on" : "off");
++ break;
++ case 'g': /* return the value of the CPU registers */
++ get_gdb_regs(usethread, ®s, gdb_regs);
++ 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;
+
-+You have just built the kernel on your DEVELOPMENT machine that you
-+intend to run on your TARGET machine.
++ case 'P':{ /* set the value of a single CPU register -
++ return OK */
++ /*
++ * For some reason, gdb wants to talk about psudo
++ * registers (greater than 15). These may have
++ * meaning for ptrace, but for us it is safe to
++ * ignor them. We do this by dumping them into
++ * _GS which we also ignor, but do have memory for.
++ */
++ int regno;
+
-+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.
++ ptr = &remcomInBuffer[1];
++ regs_to_gdb_regs(gdb_regs, ®s);
++ if ((!usethread || usethread == current) &&
++ hexToInt(&ptr, ®no) &&
++ *ptr++ == '=' && (regno >= 0)) {
++ regno =
++ (regno >= NUMREGS ? _GS : regno);
++ hex2mem(ptr, (char *) &gdb_regs[regno],
++ 4, 0);
++ gdb_regs_to_regs(gdb_regs, ®s);
++ strcpy(remcomOutBuffer, "OK");
++ break;
++ }
++ strcpy(remcomOutBuffer, "E01");
++ break;
++ }
+
-+Copy this kernel to your target machine using your usual procedures. I
-+usually arrange to copy development:
-+/usr/src/linux/arch/i386/boot/bzImage 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 (see "man
-+lilo" for details on how to set this up) on the new kernel on the target
-+machine so that it will boot! Then boot the kernel on the target
-+machine.
++ /* 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) &&
++ (*(ptr++) == ',') && (hexToInt(&ptr, &length))) {
++ ptr = 0;
++ /*
++ * hex doubles the byte count
++ */
++ if (length > (BUFMAX / 2))
++ length = BUFMAX / 2;
++ mem2hex((char *) addr,
++ remcomOutBuffer, length, 1);
++ if (mem_err) {
++ strcpy(remcomOutBuffer, "E03");
++ debug_error("memory fault\n", NULL);
++ }
++ }
+
-+On the DEVELOPMENT machine, create a file called .gdbinit in the
-+directory /usr/src/linux. An example .gdbinit file looks like this:
++ if (ptr) {
++ strcpy(remcomOutBuffer, "E01");
++ debug_error
++ ("malformed read memory command: %s\n",
++ remcomInBuffer);
++ }
++ break;
+
-+shell echo -e "\003" >/dev/ttyS0
-+set remotebaud 38400 (or what ever speed you have chosen)
-+target remote /dev/ttyS0
++ /* 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) &&
++ (*(ptr++) == ',') &&
++ (hexToInt(&ptr, &length)) && (*(ptr++) == ':')) {
++ hex2mem(ptr, (char *) addr, length, 1);
+
++ if (mem_err) {
++ strcpy(remcomOutBuffer, "E03");
++ debug_error("memory fault\n", NULL);
++ } else {
++ strcpy(remcomOutBuffer, "OK");
++ }
+
-+Change the "echo" and "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.
++ ptr = 0;
++ }
++ if (ptr) {
++ strcpy(remcomOutBuffer, "E02");
++ debug_error
++ ("malformed write memory command: %s\n",
++ remcomInBuffer);
++ }
++ break;
++ case 'S':
++ remcomInBuffer[0] = 's';
++ case 'C':
++ /* Csig;AA..AA where ;AA..AA is optional
++ * continue with signal
++ * Since signals are meaning less to us, delete that
++ * part and then fall into the 'c' code.
++ */
++ ptr = &remcomInBuffer[1];
++ length = 2;
++ while (*ptr && *ptr != ';') {
++ length++;
++ ptr++;
++ }
++ if (*ptr) {
++ do {
++ ptr++;
++ *(ptr - length++) = *ptr;
++ } while (*ptr);
++ } else {
++ remcomInBuffer[1] = 0;
++ }
+
-+You are now ready to try it out.
++ /* cAA..AA Continue at address AA..AA(optional) */
++ /* sAA..AA Step one instruction from AA..AA(optional) */
++ /* D detach, reply OK and then continue */
++ case 'c':
++ case 's':
++ case 'D':
+
-+Boot your target machine with "kgdb" in the boot command i.e. something
-+like:
++ /* try to read optional parameter,
++ pc unchanged if no parm */
++ ptr = &remcomInBuffer[1];
++ if (hexToInt(&ptr, &addr)) {
++ if (remote_debug)
++ printk("Changing EIP to 0x%x\n", addr);
+
-+lilo> test kgdb
++ regs.eip = addr;
++ }
+
-+or if you also want console output thru gdb:
++ newPC = regs.eip;
+
-+lilo> test kgdb console=kgdb
++ /* clear the trace bit */
++ regs.eflags &= 0xfffffeff;
+
-+You should see the lilo message saying it has loaded the kernel and then
-+all output stops. The kgdb stub is trying to connect with gdb. Start
-+gdb something like this:
++ /* set the trace bit if we're stepping */
++ if (remcomInBuffer[0] == 's')
++ regs.eflags |= 0x100;
+
++ /* detach is a friendly version of continue. Note that
++ debugging is still enabled (e.g hit control C)
++ */
++ if (remcomInBuffer[0] == 'D') {
++ strcpy(remcomOutBuffer, "OK");
++ putpacket(remcomOutBuffer);
++ }
+
-+On your DEVELOPMENT machine, cd /usr/src/linux and enter "gdb vmlinux".
-+When gdb gets the symbols loaded it will read your .gdbinit file and, 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 kgdb activation
-+code.
++ if (remote_debug) {
++ printk("Resuming execution\n");
++ print_regs(®s);
++ }
++ asm volatile ("movl %%db6, %0\n":"=r" (dr6)
++ :);
++ if (!(dr6 & 0x4000)) {
++ for (breakno = 0; breakno < 4; ++breakno) {
++ if (dr6 & (1 << breakno) &&
++ (breakinfo[breakno].type == 0)) {
++ /* Set restore flag */
++ regs.eflags |= 0x10000;
++ break;
++ }
++ }
++ }
++ correct_hw_break();
++ asm volatile ("movl %0, %%db6\n"::"r" (0));
++ goto exit_kgdb;
+
-+The gdb interaction should look something like this:
++ /* kill the program */
++ case 'k': /* do nothing */
++ break;
+
-+ 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...
-+ breakpoint () at i386-stub.c:750
-+ 750 }
-+ (gdb)
++ /* query */
++ case 'q':
++ nothreads = 0;
++ switch (remcomInBuffer[1]) {
++ case 'f':
++ threadid = 1;
++ thread_list = 2;
++ thread_list_start = (usethread ? : current);
++ case 's':
++ if (!cmp_str(&remcomInBuffer[2],
++ "ThreadInfo", 10))
++ break;
+
-+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.
++ remcomOutBuffer[nothreads++] = 'm';
++ for (; threadid < PID_MAX + MAX_NO_CPUS;
++ threadid++) {
++ thread = getthread(threadid);
++ if (thread) {
++ nothreads += int_to_hex_v(
++ &remcomOutBuffer[
++ nothreads],
++ threadid);
++ if (thread_min > threadid)
++ thread_min = threadid;
++ remcomOutBuffer[
++ nothreads] = ',';
++ nothreads++;
++ if (nothreads > BUFMAX - 10)
++ break;
++ }
++ }
++ if (remcomOutBuffer[nothreads - 1] == 'm') {
++ remcomOutBuffer[nothreads - 1] = 'l';
++ } else {
++ nothreads--;
++ }
++ remcomOutBuffer[nothreads] = 0;
++ break;
+
-+If you have the kgdb console enabled when you continue, gdb will print
-+out all the console messages.
++#ifdef old_thread_list /* Old thread info request */
++ case 'L':
++ /* List threads */
++ thread_list = 2;
++ thread_list_start = (usethread ? : current);
++ unpack_byte(remcomInBuffer + 3, &maxthreads);
++ unpack_threadid(remcomInBuffer + 5, &thref);
++ do {
++ int buf_thread_limit =
++ (BUFMAX - 22) / BUF_THREAD_ID_SIZE;
++ if (maxthreads > buf_thread_limit) {
++ maxthreads = buf_thread_limit;
++ }
++ } while (0);
++ remcomOutBuffer[0] = 'q';
++ remcomOutBuffer[1] = 'M';
++ remcomOutBuffer[4] = '0';
++ pack_threadid(remcomOutBuffer + 5, &thref);
+
-+The above example caused a breakpoint relatively early in the boot
-+process. For the i386 kgdb it is possible to code a break instruction
-+as the first C-language point in init/main.c, i.e. as the first instruction
-+in start_kernel(). This could be done as follows:
++ threadid = threadref_to_int(&thref);
++ for (nothreads = 0;
++ nothreads < maxthreads &&
++ threadid < PID_MAX + MAX_NO_CPUS;
++ threadid++) {
++ thread = getthread(threadid);
++ if (thread) {
++ int_to_threadref(&thref,
++ threadid);
++ pack_threadid(remcomOutBuffer +
++ 21 +
++ nothreads * 16,
++ &thref);
++ nothreads++;
++ if (thread_min > threadid)
++ thread_min = threadid;
++ }
++ }
+
-+#include <asm/kgdb.h>
-+ breakpoint();
++ if (threadid == PID_MAX + MAX_NO_CPUS) {
++ remcomOutBuffer[4] = '1';
++ }
++ pack_hex_byte(remcomOutBuffer + 2, nothreads);
++ remcomOutBuffer[21 + nothreads * 16] = '\0';
++ break;
++#endif
++ case 'C':
++ /* Current thread id */
++ remcomOutBuffer[0] = 'Q';
++ remcomOutBuffer[1] = 'C';
++ threadid = current->pid;
++ if (!threadid) {
++ /*
++ * idle thread
++ */
++ for (threadid = PID_MAX;
++ threadid < PID_MAX + MAX_NO_CPUS;
++ threadid++) {
++ if (current ==
++ idle_task(threadid -
++ PID_MAX))
++ break;
++ }
++ }
++ int_to_threadref(&thref, threadid);
++ pack_threadid(remcomOutBuffer + 2, &thref);
++ remcomOutBuffer[18] = '\0';
++ break;
+
-+This breakpoint() is really a function that sets up the breakpoint and
-+single-step hardware trap cells and then executes a breakpoint. Any
-+early hard coded breakpoint will need to use this function. Once the
-+trap cells are set up they need not be set again, but doing it again
-+does not hurt anything, so you don't need to be concerned about which
-+breakpoint is hit first. Once the trap cells are set up (and the kernel
-+sets them up in due course even if breakpoint() is never called) the
-+macro:
++ case 'E':
++ /* Print exception info */
++ printexceptioninfo(exceptionVector,
++ err_code, remcomOutBuffer);
++ break;
++ case 'T':{
++ char * nptr;
++ /* Thread extra info */
++ if (!cmp_str(&remcomInBuffer[2],
++ "hreadExtraInfo,", 15)) {
++ break;
++ }
++ ptr = &remcomInBuffer[17];
++ hexToInt(&ptr, &threadid);
++ thread = getthread(threadid);
++ nptr = &thread->comm[0];
++ length = 0;
++ ptr = &remcomOutBuffer[0];
++ do {
++ length++;
++ ptr = pack_hex_byte(ptr, *nptr++);
++ } while (*nptr && length < 16);
++ /*
++ * would like that 16 to be the size of
++ * task_struct.comm but don't know the
++ * syntax..
++ */
++ *ptr = 0;
++ }
++ }
++ break;
+
-+BREAKPOINT;
++ /* 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;
++ }
++ /*
++ * Just in case I forget what this is all about,
++ * the "thread info" command to gdb causes it
++ * to ask for a thread list. It then switches
++ * to each thread and asks for the registers.
++ * For this (and only this) usage, we want to
++ * fudge the registers of tasks not on the run
++ * list (i.e. waiting) to show the routine that
++ * called schedule. Also, gdb, is a minimalist
++ * in that if the current thread is the last
++ * it will not re-read the info when done.
++ * This means that in this case we must show
++ * the real registers. So here is how we do it:
++ * Each entry we keep track of the min
++ * thread in the list (the last that gdb will)
++ * get info for. We also keep track of the
++ * starting thread.
++ * "thread_list" is cleared when switching back
++ * to the min thread if it is was current, or
++ * if it was not current, thread_list is set
++ * to 1. When the switch to current comes,
++ * if thread_list is 1, clear it, else do
++ * nothing.
++ */
++ usethread = thread;
++ if ((thread_list == 1) &&
++ (thread == thread_list_start)) {
++ thread_list = 0;
++ }
++ if (thread_list && (threadid == thread_min)) {
++ if (thread == thread_list_start) {
++ thread_list = 0;
++ } else {
++ thread_list = 1;
++ }
++ }
++ /* follow through */
++ case 'c':
++ remcomOutBuffer[0] = 'O';
++ remcomOutBuffer[1] = 'K';
++ remcomOutBuffer[2] = '\0';
++ break;
++ }
++ break;
+
-+will generate an inline breakpoint. This may be more useful as it stops
-+the processor at the instruction instead of in a function a step removed
-+from the location of interest. In either case <asm/kgdb.h> must be
-+included to define both breakpoint() and BREAKPOINT.
++ /* 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';
++ if (thread_min > threadid)
++ thread_min = threadid;
++ } else {
++ remcomOutBuffer[0] = 'E';
++ remcomOutBuffer[1] = '\0';
++ }
++ break;
+
-+Triggering kgdbstub at other times
-+==================================
++ case 'Y': /* set up a hardware breakpoint */
++ 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;
+
-+Often you don't need to enter the debugger until much later in the boot
-+or even after the machine has been running for some time. Once the
-+kernel is booted and interrupts are on, you can force the system to
-+enter the debugger by sending a control-C to the debug port. This is
-+what the first line of the recommended .gdbinit file does. This allows
-+you to start gdb any time after the system is up as well as when the
-+system is already at a breakpoint. (In the case where the system is
-+already at a breakpoint the control-C is not needed, however, it will
-+be ignored by the target so no harm is done. Also note the the echo
-+command assumes that the port speed is already set. This will be true
-+once gdb has connected, but it is best to set the port speed before you
-+run gdb.)
++ /* 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;
+
-+Another simple way to do this is to put the following file in you ~/bin
-+directory:
++ case 'r': /* reboot */
++ strcpy(remcomOutBuffer, "OK");
++ putpacket(remcomOutBuffer);
++ /*to_gdb("Rebooting\n"); */
++ /* triplefault no return from here */
++ {
++ static long no_idt[2];
++ __asm__ __volatile__("lidt %0"::"m"(no_idt[0]));
++ BREAKPOINT();
++ }
+
-+#!/bin/bash
-+echo -e "\003" > /dev/ttyS0
++ } /* switch */
+
-+Here, the ttyS0 should be replaced with what ever port you are using.
-+The "\003" is control-C. Once you are connected with gdb, you can enter
-+control-C at the command prompt.
++ /* reply to the request */
++ putpacket(remcomOutBuffer);
++ } /* while(1==1) */
++ /*
++ * reached by goto only.
++ */
++ exit_kgdb:
++ /*
++ * Here is where we set up to trap a gdb function call. NEW_esp
++ * will be changed if we are trying to do this. We handle both
++ * adding and subtracting, thus allowing gdb to put grung on
++ * the stack which it removes later.
++ */
++ if (NEW_esp != OLD_esp) {
++ int *ptr = END_OF_LOOKASIDE;
++ if (NEW_esp < OLD_esp)
++ ptr -= (OLD_esp - NEW_esp) / sizeof (int);
++ *--ptr = linux_regs->eflags;
++ *--ptr = linux_regs->xcs;
++ *--ptr = linux_regs->eip;
++ *--ptr = linux_regs->ecx;
++ *--ptr = linux_regs->ebx;
++ *--ptr = linux_regs->eax;
++ linux_regs->ecx = NEW_esp - (sizeof (int) * 6);
++ linux_regs->ebx = (unsigned int) END_OF_LOOKASIDE;
++ if (NEW_esp < OLD_esp) {
++ linux_regs->eip = (unsigned int) fn_call_stub;
++ } else {
++ linux_regs->eip = (unsigned int) fn_rtn_stub;
++ linux_regs->eax = NEW_esp;
++ }
++ linux_regs->eflags &= ~(IF_BIT | TF_BIT);
++ }
++#ifdef CONFIG_SMP
++ /*
++ * Release gdb wait locks
++ * Sanity check time. Must have at least one cpu to run. Also single
++ * step must not be done if the current cpu is on hold.
++ */
++ if (spinlock_count == 1) {
++ int ss_hold = (regs.eflags & 0x100) && kgdb_info.hold_on_sstep;
++ int cpu_avail = 0;
++ int i;
+
-+An alternative way to get control to the debugger is to enable the kGdb
-+SysRq command. Then you would enter Alt-SysRq-g (all three keys at the
-+same time, but push them down in the order given). To refresh your
-+memory of the available SysRq commands try Alt-SysRq-=. Actually any
-+undefined command could replace the "=", but I like to KNOW that what I
-+am pushing will never be defined.
++ for (i = 0; i < MAX_NO_CPUS; i++) {
++ if (!cpu_online(i))
++ break;
++ if (!hold_cpu(i)) {
++ cpu_avail = 1;
++ }
++ }
++ /*
++ * Early in the bring up there will be NO cpus on line...
++ */
++ if (!cpu_avail && !cpus_empty(cpu_online_map)) {
++ to_gdb("No cpus unblocked, see 'kgdb_info.hold_cpu'\n");
++ goto once_again;
++ }
++ if (hold_cpu(smp_processor_id()) && (regs.eflags & 0x100)) {
++ to_gdb
++ ("Current cpu must be unblocked to single step\n");
++ goto once_again;
++ }
++ if (!(ss_hold)) {
++ int i;
++ for (i = 0; i < MAX_NO_CPUS; i++) {
++ if (!hold_cpu(i)) {
++ spin_unlock(&waitlocks[i]);
++ }
++ }
++ } else {
++ spin_unlock(&waitlocks[smp_processor_id()]);
++ }
++ /* Release kgdb spinlock */
++ KGDB_SPIN_UNLOCK(&kgdb_spinlock);
++ /*
++ * If this cpu is on hold, this is where we
++ * do it. Note, the NMI will pull us out of here,
++ * but will return as the above lock is not held.
++ * We will stay here till another cpu releases the lock for us.
++ */
++ spin_unlock_wait(waitlocks + smp_processor_id());
++ kgdb_local_irq_restore(flags);
++ return (0);
++ }
++#if 0
++exit_just_unlock:
++#endif
++#endif
++ /* Release kgdb spinlock */
++ KGDB_SPIN_UNLOCK(&kgdb_spinlock);
++ kgdb_local_irq_restore(flags);
++ return (0);
++}
+
-+Debugging hints
-+===============
++/* this function is used to set up exception handlers for tracing and
++ * breakpoints.
++ * This function is not needed as the above line does all that is needed.
++ * We leave it for backward compatitability...
++ */
++void
++set_debug_traps(void)
++{
++ /*
++ * linux_debug_hook is defined in traps.c. We store a pointer
++ * to our own exception handler into it.
+
-+You can break into the target machine at any time from the development
-+machine by typing ^C (see above paragraph). If the target machine has
-+interrupts enabled this will stop it in the kernel and enter the
-+debugger.
++ * But really folks, every hear of labeled common, an old Fortran
++ * concept. Lots of folks can reference it and it is define if
++ * anyone does. Only one can initialize it at link time. We do
++ * this with the hook. See the statement above. No need for any
++ * executable code and it is ready as soon as the kernel is
++ * loaded. Very desirable in kernel debugging.
+
-+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. The exploratory breakpoints can be
-+entered either thru gdb or hard coded into the source. This is very
-+handy if you do something like:
++ linux_debug_hook = handle_exception ;
++ */
+
-+if (<it hurts>) BREAKPOINT;
++ /* In case GDB is started before us, ack any packets (presumably
++ "$?#xx") sitting there.
++ putDebugChar ('+');
+
++ initialized = 1;
++ */
++}
+
-+There is a copy of an e-mail in the Documentation/i386/kgdb/ directory
-+(debug-nmi.txt) 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.
++/* 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. */
++/* But really, just use the BREAKPOINT macro. We will handle the int stuff
++ */
+
-+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, first clear all breakpoints and
-+continue, then type ^Z to suspend gdb and then kill it with "kill %1" or
-+something similar.
++#ifdef later
++/*
++ * possibly we should not go thru the traps.c code at all? Someday.
++ */
++void
++do_kgdb_int3(struct pt_regs *regs, long error_code)
++{
++ kgdb_handle_exception(3, 5, error_code, regs);
++ return;
++}
++#endif
++#undef regs
++#ifdef CONFIG_TRAP_BAD_SYSCALL_EXITS
++asmlinkage void
++bad_sys_call_exit(int stuff)
++{
++ struct pt_regs *regs = (struct pt_regs *) &stuff;
++ printk("Sys call %d return with %x preempt_count\n",
++ (int) regs->orig_eax, preempt_count());
++}
++#endif
++#ifdef CONFIG_STACK_OVERFLOW_TEST
++#include <asm/kgdb.h>
++asmlinkage void
++stack_overflow(void)
++{
++#ifdef BREAKPOINT
++ BREAKPOINT();
++#else
++ printk("Kernel stack overflow, looping forever\n");
++#endif
++ while (1) {
++ }
++}
++#endif
+
-+If gdbstub Does Not Work
-+========================
++#if defined(CONFIG_SMP) || defined(CONFIG_KGDB_CONSOLE)
++char gdbconbuf[BUFMAX];
+
-+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. Make sure it works
-+in both directions. There is no point in tearing out your hair in the
-+kernel if the line doesn't work.
++static void
++kgdb_gdb_message(const char *s, unsigned count)
++{
++ int i;
++ int wcount;
++ char *bufptr;
++ /*
++ * This takes care of NMI while spining out chars to gdb
++ */
++ IF_SMP(in_kgdb_console = 1);
++ 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;
+
-+All of the real action takes place in the file
-+/usr/src/linux/arch/i386/kernel/kgdb_stub.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:
++ putpacket(gdbconbuf);
+
-+ set remotedebug
++ }
++ IF_SMP(in_kgdb_console = 0);
++}
++#endif
++#ifdef CONFIG_SMP
++static void
++to_gdb(const char *s)
++{
++ int count = 0;
++ while (s[count] && (count++ < BUFMAX)) ;
++ kgdb_gdb_message(s, count);
++}
++#endif
++#ifdef CONFIG_KGDB_CONSOLE
++#include <linux/console.h>
++#include <linux/init.h>
++#include <linux/fs.h>
++#include <asm/uaccess.h>
++#include <asm/semaphore.h>
+
-+This will print out the protocol messages that gdb is exchanging with
-+the target machine.
++void
++kgdb_console_write(struct console *co, const char *s, unsigned count)
++{
+
-+Another place to look is /usr/src/arch/i386/lib/kgdb_serial.c. This is
-+the code that talks to the serial port on the target side. There might
-+be a problem there. In particular there is a section of this code that
-+tests the UART which will tell you what UART you have if you define
-+"PRNT" (just remove "_off" from the #define PRNT_off). To view this
-+report you will need to boot the system without any beakpoints. This
-+allows the kernel to run to the point where it calls kgdb to set up
-+interrupts. At this time kgdb will test the UART and print out the type
-+it finds. (You need to wait so that the printks are actually being
-+printed. Early in the boot they are cached, waiting for the console to
-+be enabled. Also, if kgdb is entered thru a breakpoint it is possible
-+to cause a dead lock by calling printk when the console is locked. The
-+stub thus avoids doing printks from breakpoints, especially in the
-+serial code.) At this time, if the UART fails to do the expected thing,
-+kgdb will print out (using printk) information on what failed. (These
-+messages will be buried in all the other boot up messages. Look for
-+lines that start with "gdb_hook_interrupt:". You may want to use dmesg
-+once the system is up to view the log. If this fails or if you still
-+don't connect, review your answers for the port address. Use:
++ if (gdb_i386vector == -1) {
++ /*
++ * We have not yet talked to gdb. What to do...
++ * lets break, on continue we can do the write.
++ * But first tell him whats up. Uh, well no can do,
++ * as this IS the console. Oh well...
++ * We do need to wait or the messages will be lost.
++ * Other option would be to tell the above code to
++ * ignore this breakpoint and do an auto return,
++ * but that might confuse gdb. Also this happens
++ * early enough in boot up that we don't have the traps
++ * set up yet, so...
++ */
++ breakpoint();
++ }
++ kgdb_gdb_message(s, count);
++}
+
-+setserial /dev/ttyS0
++/*
++ * ------------------------------------------------------------
++ * Serial KGDB driver
++ * ------------------------------------------------------------
++ */
+
-+to get the current port and IRQ information. This command will also
-+tell you what the system found for the UART type. The stub recognizes
-+the following UART types:
++static struct console kgdbcons = {
++ name:"kgdb",
++ write:kgdb_console_write,
++#ifdef CONFIG_KGDB_USER_CONSOLE
++ device:kgdb_console_device,
++#endif
++ flags:CON_PRINTBUFFER | CON_ENABLED,
++ index:-1,
++};
+
-+16450, 16550, and 16550A
++/*
++ * The trick here is that this file gets linked before printk.o
++ * That means we get to peer at the console info in the command
++ * line before it does. If we are up, we register, otherwise,
++ * do nothing. By returning 0, we allow printk to look also.
++ */
++static int kgdb_console_enabled;
+
-+If you are really desperate you can use printk debugging in the
-+kgdbstub code in the target kernel until you get it working. In particular,
-+there is a global variable in /usr/src/linux/arch/i386/kernel/kgdb_stub.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. Likewise there are debug printks in the kgdb_serial.c
-+code that can be turned on with simple changes in the macro defines.
++int __init
++kgdb_console_init(char *str)
++{
++ if ((strncmp(str, "kgdb", 4) == 0) || (strncmp(str, "gdb", 3) == 0)) {
++ register_console(&kgdbcons);
++ kgdb_console_enabled = 1;
++ }
++ return 0; /* let others look at the string */
++}
+
++__setup("console=", kgdb_console_init);
+
-+Debugging Loadable Modules
-+==========================
++#ifdef CONFIG_KGDB_USER_CONSOLE
++static kdev_t kgdb_console_device(struct console *c);
++/* This stuff sort of works, but it knocks out telnet devices
++ * we are leaving it here in case we (or you) find time to figure it out
++ * better..
++ */
+
-+This technique comes courtesy of Edouard Parmelan
-+<Edouard.Parmelan@quadratec.fr>
++/*
++ * We need a real char device as well for when the console is opened for user
++ * space activities.
++ */
+
-+When you run gdb, enter the command
++static int
++kgdb_consdev_open(struct inode *inode, struct file *file)
++{
++ return 0;
++}
+
-+source gdbinit-modules
++static ssize_t
++kgdb_consdev_write(struct file *file, const char *buf,
++ size_t count, loff_t * ppos)
++{
++ int size, ret = 0;
++ static char kbuf[128];
++ static DECLARE_MUTEX(sem);
+
-+This will read in a file of gdb macros that was installed in your
-+kernel source directory when kgdb was installed. This file implements
-+the following commands:
++ /* We are not reentrant... */
++ if (down_interruptible(&sem))
++ return -ERESTARTSYS;
+
-+mod-list
-+ Lists the loaded modules in the form <module-address> <module-name>
++ while (count > 0) {
++ /* need to copy the data from user space */
++ size = count;
++ if (size > sizeof (kbuf))
++ size = sizeof (kbuf);
++ if (copy_from_user(kbuf, buf, size)) {
++ ret = -EFAULT;
++ break;;
++ }
++ kgdb_console_write(&kgdbcons, kbuf, size);
++ count -= size;
++ ret += size;
++ buf += size;
++ }
+
-+mod-print-symbols <module-address>
-+ Prints all the symbols in the indicated module.
++ up(&sem);
+
-+mod-add-symbols <module-address> <object-file-path-name>
-+ Loads the symbols from the object file and associates them
-+ with the indicated module.
++ return ret;
++}
+
-+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.
++struct file_operations kgdb_consdev_fops = {
++ open:kgdb_consdev_open,
++ write:kgdb_consdev_write
++};
++static kdev_t
++kgdb_console_device(struct console *c)
++{
++ return MKDEV(TTYAUX_MAJOR, 1);
++}
+
-+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.
++/*
++ * This routine gets called from the serial stub in the i386/lib
++ * This is so it is done late in bring up (just before the console open).
++ */
++void
++kgdb_console_finit(void)
++{
++ if (kgdb_console_enabled) {
++ char *cptr = cdevname(MKDEV(TTYAUX_MAJOR, 1));
++ char *cp = cptr;
++ while (*cptr && *cptr != '(')
++ cptr++;
++ *cptr = 0;
++ unregister_chrdev(TTYAUX_MAJOR, cp);
++ register_chrdev(TTYAUX_MAJOR, "kgdb", &kgdb_consdev_fops);
++ }
++}
++#endif
++#endif
++#ifdef CONFIG_KGDB_TS
++#include <asm/msr.h> /* time stamp code */
++#include <asm/hardirq.h> /* in_interrupt */
++#ifdef CONFIG_KGDB_TS_64
++#define DATA_POINTS 64
++#endif
++#ifdef CONFIG_KGDB_TS_128
++#define DATA_POINTS 128
++#endif
++#ifdef CONFIG_KGDB_TS_256
++#define DATA_POINTS 256
++#endif
++#ifdef CONFIG_KGDB_TS_512
++#define DATA_POINTS 512
++#endif
++#ifdef CONFIG_KGDB_TS_1024
++#define DATA_POINTS 1024
++#endif
++#ifndef DATA_POINTS
++#define DATA_POINTS 128 /* must be a power of two */
++#endif
++#define INDEX_MASK (DATA_POINTS - 1)
++#if (INDEX_MASK & DATA_POINTS)
++#error "CONFIG_KGDB_TS_COUNT must be a power of 2"
++#endif
++struct kgdb_and_then_struct {
++#ifdef CONFIG_SMP
++ int on_cpu;
++#endif
++ struct task_struct *task;
++ long long at_time;
++ int from_ln;
++ char *in_src;
++ void *from;
++ int *with_shpf;
++ int data0;
++ int data1;
++};
++struct kgdb_and_then_struct2 {
++#ifdef CONFIG_SMP
++ int on_cpu;
++#endif
++ struct task_struct *task;
++ long long at_time;
++ int from_ln;
++ char *in_src;
++ void *from;
++ int *with_shpf;
++ struct task_struct *t1;
++ struct task_struct *t2;
++};
++struct kgdb_and_then_struct kgdb_data[DATA_POINTS];
+
-+Threads
-+=======
++struct kgdb_and_then_struct *kgdb_and_then = &kgdb_data[0];
++int kgdb_and_then_count;
+
-+Each process in a target machine is seen as a gdb thread. gdb thread
-+related commands (info threads, thread n) can be used.
++void
++kgdb_tstamp(int line, char *source, int data0, int data1)
++{
++ static spinlock_t ts_spin = SPIN_LOCK_UNLOCKED;
++ int flags;
++ kgdb_local_irq_save(flags);
++ spin_lock(&ts_spin);
++ rdtscll(kgdb_and_then->at_time);
++#ifdef CONFIG_SMP
++ kgdb_and_then->on_cpu = smp_processor_id();
++#endif
++ kgdb_and_then->task = current;
++ kgdb_and_then->from_ln = line;
++ kgdb_and_then->in_src = source;
++ kgdb_and_then->from = __builtin_return_address(0);
++ kgdb_and_then->with_shpf = (int *) (((flags & IF_BIT) >> 9) |
++ (preempt_count() << 8));
++ kgdb_and_then->data0 = data0;
++ kgdb_and_then->data1 = data1;
++ kgdb_and_then = &kgdb_data[++kgdb_and_then_count & INDEX_MASK];
++ spin_unlock(&ts_spin);
++ kgdb_local_irq_restore(flags);
++#ifdef CONFIG_PREEMPT
+
-+ia-32 hardware breakpoints
-+==========================
++#endif
++ return;
++}
++#endif
++typedef int gdb_debug_hook(int exceptionVector,
++ int signo, int err_code, struct pt_regs *linux_regs);
++gdb_debug_hook *linux_debug_hook = &kgdb_handle_exception; /* histerical reasons... */
+Index: linux/arch/i386/kernel/nmi.c
+===================================================================
+--- linux.orig/arch/i386/kernel/nmi.c
++++ linux/arch/i386/kernel/nmi.c
+@@ -34,7 +34,17 @@
+
+ #include "mach_traps.h"
+
++#ifdef CONFIG_KGDB
++#include <asm/kgdb.h>
++#ifdef CONFIG_SMP
++unsigned int nmi_watchdog = NMI_IO_APIC;
++#else
++unsigned int nmi_watchdog = NMI_LOCAL_APIC;
++#endif
++#else
+ unsigned int nmi_watchdog = NMI_NONE;
++#endif
+
-+kgdb 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.
+ extern int unknown_nmi_panic;
+ static unsigned int nmi_hz = HZ;
+ static unsigned int nmi_perfctr_msr; /* the MSR to reset in NMI handler */
+@@ -466,6 +476,9 @@ void touch_nmi_watchdog (void)
+ for (i = 0; i < NR_CPUS; i++)
+ alert_counter[i] = 0;
+ }
++#ifdef CONFIG_KGDB
++int tune_watchdog = 5*HZ;
++#endif
+
+ extern void die_nmi(struct pt_regs *, const char *msg);
+
+@@ -481,12 +494,24 @@ void nmi_watchdog_tick (struct pt_regs *
+
+ sum = irq_stat[cpu].apic_timer_irqs;
+
++#ifdef CONFIG_KGDB
++ if (!in_kgdb(regs) && last_irq_sums[cpu] == sum) {
+
-+Each hardware breakpoint can be of one of the following three types.
++#else
+ if (last_irq_sums[cpu] == sum) {
++#endif
+ /*
+ * Ayiee, looks like this CPU is stuck ...
+ * wait a few IRQs (5 seconds) before doing the oops ...
+ */
+ alert_counter[cpu]++;
++#ifdef CONFIG_KGDB
++ if (alert_counter[cpu] == tune_watchdog) {
++ kgdb_handle_exception(2, SIGPWR, 0, regs);
++ last_irq_sums[cpu] = sum;
++ alert_counter[cpu] = 0;
++ }
++#endif
+ if (alert_counter[cpu] == 30*nmi_hz)
+ die_nmi(regs, "NMI Watchdog detected LOCKUP");
+ } else {
+Index: linux/arch/i386/kernel/smp.c
+===================================================================
+--- linux.orig/arch/i386/kernel/smp.c
++++ linux/arch/i386/kernel/smp.c
+@@ -459,7 +459,17 @@ void flush_tlb_all(void)
+ {
+ on_each_cpu(do_flush_tlb_all, NULL, 1, 1);
+ }
+-
++#ifdef CONFIG_KGDB
++/*
++ * By using the NMI code instead of a vector we just sneak thru the
++ * word generator coming out with just what we want. AND it does
++ * not matter if clustered_apic_mode is set or not.
++ */
++void smp_send_nmi_allbutself(void)
++{
++ send_IPI_allbutself(APIC_DM_NMI);
++}
++#endif
+ /*
+ * this function sends a 'reschedule' IPI to another CPU.
+ * it goes straight through and wastes no time serializing
+Index: linux/arch/i386/kernel/traps.c
+===================================================================
+--- linux.orig/arch/i386/kernel/traps.c
++++ linux/arch/i386/kernel/traps.c
+@@ -103,6 +103,39 @@ int register_die_notifier(struct notifie
+ return err;
+ }
+
++#ifdef CONFIG_KGDB
++extern void sysenter_past_esp(void);
++#include <asm/kgdb.h>
++#include <linux/init.h>
++void set_intr_gate(unsigned int n, void *addr);
++static void set_intr_usr_gate(unsigned int n, void *addr);
++/*
++ * Should be able to call this breakpoint() very early in
++ * bring up. Just hard code the call where needed.
++ * The breakpoint() code is here because set_?_gate() functions
++ * are local (static) to trap.c. They need be done only once,
++ * but it does not hurt to do them over.
++ */
++void breakpoint(void)
++{
++ set_intr_usr_gate(3,&int3); /* disable ints on trap */
++ set_intr_gate(1,&debug);
++ set_intr_gate(14,&page_fault);
+
-+1. Execution breakpoint - An Execution breakpoint is triggered when code
-+ at the breakpoint address is executed.
++ BREAKPOINT();
++}
++#define CHK_REMOTE_DEBUG(trapnr,signr,error_code,regs,after) \
++ { \
++ if (!user_mode(regs) ) \
++ { \
++ kgdb_handle_exception(trapnr, signr, error_code, regs); \
++ after; \
++ } else if ((trapnr == 3) && (regs->eflags &0x200)) local_irq_enable(); \
++ }
++#else
++#define CHK_REMOTE_DEBUG(trapnr,signr,error_code,regs,after)
++#endif
+
-+ 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.
+ static inline int valid_stack_ptr(struct thread_info *tinfo, void *p)
+ {
+ return p > (void *)tinfo &&
+@@ -328,6 +361,15 @@ void die(const char * str, struct pt_reg
+ #endif
+ if (nl)
+ printk("\n");
++#ifdef CONFIG_KGDB
++ /* This is about the only place we want to go to kgdb even if in
++ * user mode. But we must go in via a trap so within kgdb we will
++ * always be in kernel mode.
++ */
++ if (user_mode(regs))
++ BREAKPOINT();
++#endif
++ CHK_REMOTE_DEBUG(0,SIGTRAP,err,regs,)
+ notify_die(DIE_OOPS, (char *)str, regs, err, 255, SIGSEGV);
+ show_registers(regs);
+ try_crashdump(regs);
+@@ -453,6 +495,7 @@ static inline void 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,) \
+ if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \
+ == NOTIFY_STOP) \
+ return; \
+@@ -476,6 +519,7 @@ 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, return) \
+ if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \
+ == NOTIFY_STOP) \
+ return; \
+@@ -605,6 +649,7 @@ gp_in_vm86:
+ gp_in_kernel:
+ if (!fixup_exception(regs)) {
+ die:
++ CHK_REMOTE_DEBUG(13,SIGSEGV,error_code,regs,)
+ if (notify_die(DIE_GPF, "general protection fault", regs,
+ error_code, 13, SIGSEGV) == NOTIFY_STOP)
+ return;
+@@ -829,8 +874,18 @@ asmlinkage void do_debug(struct pt_regs
+ * allowing programs to debug themselves without the ptrace()
+ * interface.
+ */
++#ifdef CONFIG_KGDB
++ /*
++ * I think this is the only "real" case of a TF in the kernel
++ * that really belongs to user space. Others are
++ * "Ours all ours!"
++ */
++ if (((regs->xcs & 3) == 0) && ((void *)regs->eip == sysenter_past_esp))
++ goto clear_TF_reenable;
++#else
+ if ((regs->xcs & 3) == 0)
+ goto clear_TF_reenable;
++#endif
+ if ((tsk->ptrace & (PT_DTRACE|PT_PTRACED)) == PT_DTRACE)
+ goto clear_TF;
+ }
+@@ -842,6 +897,17 @@ asmlinkage void do_debug(struct pt_regs
+ info.si_errno = 0;
+ info.si_code = TRAP_BRKPT;
+
++#ifdef CONFIG_KGDB
++ /*
++ * If this is a kernel mode trap, we need to reset db7 to allow us
++ * to continue sanely ALSO skip the signal delivery
++ */
++ if ((regs->xcs & 3) == 0)
++ goto clear_dr7;
+
-+2. Write breakpoint - A write breakpoint is triggered when memory
-+ location at the breakpoint address is written.
++ /* if not kernel, allow ints but only if they were on */
++ if ( regs->eflags & 0x200) local_irq_enable();
++#endif
+ /* 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.
+ */
+@@ -856,6 +922,7 @@ clear_dr7:
+ __asm__("movl %0,%%db7"
+ : /* no output */
+ : "r" (0));
++ CHK_REMOTE_DEBUG(1,SIGTRAP,error_code,regs,)
+ return;
+
+ debug_vm86:
+@@ -1151,6 +1218,12 @@ static void __init set_task_gate(unsigne
+ {
+ _set_gate(idt_table+n,5,0,0,(gdt_entry<<3));
+ }
++#ifdef CONFIG_KGDB
++void set_intr_usr_gate(unsigned int n, void *addr)
++{
++ _set_gate(idt_table+n,14,3,addr,__KERNEL_CS);
++}
++#endif
+
+
+ void __init trap_init(void)
+@@ -1169,7 +1242,11 @@ void __init trap_init(void)
+ set_trap_gate(0,÷_error);
+ set_intr_gate(1,&debug);
+ set_intr_gate(2,&nmi);
++#ifndef CONFIG_KGDB
+ set_system_intr_gate(3, &int3); /* int3-5 can be called from all */
++#else
++ set_intr_usr_gate(3,&int3); /* int3-5 can be called from all */
++#endif
+ set_system_gate(4,&overflow);
+ set_system_gate(5,&bounds);
+ set_trap_gate(6,&invalid_op);
+Index: linux/arch/i386/lib/Makefile
+===================================================================
+--- linux.orig/arch/i386/lib/Makefile
++++ linux/arch/i386/lib/Makefile
+@@ -8,3 +8,4 @@ lib-y = checksum.o delay.o usercopy.o ge
+
+ lib-$(CONFIG_X86_USE_3DNOW) += mmx.o
+ lib-$(CONFIG_HAVE_DEC_LOCK) += dec_and_lock.o
++lib-$(CONFIG_KGDB) += kgdb_serial.o
+Index: linux/arch/i386/lib/kgdb_serial.c
+===================================================================
+--- linux.orig/arch/i386/lib/kgdb_serial.c
++++ linux/arch/i386/lib/kgdb_serial.c
+@@ -0,0 +1,485 @@
++/*
++ * Serial interface GDB stub
++ *
++ * Written (hacked together) by David Grothe (dave@gcom.com)
++ * Modified to allow invokation early in boot see also
++ * kgdb.h for instructions by George Anzinger(george@mvista.com)
++ *
++ */
+
-+ 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.
++#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/config.h>
++#include <linux/major.h>
++#include <linux/string.h>
++#include <linux/fcntl.h>
++#include <linux/ptrace.h>
++#include <linux/ioport.h>
++#include <linux/mm.h>
++#include <linux/init.h>
++#include <linux/highmem.h>
++#include <asm/system.h>
++#include <asm/io.h>
++#include <asm/segment.h>
++#include <asm/bitops.h>
++#include <asm/system.h>
++#include <asm/kgdb_local.h>
++#ifdef CONFIG_KGDB_USER_CONSOLE
++extern void kgdb_console_finit(void);
++#endif
++#define PRNT_off
++#define TEST_EXISTANCE
++#ifdef PRNT
++#define dbprintk(s) printk s
++#else
++#define dbprintk(s)
++#endif
++#define TEST_INTERRUPT_off
++#ifdef TEST_INTERRUPT
++#define intprintk(s) printk s
++#else
++#define intprintk(s)
++#endif
+
-+3. Access breakpoint - An access breakpoint is triggered when memory
-+ location at the breakpoint address is either read or written.
++#define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT)
+
-+ Access breakpoints also have lengths similar to write breakpoints.
++#define GDB_BUF_SIZE 512 /* power of 2, please */
+
-+IO breakpoints in ia-32 are not supported.
++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;
+
-+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.
++struct async_struct *gdb_async_info;
++static int gdb_async_irq;
+
-+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 occurred.
-+ Prints number of the hardware breakpoint if a hardware breakpoint has
-+ occurred.
++#define outb_px(a,b) outb_p(b,a)
+
-+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
++static void program_uart(struct async_struct *info);
++static void write_char(struct async_struct *info, int chr);
++/*
++ * Get a byte from the hardware data buffer and return it
++ */
++static int
++read_data_bfr(struct async_struct *info)
++{
++ char it = inb_p(info->port + UART_LSR);
+
-+SMP support
-+==========
++ if (it & UART_LSR_DR)
++ return (inb_p(info->port + UART_RX));
++ /*
++ * If we have a framing error assume somebody messed with
++ * our uart. Reprogram it and send '-' both ways...
++ */
++ if (it & 0xc) {
++ program_uart(info);
++ write_char(info, '-');
++ return ('-');
++ }
++ return (-1);
+
-+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 occurred. Threads running on other processor(s) appear
-+similar to other non-running threads in the 'info threads' output.
-+Within the kgdb stub there is a structure "waiting_cpus" in which kgdb
-+records the values of "current" and "regs" for each CPU other than the
-+one that hit the breakpoint. "current" is a pointer to the task
-+structure for the task that CPU is running, while "regs" points to the
-+saved registers for the task. This structure can be examined with the
-+gdb "p" command.
++} /* read_data_bfr */
+
-+ia-32 hardware debugging registers on all processors are set to same
-+values. Hence any hardware breakpoints may occur on any processor.
++/*
++ * Get a char if available, return -1 if nothing available.
++ * Empty the receive buffer first, then look at the interface hardware.
+
-+gdb troubleshooting
-+===================
++ * Locking here is a bit of a problem. We MUST not lock out communication
++ * if we are trying to talk to gdb about a kgdb entry. ON the other hand
++ * we can loose chars in the console pass thru if we don't lock. It is also
++ * possible that we could hold the lock or be waiting for it when kgdb
++ * NEEDS to talk. Since kgdb locks down the world, it does not need locks.
++ * We do, of course have possible issues with interrupting a uart operation,
++ * but we will just depend on the uart status to help keep that straight.
+
-+1. gdb hangs
-+Kill it. restart gdb. Connect to target machine.
++ */
++static spinlock_t uart_interrupt_lock = SPIN_LOCK_UNLOCKED;
++#ifdef CONFIG_SMP
++extern spinlock_t kgdb_spinlock;
++#endif
+
-+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) to the serial line.
-+e.g. echo -e "\003" > /dev/ttyS1
-+This forces that target machine into the debugger, after which you
-+can connect.
++static int
++read_char(struct async_struct *info)
++{
++ int chr;
++ unsigned long flags;
++ local_irq_save(flags);
++#ifdef CONFIG_SMP
++ if (!spin_is_locked(&kgdb_spinlock)) {
++ spin_lock(&uart_interrupt_lock);
++ }
++#endif
++ if (atomic_read(&gdb_buf_in_cnt) != 0) { /* intr routine has q'd chars */
++ chr = gdb_buf[gdb_buf_out_inx++];
++ gdb_buf_out_inx &= (GDB_BUF_SIZE - 1);
++ atomic_dec(&gdb_buf_in_cnt);
++ } else {
++ chr = read_data_bfr(info);
++ }
++#ifdef CONFIG_SMP
++ if (!spin_is_locked(&kgdb_spinlock)) {
++ spin_unlock(&uart_interrupt_lock);
++ }
++#endif
++ local_irq_restore(flags);
++ return (chr);
++}
+
-+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
++/*
++ * Wait until the interface can accept a char, then write it.
++ */
++static void
++write_char(struct async_struct *info, int chr)
++{
++ while (!(inb_p(info->port + UART_LSR) & UART_LSR_THRE)) ;
+
-+Check serial line speed and set it to correct value if required
-+e.g. stty ispeed 115200 ospeed 115200 < /dev/ttyS1
++ outb_p(chr, info->port + UART_TX);
+
-+EVENTS
-+======
++} /* write_char */
+
-+Ever want to know the order of things happening? Which CPU did what and
-+when? How did the spinlock get the way it is? Then events are for
-+you. Events are defined by calls to an event collection interface and
-+saved for later examination. In this case, kgdb events are saved by a
-+very fast bit of code in kgdb which is fully SMP and interrupt protected
-+and they are examined by using gdb to display them. Kgdb keeps only
-+the last N events, where N must be a power of two and is defined at
-+configure time.
++/*
++ * Mostly we don't need a spinlock, but since the console goes
++ * thru here with interrutps on, well, we need to catch those
++ * chars.
++ */
++/*
++ * 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 irqreturn_t
++gdb_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++{
++ struct async_struct *info;
++ unsigned long flags;
+
++ info = gdb_async_info;
++ if (!info || !info->tty || irq != gdb_async_irq)
++ return IRQ_NONE;
+
-+Events are signaled to kgdb by calling:
++ local_irq_save(flags);
++ spin_lock(&uart_interrupt_lock);
++ do {
++ int chr = read_data_bfr(info);
++ intprintk(("Debug char on int: %x hex\n", chr));
++ if (chr < 0)
++ continue;
+
-+kgdb_ts(data0,data1)
++ if (chr == 3) { /* Ctrl-C means remote interrupt */
++ BREAKPOINT();
++ continue;
++ }
+
-+For each call kgdb records each call in an array along with other info.
-+Here is the array definition:
++ if (atomic_read(&gdb_buf_in_cnt) >= GDB_BUF_SIZE) {
++ /* buffer overflow tosses early char */
++ read_char(info);
++ }
++ gdb_buf[gdb_buf_in_inx++] = chr;
++ gdb_buf_in_inx &= (GDB_BUF_SIZE - 1);
++ } while (inb_p(info->port + UART_IIR) & UART_IIR_RDI);
++ spin_unlock(&uart_interrupt_lock);
++ local_irq_restore(flags);
++ return IRQ_HANDLED;
++} /* gdb_interrupt */
+
-+struct kgdb_and_then_struct {
-+#ifdef CONFIG_SMP
-+ int on_cpu;
-+#endif
-+ long long at_time;
-+ int from_ln;
-+ char * in_src;
-+ void *from;
-+ int with_if;
-+ int data0;
-+ int data1;
-+};
++/*
++ * Just a NULL routine for testing.
++ */
++void
++gdb_null(void)
++{
++} /* gdb_null */
+
-+For SMP machines the CPU is recorded, for all machines the TSC is
-+recorded (gets a time stamp) as well as the line number and source file
-+the call was made from. The address of the (from), the "if" (interrupt
-+flag) and the two data items are also recorded. The macro kgdb_ts casts
-+the types to int, so you can put any 32-bit values here. There is a
-+configure option to select the number of events you want to keep. A
-+nice number might be 128, but you can keep up to 1024 if you want. The
-+number must be a power of two. An "andthen" macro library is provided
-+for gdb to help you look at these events. It is also possible to define
-+a different structure for the event storage and cast the data to this
-+structure. For example the following structure is defined in kgdb:
++/* These structure are filled in with values defined in asm/kgdb_local.h
++ */
++static struct serial_state state = SB_STATE;
++static struct async_struct local_info = SB_INFO;
++static int ok_to_enable_ints = 0;
++static void kgdb_enable_ints_now(void);
+
-+struct kgdb_and_then_struct2 {
-+#ifdef CONFIG_SMP
-+ int on_cpu;
++extern char *kgdb_version;
++/*
++ * Hook an IRQ for KGDB.
++ *
++ * This routine is called from putDebugChar, below.
++ */
++static int ints_disabled = 1;
++int
++gdb_hook_interrupt(struct async_struct *info, int verb)
++{
++ struct serial_state *state = info->state;
++ unsigned long flags;
++ int port;
++#ifdef TEST_EXISTANCE
++ int scratch, scratch2;
+#endif
-+ long long at_time;
-+ int from_ln;
-+ char * in_src;
-+ void *from;
-+ int with_if;
-+ struct task_struct *t1;
-+ struct task_struct *t2;
-+};
+
-+If you use this for display, the data elements will be displayed as
-+pointers to task_struct entries. You may want to define your own
-+structure to use in casting. You should only change the last two items
-+and you must keep the structure size the same. Kgdb will handle these
-+as 32-bit ints, but within that constraint you can define a structure to
-+cast to any 32-bit quantity. This need only be available to gdb and is
-+only used for casting in the display code.
++ /* The above fails if memory managment is not set up yet.
++ * Rather than fail the set up, just keep track of the fact
++ * and pick up the interrupt thing later.
++ */
++ gdb_async_info = info;
++ port = gdb_async_info->port;
++ gdb_async_irq = state->irq;
++ if (verb) {
++ printk("kgdb %s : port =%x, IRQ=%d, divisor =%d\n",
++ kgdb_version,
++ port,
++ gdb_async_irq, gdb_async_info->state->custom_divisor);
++ }
++ local_irq_save(flags);
++#ifdef TEST_EXISTANCE
++ /* Existance test */
++ /* Should not need all this, but just in case.... */
++
++ scratch = inb_p(port + UART_IER);
++ outb_px(port + UART_IER, 0);
++ outb_px(0xff, 0x080);
++ scratch2 = inb_p(port + UART_IER);
++ outb_px(port + UART_IER, scratch);
++ if (scratch2) {
++ printk
++ ("gdb_hook_interrupt: Could not clear IER, not a UART!\n");
++ local_irq_restore(flags);
++ return 1; /* We failed; there's nothing here */
++ }
++ scratch2 = inb_p(port + UART_LCR);
++ outb_px(port + UART_LCR, 0xBF); /* set up for StarTech test */
++ outb_px(port + UART_EFR, 0); /* EFR is the same as FCR */
++ outb_px(port + UART_LCR, 0);
++ outb_px(port + UART_FCR, UART_FCR_ENABLE_FIFO);
++ scratch = inb_p(port + UART_IIR) >> 6;
++ if (scratch == 1) {
++ printk("gdb_hook_interrupt: Undefined UART type!"
++ " Not a UART! \n");
++ local_irq_restore(flags);
++ return 1;
++ } else {
++ dbprintk(("gdb_hook_interrupt: UART type "
++ "is %d where 0=16450, 2=16550 3=16550A\n", scratch));
++ }
++ scratch = inb_p(port + UART_MCR);
++ outb_px(port + UART_MCR, UART_MCR_LOOP | scratch);
++ outb_px(port + UART_MCR, UART_MCR_LOOP | 0x0A);
++ scratch2 = inb_p(port + UART_MSR) & 0xF0;
++ outb_px(port + UART_MCR, scratch);
++ if (scratch2 != 0x90) {
++ printk("gdb_hook_interrupt: "
++ "Loop back test failed! Not a UART!\n");
++ local_irq_restore(flags);
++ return scratch2 + 1000; /* force 0 to fail */
++ }
++#endif /* test existance */
++ program_uart(info);
++ local_irq_restore(flags);
+
-+Final Items
-+===========
++ return (0);
+
-+I picked up this code from Amit S. Kale and enhanced it.
++} /* gdb_hook_interrupt */
+
-+If you make some really cool modification to this stuff, or if you
-+fix a bug, please let me know.
++static void
++program_uart(struct async_struct *info)
++{
++ int port = info->port;
+
-+George Anzinger
-+<george@mvista.com>
++ (void) inb_p(port + UART_RX);
++ outb_px(port + UART_IER, 0);
+
-+Amit S. Kale
-+<akale@veritas.com>
++ (void) inb_p(port + UART_RX); /* serial driver comments say */
++ (void) inb_p(port + UART_IIR); /* this clears the interrupt regs */
++ (void) inb_p(port + UART_MSR);
++ outb_px(port + UART_LCR, UART_LCR_WLEN8 | UART_LCR_DLAB);
++ outb_px(port + UART_DLL, info->state->custom_divisor & 0xff); /* LS */
++ outb_px(port + UART_DLM, info->state->custom_divisor >> 8); /* MS */
++ outb_px(port + UART_MCR, info->MCR);
+
-+(First kgdb by David Grothe <dave@gcom.com>)
++ outb_px(port + UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1 | UART_FCR_CLEAR_XMIT | UART_FCR_CLEAR_RCVR); /* set fcr */
++ outb_px(port + UART_LCR, UART_LCR_WLEN8); /* reset DLAB */
++ outb_px(port + UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1); /* set fcr */
++ if (!ints_disabled) {
++ intprintk(("KGDB: Sending %d to port %x offset %d\n",
++ gdb_async_info->IER,
++ (int) gdb_async_info->port, UART_IER));
++ outb_px(gdb_async_info->port + UART_IER, gdb_async_info->IER);
++ }
++ return;
++}
+
-+(modified by Tigran Aivazian <tigran@sco.com>)
-+ Putting gdbstub into the kernel config menu.
++/*
++ * 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. In the
++ */
++int kgdb_in_isr = 0;
++int kgdb_in_lsr = 0;
++extern spinlock_t kgdb_spinlock;
+
-+(modified by Scott Foehner <sfoehner@engr.sgi.com>)
-+ Hooks for entering gdbstub at boot time.
++/* Caller takes needed protections */
+
-+(modified by Amit S. Kale <akale@veritas.com>)
-+ Threads, ia-32 hw debugging, mp support, console support,
-+ nmi watchdog handling.
++int
++getDebugChar(void)
++{
++ volatile int chr, dum, time, end_time;
+
-+(modified by George Anzinger <george@mvista.com>)
-+ Extended threads to include the idle threads.
-+ Enhancements to allow breakpoint() at first C code.
-+ Use of module_init() and __setup() to automate the configure.
-+ Enhanced the cpu "collection" code to work in early bring-up.
-+ Added ability to call functions from gdb
-+ Print info thread stuff without going back to schedule()
-+ Now collect the "other" cpus with an IPI/ NMI.
-diff -puN /dev/null Documentation/i386/kgdb/loadmodule.sh
---- /dev/null 2003-09-15 06:40:47.000000000 -0700
-+++ 25-akpm/Documentation/i386/kgdb/loadmodule.sh 2004-10-21 14:54:15.325593648 -0700
-@@ -0,0 +1,78 @@
-+#/bin/sh
-+# This script loads a module on a target machine and generates a gdb script.
-+# source generated gdb script to load the module file at appropriate addresses
-+# in gdb.
-+#
-+# Usage:
-+# Loading the module on target machine and generating gdb script)
-+# [foo]$ loadmodule.sh <modulename>
-+#
-+# Loading the module file into gdb
-+# (gdb) source <gdbscriptpath>
-+#
-+# Modify following variables according to your setup.
-+# TESTMACHINE - Name of the target machine
-+# GDBSCRIPTS - The directory where a gdb script will be generated
-+#
-+# Author: Amit S. Kale (akale@veritas.com).
-+#
-+# If you run into problems, please check files pointed to by following
-+# variables.
-+# ERRFILE - /tmp/<modulename>.errs contains stderr output of insmod
-+# MAPFILE - /tmp/<modulename>.map contains stdout output of insmod
-+# GDBSCRIPT - $GDBSCRIPTS/load<modulename> gdb script.
++ dbprintk(("getDebugChar(port %x): ", gdb_async_info->port));
+
-+TESTMACHINE=foo
-+GDBSCRIPTS=/home/bar
++ if (gdb_async_info == NULL) {
++ gdb_hook_interrupt(&local_info, 0);
++ }
++ /*
++ * This trick says if we wait a very long time and get
++ * no char, return the -1 and let the upper level deal
++ * with it.
++ */
++ rdtsc(dum, time);
++ end_time = time + 2;
++ while (((chr = read_char(gdb_async_info)) == -1) &&
++ (end_time - time) > 0) {
++ rdtsc(dum, time);
++ };
++ /*
++ * This covers our butts if some other code messes with
++ * our uart, hay, it happens :o)
++ */
++ if (chr == -1)
++ program_uart(gdb_async_info);
+
-+if [ $# -lt 1 ] ; then {
-+ echo Usage: $0 modulefile
-+ exit
-+} ; fi
++ dbprintk(("%c\n", chr > ' ' && chr < 0x7F ? chr : ' '));
++ return (chr);
+
-+MODULEFILE=$1
-+MODULEFILEBASENAME=`basename $1`
++} /* getDebugChar */
+
-+if [ $MODULEFILE = $MODULEFILEBASENAME ] ; then {
-+ MODULEFILE=`pwd`/$MODULEFILE
-+} fi
++static int count = 3;
++static spinlock_t one_at_atime = SPIN_LOCK_UNLOCKED;
+
-+ERRFILE=/tmp/$MODULEFILEBASENAME.errs
-+MAPFILE=/tmp/$MODULEFILEBASENAME.map
-+GDBSCRIPT=$GDBSCRIPTS/load$MODULEFILEBASENAME
++static int __init
++kgdb_enable_ints(void)
++{
++ if (gdb_async_info == NULL) {
++ gdb_hook_interrupt(&local_info, 1);
++ }
++ ok_to_enable_ints = 1;
++ kgdb_enable_ints_now();
++#ifdef CONFIG_KGDB_USER_CONSOLE
++ kgdb_console_finit();
++#endif
++ return 0;
++}
+
-+function findaddr() {
-+ local ADDR=0x$(echo "$SEGMENTS" | \
-+ grep "$1" | sed 's/^[^ ]*[ ]*[^ ]*[ ]*//' | \
-+ sed 's/[ ]*[^ ]*$//')
-+ echo $ADDR
++#ifdef CONFIG_SERIAL_8250
++void shutdown_for_kgdb(struct async_struct *gdb_async_info);
++#endif
++
++#ifdef CONFIG_DISCONTIGMEM
++static inline int kgdb_mem_init_done(void)
++{
++ return highmem_start_page != NULL;
++}
++#else
++static inline int kgdb_mem_init_done(void)
++{
++ return max_mapnr != 0;
+}
++#endif
+
-+function checkerrs() {
-+ if [ "`cat $ERRFILE`" != "" ] ; then {
-+ cat $ERRFILE
-+ exit
-+ } fi
++static void
++kgdb_enable_ints_now(void)
++{
++ if (!spin_trylock(&one_at_atime))
++ return;
++ if (!ints_disabled)
++ goto exit;
++ if (kgdb_mem_init_done() &&
++ ints_disabled) { /* don't try till mem init */
++#ifdef CONFIG_SERIAL_8250
++ /*
++ * The ifdef here allows the system to be configured
++ * without the serial driver.
++ * Don't make it a module, however, it will steal the port
++ */
++ shutdown_for_kgdb(gdb_async_info);
++#endif
++ ints_disabled = request_irq(gdb_async_info->state->irq,
++ gdb_interrupt,
++ IRQ_T(gdb_async_info),
++ "KGDB-stub", NULL);
++ intprintk(("KGDB: request_irq returned %d\n", ints_disabled));
++ }
++ if (!ints_disabled) {
++ intprintk(("KGDB: Sending %d to port %x offset %d\n",
++ gdb_async_info->IER,
++ (int) gdb_async_info->port, UART_IER));
++ outb_px(gdb_async_info->port + UART_IER, gdb_async_info->IER);
++ }
++ exit:
++ spin_unlock(&one_at_atime);
+}
+
-+#load the module
-+echo Copying $MODULEFILE to $TESTMACHINE
-+rcp $MODULEFILE root@${TESTMACHINE}:
++/*
++ * 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. Caller takes needed protections.
++ */
++void
++putDebugChar(int chr)
++{
++ dbprintk(("putDebugChar(port %x): chr=%02x '%c', ints_on=%d\n",
++ gdb_async_info->port,
++ chr,
++ chr > ' ' && chr < 0x7F ? chr : ' ', ints_disabled ? 0 : 1));
+
-+echo Loading module $MODULEFILE
-+rsh -l root $TESTMACHINE /sbin/insmod -m ./`basename $MODULEFILE` \
-+ > $MAPFILE 2> $ERRFILE
-+checkerrs
++ if (gdb_async_info == NULL) {
++ gdb_hook_interrupt(&local_info, 0);
++ }
+
-+SEGMENTS=`head -n 11 $MAPFILE | tail -n 10`
-+TEXTADDR=$(findaddr "\\.text[^.]")
-+LOADSTRING="add-symbol-file $MODULEFILE $TEXTADDR"
-+SEGADDRS=`echo "$SEGMENTS" | awk '//{
-+ if ($1 != ".text" && $1 != ".this" &&
-+ $1 != ".kstrtab" && $1 != ".kmodtab") {
-+ print " -s " $1 " 0x" $3 " "
++ write_char(gdb_async_info, chr); /* this routine will wait */
++ count = (chr == '#') ? 0 : count + 1;
++ if ((count == 2)) { /* try to enable after */
++ if (ints_disabled & ok_to_enable_ints)
++ kgdb_enable_ints_now(); /* try to enable after */
++
++ /* We do this a lot because, well we really want to get these
++ * interrupts. The serial driver will clear these bits when it
++ * initializes the chip. Every thing else it does is ok,
++ * but this.
++ */
++ if (!ints_disabled) {
++ outb_px(gdb_async_info->port + UART_IER,
++ gdb_async_info->IER);
++ }
+ }
-+}'`
-+LOADSTRING="$LOADSTRING $SEGADDRS"
-+echo Generating script $GDBSCRIPT
-+echo $LOADSTRING > $GDBSCRIPT
-diff -puN drivers/char/keyboard.c~kgdb-ga drivers/char/keyboard.c
---- 25/drivers/char/keyboard.c~kgdb-ga 2004-10-21 14:54:15.273601552 -0700
-+++ 25-akpm/drivers/char/keyboard.c 2004-10-21 14:54:15.326593496 -0700
-@@ -1081,6 +1081,9 @@ void kbd_keycode(unsigned int keycode, i
++
++} /* putDebugChar */
++
++module_init(kgdb_enable_ints);
+Index: linux/arch/i386/mm/fault.c
+===================================================================
+--- linux.orig/arch/i386/mm/fault.c
++++ linux/arch/i386/mm/fault.c
+@@ -453,6 +453,12 @@ no_context:
+ * Oops. The kernel tried to access some bad page. We'll have to
+ * terminate things with extreme prejudice.
+ */
++#ifdef CONFIG_KGDB
++ if (!user_mode(regs)){
++ kgdb_handle_exception(14,SIGBUS, error_code, regs);
++ return;
++ }
++#endif
+
+ bust_spinlocks(1);
+
+Index: linux/arch/x86_64/boot/compressed/head.S
+===================================================================
+--- linux.orig/arch/x86_64/boot/compressed/head.S
++++ linux/arch/x86_64/boot/compressed/head.S
+@@ -26,6 +26,7 @@
+ .code32
+ .text
+
++#define IN_BOOTLOADER
+ #include <linux/linkage.h>
+ #include <asm/segment.h>
+
+Index: linux/arch/x86_64/boot/compressed/misc.c
+===================================================================
+--- linux.orig/arch/x86_64/boot/compressed/misc.c
++++ linux/arch/x86_64/boot/compressed/misc.c
+@@ -9,6 +9,7 @@
+ * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
+ */
+
++#define IN_BOOTLOADER
+ #include "miscsetup.h"
+ #include <asm/io.h>
+
+Index: linux/drivers/char/keyboard.c
+===================================================================
+--- linux.orig/drivers/char/keyboard.c
++++ linux/drivers/char/keyboard.c
+@@ -1078,6 +1078,9 @@ void kbd_keycode(unsigned int keycode, i
}
if (sysrq_down && down && !rep) {
handle_sysrq(kbd_sysrq_xlate[keycode], regs, tty);
return;
}
#endif
-diff -puN drivers/char/sysrq.c~kgdb-ga drivers/char/sysrq.c
---- 25/drivers/char/sysrq.c~kgdb-ga 2004-10-21 14:54:15.275601248 -0700
-+++ 25-akpm/drivers/char/sysrq.c 2004-10-21 14:54:15.326593496 -0700
+Index: linux/drivers/char/sysrq.c
+===================================================================
+--- linux.orig/drivers/char/sysrq.c
++++ linux/drivers/char/sysrq.c
@@ -35,6 +35,25 @@
#include <linux/spinlock.h>
extern void reset_vc(unsigned int);
-@@ -238,8 +257,8 @@ static struct sysrq_key_op *sysrq_key_ta
- /* c */ NULL,
+@@ -271,8 +290,8 @@ static struct sysrq_key_op *sysrq_key_ta
+ /* c */ &sysrq_crash_op,
/* d */ NULL,
/* e */ &sysrq_term_op,
-/* f */ NULL,
/* h */ NULL,
/* i */ &sysrq_kill_op,
/* j */ NULL,
-diff -puN drivers/serial/8250.c~kgdb-ga drivers/serial/8250.c
---- 25/drivers/serial/8250.c~kgdb-ga 2004-10-21 14:54:15.276601096 -0700
-+++ 25-akpm/drivers/serial/8250.c 2004-10-21 14:54:15.328593192 -0700
-@@ -983,7 +983,7 @@ receive_chars(struct uart_8250_port *up,
+Index: linux/drivers/serial/8250.c
+===================================================================
+--- linux.orig/drivers/serial/8250.c
++++ linux/drivers/serial/8250.c
+@@ -880,7 +880,7 @@ receive_chars(struct uart_8250_port *up,
if (unlikely(tty->flip.count >= TTY_FLIPBUF_SIZE)) {
tty->flip.work.func((void *)tty);
if (tty->flip.count >= TTY_FLIPBUF_SIZE)
}
ch = serial_inp(up, UART_RX);
*tty->flip.char_buf_ptr = ch;
-@@ -1348,12 +1348,21 @@ static void serial8250_break_ctl(struct
+@@ -1241,12 +1241,21 @@ static void serial8250_break_ctl(struct
spin_unlock_irqrestore(&up->port.lock, flags);
}
up->capabilities = uart_config[up->port.type].flags;
up->mcr = 0;
-@@ -1990,6 +1999,10 @@ serial8250_register_ports(struct uart_dr
+@@ -1877,6 +1886,10 @@ static void __init serial8250_register_p
for (i = 0; i < UART_NR; i++) {
struct uart_8250_port *up = &serial8250_ports[i];
+#endif
up->port.line = i;
up->port.ops = &serial8250_pops;
- up->port.dev = dev;
-@@ -2376,6 +2389,31 @@ void serial8250_unregister_port(int line
+ init_timer(&up->timer);
+@@ -2160,6 +2173,31 @@ void serial8250_resume_port(int line)
+ uart_resume_port(&serial8250_reg, &serial8250_ports[line].port);
}
- EXPORT_SYMBOL(serial8250_unregister_port);
+#ifdef CONFIG_KGDB
+/*
static int __init serial8250_init(void)
{
int ret, i;
-diff -puN drivers/serial/serial_core.c~kgdb-ga drivers/serial/serial_core.c
---- 25/drivers/serial/serial_core.c~kgdb-ga 2004-10-21 14:54:15.278600792 -0700
-+++ 25-akpm/drivers/serial/serial_core.c 2004-10-21 14:54:15.330592888 -0700
-@@ -1976,6 +1976,11 @@ uart_configure_port(struct uart_driver *
+Index: linux/drivers/serial/serial_core.c
+===================================================================
+--- linux.orig/drivers/serial/serial_core.c
++++ linux/drivers/serial/serial_core.c
+@@ -1981,6 +1981,11 @@ uart_configure_port(struct uart_driver *
{
unsigned int flags;
/*
* If there isn't a port here, don't do anything further.
*/
-diff -puN include/asm-i386/bugs.h~kgdb-ga include/asm-i386/bugs.h
---- 25/include/asm-i386/bugs.h~kgdb-ga 2004-10-21 14:54:15.279600640 -0700
-+++ 25-akpm/include/asm-i386/bugs.h 2004-10-21 14:54:15.331592736 -0700
-@@ -1,11 +1,11 @@
- /*
- * include/asm-i386/bugs.h
- *
-- * Copyright (C) 1994 Linus Torvalds
-+ * Copyright (C) 1994 Linus Torvalds
- *
- * Cyrix stuff, June 1998 by:
- * - Rafael R. Reilova (moved everything from head.S),
-- * <rreilova@ececs.uc.edu>
-+ * <rreilova@ececs.uc.edu>
- * - Channing Corn (tests & fixes),
- * - Andrew D. Balsa (code cleanup).
- *
+Index: linux/include/asm-i386/bugs.h
+===================================================================
+--- linux.orig/include/asm-i386/bugs.h
++++ linux/include/asm-i386/bugs.h
@@ -25,7 +25,20 @@
#include <asm/processor.h>
#include <asm/i387.h>
static int __init no_halt(char *s)
{
boot_cpu_data.hlt_works_ok = 0;
-@@ -140,7 +153,7 @@ static void __init check_popad(void)
- : "ecx", "edi" );
- /* If this fails, it means that any user program may lock the CPU hard. Too bad. */
- if (res != 12345678) printk( "Buggy.\n" );
-- else printk( "OK.\n" );
-+ else printk( "OK.\n" );
- #endif
- }
-
-diff -puN /dev/null include/asm-i386/kgdb.h
---- /dev/null 2003-09-15 06:40:47.000000000 -0700
-+++ 25-akpm/include/asm-i386/kgdb.h 2004-10-21 14:54:15.331592736 -0700
+Index: linux/include/asm-i386/kgdb.h
+===================================================================
+--- linux.orig/include/asm-i386/kgdb.h
++++ linux/include/asm-i386/kgdb.h
@@ -0,0 +1,59 @@
+#ifndef __KGDB
+#define __KGDB
+#define INIT_KGDB_INTS kgdb_enable_ints()
+
+#ifndef BREAKPOINT
-+#define BREAKPOINT asm(" int $3")
++#define BREAKPOINT() asm(" int $3")
+#endif
+/*
+ * GDB debug stub (or any debug stub) can point the 'linux_debug_hook'
+#endif
+#else /* CONFIG_KGDB && ! __ASSEMBLY__ ,stubs follow... */
+#ifndef BREAKPOINT
-+#define BREAKPOINT
++#define BREAKPOINT()
+#endif
+#define kgdb_ts(data0,data1)
+#define in_kgdb
+#define INIT_KGDB_INTS
+#endif
+#endif /* __KGDB */
-diff -puN /dev/null include/asm-i386/kgdb_local.h
---- /dev/null 2003-09-15 06:40:47.000000000 -0700
-+++ 25-akpm/include/asm-i386/kgdb_local.h 2004-10-21 14:54:15.332592584 -0700
+Index: linux/include/asm-i386/kgdb_local.h
+===================================================================
+--- linux.orig/include/asm-i386/kgdb_local.h
++++ linux/include/asm-i386/kgdb_local.h
@@ -0,0 +1,102 @@
+#ifndef __KGDB_LOCAL
+#define ___KGDB_LOCAL
+#include <asm/msr.h>
+#include <asm/kgdb.h>
+
-+#define PORT 0x3f8
-+#ifdef CONFIG_KGDB_PORT
-+#undef PORT
-+#define PORT CONFIG_KGDB_PORT
-+#endif
-+#define IRQ 4
-+#ifdef CONFIG_KGDB_IRQ
-+#undef IRQ
-+#define IRQ CONFIG_KGDB_IRQ
-+#endif
-+#define SB_CLOCK 1843200
-+#define SB_BASE (SB_CLOCK/16)
-+#define SB_BAUD9600 SB_BASE/9600
-+#define SB_BAUD192 SB_BASE/19200
-+#define SB_BAUD384 SB_BASE/38400
-+#define SB_BAUD576 SB_BASE/57600
-+#define SB_BAUD1152 SB_BASE/115200
-+#ifdef CONFIG_KGDB_9600BAUD
-+#define SB_BAUD SB_BAUD9600
-+#endif
-+#ifdef CONFIG_KGDB_19200BAUD
-+#define SB_BAUD SB_BAUD192
-+#endif
-+#ifdef CONFIG_KGDB_38400BAUD
-+#define SB_BAUD SB_BAUD384
-+#endif
-+#ifdef CONFIG_KGDB_57600BAUD
-+#define SB_BAUD SB_BAUD576
-+#endif
-+#ifdef CONFIG_KGDB_115200BAUD
-+#define SB_BAUD SB_BAUD1152
-+#endif
-+#ifndef SB_BAUD
-+#define SB_BAUD SB_BAUD1152 /* Start with this if not given */
-+#endif
++#define PORT 0x3f8
++#ifdef CONFIG_KGDB_PORT
++#undef PORT
++#define PORT CONFIG_KGDB_PORT
++#endif
++#define IRQ 4
++#ifdef CONFIG_KGDB_IRQ
++#undef IRQ
++#define IRQ CONFIG_KGDB_IRQ
++#endif
++#define SB_CLOCK 1843200
++#define SB_BASE (SB_CLOCK/16)
++#define SB_BAUD9600 SB_BASE/9600
++#define SB_BAUD192 SB_BASE/19200
++#define SB_BAUD384 SB_BASE/38400
++#define SB_BAUD576 SB_BASE/57600
++#define SB_BAUD1152 SB_BASE/115200
++#ifdef CONFIG_KGDB_9600BAUD
++#define SB_BAUD SB_BAUD9600
++#endif
++#ifdef CONFIG_KGDB_19200BAUD
++#define SB_BAUD SB_BAUD192
++#endif
++#ifdef CONFIG_KGDB_38400BAUD
++#define SB_BAUD SB_BAUD384
++#endif
++#ifdef CONFIG_KGDB_57600BAUD
++#define SB_BAUD SB_BAUD576
++#endif
++#ifdef CONFIG_KGDB_115200BAUD
++#define SB_BAUD SB_BAUD1152
++#endif
++#ifndef SB_BAUD
++#define SB_BAUD SB_BAUD1152 /* Start with this if not given */
++#endif
++
++#ifndef CONFIG_X86_TSC
++#undef rdtsc
++#define rdtsc(a,b) if (a++ > 10000){a = 0; b++;}
++#undef rdtscll
++#define rdtscll(s) s++
++#endif
++
++#ifdef _raw_read_unlock /* must use a name that is "define"ed, not an inline */
++#undef spin_lock
++#undef spin_trylock
++#undef spin_unlock
++#define spin_lock _raw_spin_lock
++#define spin_trylock _raw_spin_trylock
++#define spin_unlock _raw_spin_unlock
++#else
++#endif
++#undef spin_unlock_wait
++#define spin_unlock_wait(x) do { cpu_relax(); barrier();} \
++ while(spin_is_locked(x))
++
++#define SB_IER 1
++#define SB_MCR UART_MCR_OUT2 | UART_MCR_DTR | UART_MCR_RTS
++
++#define FLAGS 0
++#define SB_STATE { \
++ magic: SSTATE_MAGIC, \
++ baud_base: SB_BASE, \
++ port: PORT, \
++ irq: IRQ, \
++ flags: FLAGS, \
++ custom_divisor:SB_BAUD}
++#define SB_INFO { \
++ magic: SERIAL_MAGIC, \
++ port: PORT,0,FLAGS, \
++ state: &state, \
++ tty: (struct tty_struct *)&state, \
++ IER: SB_IER, \
++ MCR: SB_MCR}
++extern void putDebugChar(int);
++/* RTAI support needs us to really stop/start interrupts */
++
++#define kgdb_sti() __asm__ __volatile__("sti": : :"memory")
++#define kgdb_cli() __asm__ __volatile__("cli": : :"memory")
++#define kgdb_local_save_flags(x) __asm__ __volatile__(\
++ "pushfl ; popl %0":"=g" (x): /* no input */)
++#define kgdb_local_irq_restore(x) __asm__ __volatile__(\
++ "pushl %0 ; popfl": \
++ /* no output */ :"g" (x):"memory", "cc")
++#define kgdb_local_irq_save(x) kgdb_local_save_flags(x); kgdb_cli()
++
++#ifdef CONFIG_SERIAL
++extern void shutdown_for_kgdb(struct async_struct *info);
++#endif
++#define INIT_KDEBUG putDebugChar("+");
++#endif /* __KGDB_LOCAL */
+Index: linux/include/asm-x86_64/kgdb.h
+===================================================================
+--- linux.orig/include/asm-x86_64/kgdb.h
++++ linux/include/asm-x86_64/kgdb.h
+@@ -0,0 +1,23 @@
++#ifndef __KGDB
++#define __KGDB
++
++/*
++ * This file should not include ANY others. This makes it usable
++ * most anywhere without the fear of include order or inclusion.
++ * Make it so!
++ *
++ * This file may be included all the time. It is only active if
++ * CONFIG_KGDB is defined, otherwise it stubs out all the macros
++ * and entry points.
++ */
++#ifndef BREAKPOINT
++#define BREAKPOINT()
++#endif
++
++#define kgdb_ts(data0,data1)
++#define in_kgdb
++#define kgdb_handle_exception
++#define breakpoint
++#define INIT_KGDB_INTS
++
++#endif /* __KGDB */
+Index: linux/include/linux/config.h
+===================================================================
+--- linux.orig/include/linux/config.h
++++ linux/include/linux/config.h
+@@ -2,6 +2,9 @@
+ #define _LINUX_CONFIG_H
+
+ #include <linux/autoconf.h>
++#if defined(__i386__) && !defined(IN_BOOTLOADER)
++#include <asm/kgdb.h>
++#endif
+ #if !defined (__KERNEL__) && !defined(__KERNGLUE__)
+ #error including kernel header in userspace; use the glibc headers instead!
+ #endif
+Index: linux/include/linux/dwarf2-lang.h
+===================================================================
+--- linux.orig/include/linux/dwarf2-lang.h
++++ linux/include/linux/dwarf2-lang.h
+@@ -0,0 +1,132 @@
++#ifndef DWARF2_LANG
++#define DWARF2_LANG
++#include <linux/dwarf2.h>
++
++/*
++ * This 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 file defines macros that allow generation of DWARF debug records
++ * for asm files. This file is platform independent. Register numbers
++ * (which are about the only thing that is platform dependent) are to be
++ * supplied by a platform defined file.
++ */
++#define DWARF_preamble() .section .debug_frame,"",@progbits
++/*
++ * This macro starts a debug frame section. The debug_frame describes
++ * where to find the registers that the enclosing function saved on
++ * entry.
++ *
++ * ORD is use by the label generator and should be the same as what is
++ * passed to CFI_postamble.
++ *
++ * pc, pc register gdb ordinal.
++ *
++ * code_align this is the factor used to define locations or regions
++ * where the given definitions apply. If you use labels to define these
++ * this should be 1.
++ *
++ * data_align this is the factor used to define register offsets. If
++ * you use struct offset, this should be the size of the register in
++ * bytes or the negative of that. This is how it is used: you will
++ * define a register as the reference register, say the stack pointer,
++ * then you will say where a register is located relative to this
++ * reference registers value, say 40 for register 3 (the gdb register
++ * number). The <40> will be multiplied by <data_align> to define the
++ * byte offset of the given register (3, in this example). So if your
++ * <40> is the byte offset and the reference register points at the
++ * begining, you would want 1 for the data_offset. If <40> was the 40th
++ * 4-byte element in that structure you would want 4. And if your
++ * reference register points at the end of the structure you would want
++ * a negative data_align value(and you would have to do other math as
++ * well).
++ */
++
++#define CFI_preamble(ORD, pc, code_align, data_align) \
++.section .debug_frame,"",@progbits ; \
++frame/**/_/**/ORD: \
++ .long end/**/_/**/ORD-start/**/_/**/ORD; \
++start/**/_/**/ORD: \
++ .long DW_CIE_ID; \
++ .byte DW_CIE_VERSION; \
++ .byte 0 ; \
++ .uleb128 code_align; \
++ .sleb128 data_align; \
++ .byte pc;
++
++/*
++ * After the above macro and prior to the CFI_postamble, you need to
++ * define the initial state. This starts with defining the reference
++ * register and, usually the pc. Here are some helper macros:
++ */
++
++#define CFA_define_reference(reg, offset) \
++ .byte DW_CFA_def_cfa; \
++ .uleb128 reg; \
++ .uleb128 (offset);
++
++#define CFA_define_offset(reg, offset) \
++ .byte (DW_CFA_offset + reg); \
++ .uleb128 (offset);
++
++#define CFI_postamble(ORD) \
++ .align 4; \
++end/**/_/**/ORD:
++/*
++ * So now your code pushs stuff on the stack, you need a new location
++ * and the rules for what to do. This starts a running description of
++ * the call frame. You need to describe what changes with respect to
++ * the call registers as the location of the pc moves through the code.
++ * The following builds an FDE (fram descriptor entry?). Like the
++ * above, it has a preamble and a postamble. It also is tied to the CFI
++ * above.
++ * The first entry after the preamble must be the location in the code
++ * that the call frame is being described for.
++ */
++#define FDE_preamble(ORD, fde_no, initial_address, length) \
++ .long FDE_end/**/_/**/fde_no-FDE_start/**/_/**/fde_no; \
++FDE_start/**/_/**/fde_no: \
++ .long frame/**/_/**/ORD; \
++ .long initial_address; \
++ .long length;
++
++#define FDE_postamble(fde_no) \
++ .align 4; \
++FDE_end/**/_/**/fde_no:
++/*
++ * That done, you can now add registers, subtract registers, move the
++ * reference and even change the reference. You can also define a new
++ * area of code the info applies to. For discontinuous bits you should
++ * start a new FDE. You may have as many as you like.
++ */
++
++/*
++ * To advance the address by <bytes>
++ */
+
-+#ifndef CONFIG_X86_TSC
-+#undef rdtsc
-+#define rdtsc(a,b) if (a++ > 10000){a = 0; b++;}
-+#undef rdtscll
-+#define rdtscll(s) s++
-+#endif
++#define FDE_advance(bytes) \
++ .byte DW_CFA_advance_loc4 \
++ .long bytes
+
-+#ifdef _raw_read_unlock /* must use a name that is "define"ed, not an inline */
-+#undef spin_lock
-+#undef spin_trylock
-+#undef spin_unlock
-+#define spin_lock _raw_spin_lock
-+#define spin_trylock _raw_spin_trylock
-+#define spin_unlock _raw_spin_unlock
-+#else
-+#endif
-+#undef spin_unlock_wait
-+#define spin_unlock_wait(x) do { cpu_relax(); barrier();} \
-+ while(spin_is_locked(x))
+
-+#define SB_IER 1
-+#define SB_MCR UART_MCR_OUT2 | UART_MCR_DTR | UART_MCR_RTS
+
-+#define FLAGS 0
-+#define SB_STATE { \
-+ magic: SSTATE_MAGIC, \
-+ baud_base: SB_BASE, \
-+ port: PORT, \
-+ irq: IRQ, \
-+ flags: FLAGS, \
-+ custom_divisor:SB_BAUD}
-+#define SB_INFO { \
-+ magic: SERIAL_MAGIC, \
-+ port: PORT,0,FLAGS, \
-+ state: &state, \
-+ tty: (struct tty_struct *)&state, \
-+ IER: SB_IER, \
-+ MCR: SB_MCR}
-+extern void putDebugChar(int);
-+/* RTAI support needs us to really stop/start interrupts */
++/*
++ * With the above you can define all the register locations. But
++ * suppose the reference register moves... Takes the new offset NOT an
++ * increment. This is how esp is tracked if it is not saved.
++ */
+
-+#define kgdb_sti() __asm__ __volatile__("sti": : :"memory")
-+#define kgdb_cli() __asm__ __volatile__("cli": : :"memory")
-+#define kgdb_local_save_flags(x) __asm__ __volatile__(\
-+ "pushfl ; popl %0":"=g" (x): /* no input */)
-+#define kgdb_local_irq_restore(x) __asm__ __volatile__(\
-+ "pushl %0 ; popfl": \
-+ /* no output */ :"g" (x):"memory", "cc")
-+#define kgdb_local_irq_save(x) kgdb_local_save_flags(x); kgdb_cli()
++#define CFA_define_cfa_offset(offset) \
++ .byte $DW_CFA_def_cfa_offset; \
++ .uleb128 (offset);
++/*
++ * Or suppose you want to use a different reference register...
++ */
++#define CFA_define_cfa_register(reg) \
++ .byte DW_CFA_def_cfa_register; \
++ .uleb128 reg;
+
-+#ifdef CONFIG_SERIAL
-+extern void shutdown_for_kgdb(struct async_struct *info);
-+#endif
-+#define INIT_KDEBUG putDebugChar("+");
-+#endif /* __KGDB_LOCAL */
-diff -puN include/linux/config.h~kgdb-ga include/linux/config.h
---- 25/include/linux/config.h~kgdb-ga 2004-10-21 14:54:15.281600336 -0700
-+++ 25-akpm/include/linux/config.h 2004-10-21 14:54:15.332592584 -0700
-@@ -2,6 +2,9 @@
- #define _LINUX_CONFIG_H
-
- #include <linux/autoconf.h>
-+#if defined(__i386__) && !defined(IN_BOOTLOADER)
-+#include <asm/kgdb.h>
+#endif
- #if !defined (__KERNEL__) && !defined(__KERNGLUE__)
- #error including kernel header in userspace; use the glibc headers instead!
- #endif
-diff -puN /dev/null include/linux/dwarf2.h
---- /dev/null 2003-09-15 06:40:47.000000000 -0700
-+++ 25-akpm/include/linux/dwarf2.h 2004-10-21 14:54:15.336591976 -0700
+Index: linux/include/linux/dwarf2.h
+===================================================================
+--- linux.orig/include/linux/dwarf2.h
++++ linux/include/linux/dwarf2.h
@@ -0,0 +1,738 @@
+/* Declarations and definitions of codes relating to the DWARF2 symbolic
+ debugging information format.
+ DW_LANG_Mips_Assembler = 0x8001 COMMA
+ /* UPC. */
+ DW_LANG_Upc = 0x8765
-+IF_NOT_ASM(};)
-+
-+#define DW_LANG_lo_user 0x8000 /* Implementation-defined range start. */
-+#define DW_LANG_hi_user 0xffff /* Implementation-defined range start. */
-+
-+/* Names and codes for macro information. */
-+ENUM(dwarf_macinfo_record_type)
-+
-+ DW_MACINFO_define = 1 COMMA
-+ DW_MACINFO_undef = 2 COMMA
-+ DW_MACINFO_start_file = 3 COMMA
-+ DW_MACINFO_end_file = 4 COMMA
-+ DW_MACINFO_vendor_ext = 255
-+IF_NOT_ASM(};)
-+\f
-+/* @@@ For use with GNU frame unwind information. */
-+
-+#define DW_EH_PE_absptr 0x00
-+#define DW_EH_PE_omit 0xff
-+
-+#define DW_EH_PE_uleb128 0x01
-+#define DW_EH_PE_udata2 0x02
-+#define DW_EH_PE_udata4 0x03
-+#define DW_EH_PE_udata8 0x04
-+#define DW_EH_PE_sleb128 0x09
-+#define DW_EH_PE_sdata2 0x0A
-+#define DW_EH_PE_sdata4 0x0B
-+#define DW_EH_PE_sdata8 0x0C
-+#define DW_EH_PE_signed 0x08
-+
-+#define DW_EH_PE_pcrel 0x10
-+#define DW_EH_PE_textrel 0x20
-+#define DW_EH_PE_datarel 0x30
-+#define DW_EH_PE_funcrel 0x40
-+#define DW_EH_PE_aligned 0x50
-+
-+#define DW_EH_PE_indirect 0x80
-+
-+#endif /* _ELF_DWARF2_H */
-diff -puN /dev/null include/linux/dwarf2-lang.h
---- /dev/null 2003-09-15 06:40:47.000000000 -0700
-+++ 25-akpm/include/linux/dwarf2-lang.h 2004-10-21 14:54:15.337591824 -0700
-@@ -0,0 +1,132 @@
-+#ifndef DWARF2_LANG
-+#define DWARF2_LANG
-+#include <linux/dwarf2.h>
-+
-+/*
-+ * This 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 file defines macros that allow generation of DWARF debug records
-+ * for asm files. This file is platform independent. Register numbers
-+ * (which are about the only thing that is platform dependent) are to be
-+ * supplied by a platform defined file.
-+ */
-+#define DWARF_preamble() .section .debug_frame,"",@progbits
-+/*
-+ * This macro starts a debug frame section. The debug_frame describes
-+ * where to find the registers that the enclosing function saved on
-+ * entry.
-+ *
-+ * ORD is use by the label generator and should be the same as what is
-+ * passed to CFI_postamble.
-+ *
-+ * pc, pc register gdb ordinal.
-+ *
-+ * code_align this is the factor used to define locations or regions
-+ * where the given definitions apply. If you use labels to define these
-+ * this should be 1.
-+ *
-+ * data_align this is the factor used to define register offsets. If
-+ * you use struct offset, this should be the size of the register in
-+ * bytes or the negative of that. This is how it is used: you will
-+ * define a register as the reference register, say the stack pointer,
-+ * then you will say where a register is located relative to this
-+ * reference registers value, say 40 for register 3 (the gdb register
-+ * number). The <40> will be multiplied by <data_align> to define the
-+ * byte offset of the given register (3, in this example). So if your
-+ * <40> is the byte offset and the reference register points at the
-+ * begining, you would want 1 for the data_offset. If <40> was the 40th
-+ * 4-byte element in that structure you would want 4. And if your
-+ * reference register points at the end of the structure you would want
-+ * a negative data_align value(and you would have to do other math as
-+ * well).
-+ */
-+
-+#define CFI_preamble(ORD, pc, code_align, data_align) \
-+.section .debug_frame,"",@progbits ; \
-+frame/**/_/**/ORD: \
-+ .long end/**/_/**/ORD-start/**/_/**/ORD; \
-+start/**/_/**/ORD: \
-+ .long DW_CIE_ID; \
-+ .byte DW_CIE_VERSION; \
-+ .byte 0 ; \
-+ .uleb128 code_align; \
-+ .sleb128 data_align; \
-+ .byte pc;
-+
-+/*
-+ * After the above macro and prior to the CFI_postamble, you need to
-+ * define the initial state. This starts with defining the reference
-+ * register and, usually the pc. Here are some helper macros:
-+ */
-+
-+#define CFA_define_reference(reg, offset) \
-+ .byte DW_CFA_def_cfa; \
-+ .uleb128 reg; \
-+ .uleb128 (offset);
-+
-+#define CFA_define_offset(reg, offset) \
-+ .byte (DW_CFA_offset + reg); \
-+ .uleb128 (offset);
-+
-+#define CFI_postamble(ORD) \
-+ .align 4; \
-+end/**/_/**/ORD:
-+/*
-+ * So now your code pushs stuff on the stack, you need a new location
-+ * and the rules for what to do. This starts a running description of
-+ * the call frame. You need to describe what changes with respect to
-+ * the call registers as the location of the pc moves through the code.
-+ * The following builds an FDE (fram descriptor entry?). Like the
-+ * above, it has a preamble and a postamble. It also is tied to the CFI
-+ * above.
-+ * The first entry after the preamble must be the location in the code
-+ * that the call frame is being described for.
-+ */
-+#define FDE_preamble(ORD, fde_no, initial_address, length) \
-+ .long FDE_end/**/_/**/fde_no-FDE_start/**/_/**/fde_no; \
-+FDE_start/**/_/**/fde_no: \
-+ .long frame/**/_/**/ORD; \
-+ .long initial_address; \
-+ .long length;
++IF_NOT_ASM(};)
+
-+#define FDE_postamble(fde_no) \
-+ .align 4; \
-+FDE_end/**/_/**/fde_no:
-+/*
-+ * That done, you can now add registers, subtract registers, move the
-+ * reference and even change the reference. You can also define a new
-+ * area of code the info applies to. For discontinuous bits you should
-+ * start a new FDE. You may have as many as you like.
-+ */
++#define DW_LANG_lo_user 0x8000 /* Implementation-defined range start. */
++#define DW_LANG_hi_user 0xffff /* Implementation-defined range start. */
+
-+/*
-+ * To advance the address by <bytes>
-+ */
++/* Names and codes for macro information. */
++ENUM(dwarf_macinfo_record_type)
+
-+#define FDE_advance(bytes) \
-+ .byte DW_CFA_advance_loc4 \
-+ .long bytes
++ DW_MACINFO_define = 1 COMMA
++ DW_MACINFO_undef = 2 COMMA
++ DW_MACINFO_start_file = 3 COMMA
++ DW_MACINFO_end_file = 4 COMMA
++ DW_MACINFO_vendor_ext = 255
++IF_NOT_ASM(};)
++\f
++/* @@@ For use with GNU frame unwind information. */
+
++#define DW_EH_PE_absptr 0x00
++#define DW_EH_PE_omit 0xff
+
++#define DW_EH_PE_uleb128 0x01
++#define DW_EH_PE_udata2 0x02
++#define DW_EH_PE_udata4 0x03
++#define DW_EH_PE_udata8 0x04
++#define DW_EH_PE_sleb128 0x09
++#define DW_EH_PE_sdata2 0x0A
++#define DW_EH_PE_sdata4 0x0B
++#define DW_EH_PE_sdata8 0x0C
++#define DW_EH_PE_signed 0x08
+
-+/*
-+ * With the above you can define all the register locations. But
-+ * suppose the reference register moves... Takes the new offset NOT an
-+ * increment. This is how esp is tracked if it is not saved.
-+ */
++#define DW_EH_PE_pcrel 0x10
++#define DW_EH_PE_textrel 0x20
++#define DW_EH_PE_datarel 0x30
++#define DW_EH_PE_funcrel 0x40
++#define DW_EH_PE_aligned 0x50
+
-+#define CFA_define_cfa_offset(offset) \
-+ .byte $DW_CFA_def_cfa_offset; \
-+ .uleb128 (offset);
-+/*
-+ * Or suppose you want to use a different reference register...
-+ */
-+#define CFA_define_cfa_register(reg) \
-+ .byte DW_CFA_def_cfa_register; \
-+ .uleb128 reg;
++#define DW_EH_PE_indirect 0x80
+
-+#endif
-diff -puN include/linux/serial_core.h~kgdb-ga include/linux/serial_core.h
---- 25/include/linux/serial_core.h~kgdb-ga 2004-10-21 14:54:15.282600184 -0700
-+++ 25-akpm/include/linux/serial_core.h 2004-10-21 14:54:15.338591672 -0700
-@@ -172,7 +172,9 @@ struct uart_port {
++#endif /* _ELF_DWARF2_H */
+Index: linux/include/linux/serial_core.h
+===================================================================
+--- linux.orig/include/linux/serial_core.h
++++ linux/include/linux/serial_core.h
+@@ -174,7 +174,9 @@ struct uart_port {
unsigned char x_char; /* xon/xoff char */
unsigned char regshift; /* reg offset shift */
unsigned char iotype; /* io access style */
#define UPIO_PORT (0)
#define UPIO_HUB6 (1)
#define UPIO_MEM (2)
-diff -puN include/linux/spinlock.h~kgdb-ga include/linux/spinlock.h
---- 25/include/linux/spinlock.h~kgdb-ga 2004-10-21 14:54:15.284599880 -0700
-+++ 25-akpm/include/linux/spinlock.h 2004-10-21 14:54:15.338591672 -0700
+Index: linux/include/linux/spinlock.h
+===================================================================
+--- linux.orig/include/linux/spinlock.h
++++ linux/include/linux/spinlock.h
@@ -15,6 +15,12 @@
#include <asm/processor.h> /* for cpu relax */
1; \
})
-diff -puN kernel/pid.c~kgdb-ga kernel/pid.c
---- 25/kernel/pid.c~kgdb-ga 2004-10-21 14:54:15.285599728 -0700
-+++ 25-akpm/kernel/pid.c 2004-10-21 14:54:15.339591520 -0700
-@@ -252,6 +252,9 @@ void switch_exec_pids(task_t *leader, ta
+Index: linux/kernel/pid.c
+===================================================================
+--- linux.orig/kernel/pid.c
++++ linux/kernel/pid.c
+@@ -276,6 +276,9 @@ int pid_alive(struct task_struct *p)
* machine. From a minimum of 16 slots up to 4096 slots at one gigabyte or
* more.
*/
void __init pidhash_init(void)
{
int i, j, pidhash_size;
-@@ -273,6 +276,9 @@ void __init pidhash_init(void)
+@@ -297,6 +300,9 @@ void __init pidhash_init(void)
for (j = 0; j < pidhash_size; j++)
INIT_HLIST_HEAD(&pid_hash[i][j]);
}
}
void __init pidmap_init(void)
-diff -puN kernel/sched.c~kgdb-ga kernel/sched.c
---- 25/kernel/sched.c~kgdb-ga 2004-10-21 14:54:15.287599424 -0700
-+++ 25-akpm/kernel/sched.c 2004-10-21 14:54:15.342591064 -0700
-@@ -2931,6 +2931,13 @@ out_unlock:
+Index: linux/kernel/sched.c
+===================================================================
+--- linux.orig/kernel/sched.c
++++ linux/kernel/sched.c
+@@ -3190,6 +3190,13 @@ out_unlock:
EXPORT_SYMBOL(set_user_nice);
#ifdef __ARCH_WANT_SYS_NICE
/*
-diff -puN MAINTAINERS~kgdb-ga MAINTAINERS
---- 25/MAINTAINERS~kgdb-ga 2004-10-21 14:54:15.288599272 -0700
-+++ 25-akpm/MAINTAINERS 2004-10-21 14:54:15.344590760 -0700
-@@ -1242,6 +1242,12 @@ W: http://sf.net/projects/kernel-janitor
- W: http://developer.osdl.org/rddunlap/kj-patches/
- S: Maintained
-
-+KGDB FOR I386 PLATFORM
-+P: George Anzinger
-+M: george@mvista.com
-+L: linux-net@vger.kernel.org
-+S: Supported
-+
- KERNEL NFSD
- P: Neil Brown
- M: neilb@cse.unsw.edu.au
-diff -puN arch/i386/Kconfig.debug~kgdb-ga arch/i386/Kconfig.debug
---- 25/arch/i386/Kconfig.debug~kgdb-ga 2004-10-21 14:54:15.290598968 -0700
-+++ 25-akpm/arch/i386/Kconfig.debug 2004-10-21 14:54:15.344590760 -0700
-@@ -65,4 +65,6 @@ config X86_MPPARSE
- depends on X86_LOCAL_APIC && !X86_VISWS
- default y
-
-+source "arch/i386/Kconfig.kgdb"
-+
- endmenu
-diff -puN /dev/null arch/i386/Kconfig.kgdb
---- /dev/null 2003-09-15 06:40:47.000000000 -0700
-+++ 25-akpm/arch/i386/Kconfig.kgdb 2004-10-21 14:54:15.345590608 -0700
-@@ -0,0 +1,175 @@
-+config KGDB
-+ bool "Include kgdb kernel debugger"
-+ depends on DEBUG_KERNEL
-+ help
-+ If you say Y here, the system will be compiled with the debug
-+ option (-g) and a debugging stub will be included in the
-+ kernel. This stub communicates with gdb on another (host)
-+ computer via a serial port. The host computer should have
-+ access to the kernel binary file (vmlinux) and a serial port
-+ that is connected to the target machine. Gdb can be made to
-+ configure the serial port or you can use stty and setserial to
-+ do this. See the 'target' command in gdb. This option also
-+ configures in the ability to request a breakpoint early in the
-+ boot process. To request the breakpoint just include 'kgdb'
-+ as a boot option when booting the target machine. The system
-+ will then break as soon as it looks at the boot options. This
-+ option also installs a breakpoint in panic and sends any
-+ kernel faults to the debugger. For more information see the
-+ Documentation/i386/kgdb/kgdb.txt file.
-+
-+choice
-+ depends on KGDB
-+ prompt "Debug serial port BAUD"
-+ default KGDB_115200BAUD
-+ help
-+ Gdb and the kernel stub need to agree on the baud rate to be
-+ used. Some systems (x86 family at this writing) allow this to
-+ be configured.
-+
-+config KGDB_9600BAUD
-+ bool "9600"
-+
-+config KGDB_19200BAUD
-+ bool "19200"
-+
-+config KGDB_38400BAUD
-+ bool "38400"
-+
-+config KGDB_57600BAUD
-+ bool "57600"
-+
-+config KGDB_115200BAUD
-+ bool "115200"
-+endchoice
-+
-+config KGDB_PORT
-+ hex "hex I/O port address of the debug serial port"
-+ depends on KGDB
-+ default 3f8
-+ help
-+ Some systems (x86 family at this writing) allow the port
-+ address to be configured. The number entered is assumed to be
-+ hex, don't put 0x in front of it. The standard address are:
-+ COM1 3f8 , irq 4 and COM2 2f8 irq 3. Setserial /dev/ttySx
-+ will tell you what you have. It is good to test the serial
-+ connection with a live system before trying to debug.
-+
-+config KGDB_IRQ
-+ int "IRQ of the debug serial port"
-+ depends on KGDB
-+ default 4
-+ help
-+ This is the irq for the debug port. If everything is working
-+ correctly and the kernel has interrupts on a control C to the
-+ port should cause a break into the kernel debug stub.
-+
-+config DEBUG_INFO
-+ bool
-+ depends on KGDB
-+ default y
-+
-+config KGDB_MORE
-+ bool "Add any additional compile options"
-+ depends on KGDB
-+ default n
-+ help
-+ Saying yes here turns on the ability to enter additional
-+ compile options.
-+
-+
-+config KGDB_OPTIONS
-+ depends on KGDB_MORE
-+ string "Additional compile arguments"
-+ default "-O1"
-+ help
-+ This option allows you enter additional compile options for
-+ the whole kernel compile. Each platform will have a default
-+ that seems right for it. For example on PPC "-ggdb -O1", and
-+ for i386 "-O1". Note that by configuring KGDB "-g" is already
-+ turned on. In addition, on i386 platforms
-+ "-fomit-frame-pointer" is deleted from the standard compile
-+ options.
-+
-+config NO_KGDB_CPUS
-+ int "Number of CPUs"
-+ depends on KGDB && SMP
-+ default NR_CPUS
-+ help
-+
-+ This option sets the number of cpus for kgdb ONLY. It is used
-+ to prune some internal structures so they look "nice" when
-+ displayed with gdb. This is to overcome possibly larger
-+ numbers that may have been entered above. Enter the real
-+ number to get nice clean kgdb_info displays.
-+
-+config KGDB_TS
-+ bool "Enable kgdb time stamp macros?"
-+ depends on KGDB
-+ default n
-+ help
-+ Kgdb event macros allow you to instrument your code with calls
-+ to the kgdb event recording function. The event log may be
-+ examined with gdb at a break point. Turning on this
-+ capability also allows you to choose how many events to
-+ keep. Kgdb always keeps the lastest events.
-+
-+choice
-+ depends on KGDB_TS
-+ prompt "Max number of time stamps to save?"
-+ default KGDB_TS_128
-+
-+config KGDB_TS_64
-+ bool "64"
-+
-+config KGDB_TS_128
-+ bool "128"
-+
-+config KGDB_TS_256
-+ bool "256"
-+
-+config KGDB_TS_512
-+ bool "512"
-+
-+config KGDB_TS_1024
-+ bool "1024"
-+
-+endchoice
-+
-+config STACK_OVERFLOW_TEST
-+ bool "Turn on kernel stack overflow testing?"
-+ depends on KGDB
-+ default n
-+ help
-+ This option enables code in the front line interrupt handlers
-+ to check for kernel stack overflow on interrupts and system
-+ calls. This is part of the kgdb code on x86 systems.
-+
-+config KGDB_CONSOLE
-+ bool "Enable serial console thru kgdb port"
-+ depends on KGDB
-+ default n
-+ help
-+ This option enables the command line "console=kgdb" option.
-+ When the system is booted with this option in the command line
-+ all kernel printk output is sent to gdb (as well as to other
-+ consoles). For this to work gdb must be connected. For this
-+ reason, this command line option will generate a breakpoint if
-+ gdb has not yet connected. After the gdb continue command is
-+ given all pent up console output will be printed by gdb on the
-+ host machine. Neither this option, nor KGDB require the
-+ serial driver to be configured.
-+
-+config KGDB_SYSRQ
-+ bool "Turn on SysRq 'G' command to do a break?"
-+ depends on KGDB
-+ default y
-+ help
-+ This option includes an option in the SysRq code that allows
-+ you to enter SysRq G which generates a breakpoint to the KGDB
-+ stub. This will work if the keyboard is alive and can
-+ interrupt the system. Because of constraints on when the
-+ serial port interrupt can be enabled, this code may allow you
-+ to interrupt the system before the serial port control C is
-+ available. Just say yes here.
-+
-_