* Re: kgdb for mainline kernel: core-lite [patch 1/3] [not found] ` <1xuS8-83Q-11@gated-at.bofh.it> @ 2004-03-08 16:57 ` Andi Kleen 2004-03-08 17:18 ` Tom Rini 2004-03-09 4:36 ` Amit S. Kale 0 siblings, 2 replies; 35+ messages in thread From: Andi Kleen @ 2004-03-08 16:57 UTC (permalink / raw) To: Tom Rini; +Cc: Andrew Morton, linux-kernel, george, pavel, Amit S. Kale Tom Rini <trini@kernel.crashing.org> writes: > > Here's where what Andi said about being able to get the pt_regs stuff > off the stack (I think that's what he said at least) started to confuse > me slightly. But if I understand it right (and I never got around to > testing this) we can replace the do_schedule() stuffs at least with > something like kgdb_get_pt_regs(), since (and I lost my notes on this, > so it's probably not quite right) (thread_info->esp0)-1 No, that's the user space registers. You don't need these registers really as long as you have the correct dwarf2 CFI description of all the code involved. gdb is then able to reconstruct them using the C stack by itself. All it needs for that is esp and eip. -Andi ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: kgdb for mainline kernel: core-lite [patch 1/3] 2004-03-08 16:57 ` kgdb for mainline kernel: core-lite [patch 1/3] Andi Kleen @ 2004-03-08 17:18 ` Tom Rini 2004-03-09 4:29 ` Amit S. Kale 2004-03-09 4:36 ` Amit S. Kale 1 sibling, 1 reply; 35+ messages in thread From: Tom Rini @ 2004-03-08 17:18 UTC (permalink / raw) To: Andi Kleen; +Cc: Andrew Morton, linux-kernel, george, pavel, Amit S. Kale On Mon, Mar 08, 2004 at 05:57:26PM +0100, Andi Kleen wrote: > Tom Rini <trini@kernel.crashing.org> writes: > > > > Here's where what Andi said about being able to get the pt_regs stuff > > off the stack (I think that's what he said at least) started to confuse > > me slightly. But if I understand it right (and I never got around to > > testing this) we can replace the do_schedule() stuffs at least with > > something like kgdb_get_pt_regs(), since (and I lost my notes on this, > > so it's probably not quite right) (thread_info->esp0)-1 > > No, that's the user space registers. > > You don't need these registers really as long as you have the > correct dwarf2 CFI description of all the code involved. gdb > is then able to reconstruct them using the C stack by itself. > > All it needs for that is esp and eip. Ah, OK. Amit, how about for the expanded T-packet thing, we do what you suggested, except call it kgdb_arch_extra_regs() and let the arch fill out whatever regs it needs to. ESP/EIP for x86_64/i386, PC/SP for ppc32, etc, etc? -- Tom Rini http://gate.crashing.org/~trini/ ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: kgdb for mainline kernel: core-lite [patch 1/3] 2004-03-08 17:18 ` Tom Rini @ 2004-03-09 4:29 ` Amit S. Kale 0 siblings, 0 replies; 35+ messages in thread From: Amit S. Kale @ 2004-03-09 4:29 UTC (permalink / raw) To: Tom Rini, Andi Kleen; +Cc: Andrew Morton, linux-kernel, george, pavel On Monday 08 Mar 2004 10:48 pm, Tom Rini wrote: > On Mon, Mar 08, 2004 at 05:57:26PM +0100, Andi Kleen wrote: > > Tom Rini <trini@kernel.crashing.org> writes: > > > Here's where what Andi said about being able to get the pt_regs stuff > > > off the stack (I think that's what he said at least) started to confuse > > > me slightly. But if I understand it right (and I never got around to > > > testing this) we can replace the do_schedule() stuffs at least with > > > something like kgdb_get_pt_regs(), since (and I lost my notes on this, > > > so it's probably not quite right) (thread_info->esp0)-1 > > > > No, that's the user space registers. > > > > You don't need these registers really as long as you have the > > correct dwarf2 CFI description of all the code involved. gdb > > is then able to reconstruct them using the C stack by itself. > > > > All it needs for that is esp and eip. > > Ah, OK. Amit, how about for the expanded T-packet thing, we do what you > suggested, except call it kgdb_arch_extra_regs() and let the arch fill > out whatever regs it needs to. ESP/EIP for x86_64/i386, PC/SP for > ppc32, etc, etc? That'll be great, though it won't provide any more info to gdb, as gdb can get that info by 'g' packet. Thread listing problem is with 'g' packet returning incomplete information for threads other than the current thread. -Amit ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: kgdb for mainline kernel: core-lite [patch 1/3] 2004-03-08 16:57 ` kgdb for mainline kernel: core-lite [patch 1/3] Andi Kleen 2004-03-08 17:18 ` Tom Rini @ 2004-03-09 4:36 ` Amit S. Kale 2004-03-10 12:36 ` Andi Kleen 1 sibling, 1 reply; 35+ messages in thread From: Amit S. Kale @ 2004-03-09 4:36 UTC (permalink / raw) To: Andi Kleen, Tom Rini; +Cc: Andrew Morton, linux-kernel, george, pavel On Monday 08 Mar 2004 10:27 pm, Andi Kleen wrote: > Tom Rini <trini@kernel.crashing.org> writes: > > Here's where what Andi said about being able to get the pt_regs stuff > > off the stack (I think that's what he said at least) started to confuse > > me slightly. But if I understand it right (and I never got around to > > testing this) we can replace the do_schedule() stuffs at least with > > something like kgdb_get_pt_regs(), since (and I lost my notes on this, > > so it's probably not quite right) (thread_info->esp0)-1 > > No, that's the user space registers. > > You don't need these registers really as long as you have the > correct dwarf2 CFI description of all the code involved. gdb > is then able to reconstruct them using the C stack by itself. > > All it needs for that is esp and eip. Yes. But as things stand, gdb 6.0 doesn't show stack traces correctly with esp and eip got from switch_to and gas 2.14 can't handle i386 dwarf2 CFI. Do we want to enforce getting a CVS version of gdb _and_ gas to build kgdb? Certainly not. Current kgdb has a dependency on gdb 6.0. My RH9 gdb (5.3.x) can't talk with kgdb and complains about too long [sf]ThreadInfo packets. I don't like that either, but gdb 6.x should be standard on all distributions based on 2.6 kernels, so that's acceptable. -Amit ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: kgdb for mainline kernel: core-lite [patch 1/3] 2004-03-09 4:36 ` Amit S. Kale @ 2004-03-10 12:36 ` Andi Kleen 2004-03-10 15:27 ` Tom Rini 0 siblings, 1 reply; 35+ messages in thread From: Andi Kleen @ 2004-03-10 12:36 UTC (permalink / raw) To: Amit S. Kale Cc: Andi Kleen, Tom Rini, Andrew Morton, linux-kernel, george, pavel > Yes. But as things stand, gdb 6.0 doesn't show stack traces correctly with esp > and eip got from switch_to and gas 2.14 can't handle i386 dwarf2 CFI. Do we > want to enforce getting a CVS version of gdb _and_ gas to build kgdb? > Certainly not. binutils 2.15 should be released soon anyways AFAIK. And for x86-64 this all works just fine (as demonstrated by Jim's/George's stub), so please get rid of it at least for x86-64. I really don't want user_schedule there, because it's completely unnecessary. -Andi ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: kgdb for mainline kernel: core-lite [patch 1/3] 2004-03-10 12:36 ` Andi Kleen @ 2004-03-10 15:27 ` Tom Rini 2004-03-11 4:57 ` Amit S. Kale 0 siblings, 1 reply; 35+ messages in thread From: Tom Rini @ 2004-03-10 15:27 UTC (permalink / raw) To: Andi Kleen; +Cc: Amit S. Kale, Andrew Morton, linux-kernel, george, pavel On Wed, Mar 10, 2004 at 01:36:05PM +0100, Andi Kleen wrote: > > Yes. But as things stand, gdb 6.0 doesn't show stack traces correctly with esp > > and eip got from switch_to and gas 2.14 can't handle i386 dwarf2 CFI. Do we > > want to enforce getting a CVS version of gdb _and_ gas to build kgdb? > > Certainly not. > > binutils 2.15 should be released soon anyways AFAIK. And for x86-64 this all > works just fine (as demonstrated by Jim's/George's stub), so please get > rid of it at least for x86-64. I really don't want user_schedule there, > because it's completely unnecessary. I think more importantly, it's probably going to be one of those ugly things that will make it so much harder to get it into Linus' tree. So lets just say it'll require gdb 6.1 / binutils 2.15 for KGDB to work best. -- Tom Rini http://gate.crashing.org/~trini/ ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: kgdb for mainline kernel: core-lite [patch 1/3] 2004-03-10 15:27 ` Tom Rini @ 2004-03-11 4:57 ` Amit S. Kale 2004-03-11 5:05 ` Randy.Dunlap 2004-03-11 5:11 ` Andi Kleen 0 siblings, 2 replies; 35+ messages in thread From: Amit S. Kale @ 2004-03-11 4:57 UTC (permalink / raw) To: Tom Rini, Andi Kleen; +Cc: Andrew Morton, linux-kernel, george, pavel On Wednesday 10 Mar 2004 8:57 pm, Tom Rini wrote: > On Wed, Mar 10, 2004 at 01:36:05PM +0100, Andi Kleen wrote: > > > Yes. But as things stand, gdb 6.0 doesn't show stack traces correctly > > > with esp and eip got from switch_to and gas 2.14 can't handle i386 > > > dwarf2 CFI. Do we want to enforce getting a CVS version of gdb _and_ > > > gas to build kgdb? Certainly not. > > > > binutils 2.15 should be released soon anyways AFAIK. And for x86-64 this > > all works just fine (as demonstrated by Jim's/George's stub), so please > > get rid of it at least for x86-64. I really don't want user_schedule > > there, because it's completely unnecessary. > > I think more importantly, it's probably going to be one of those ugly > things that will make it so much harder to get it into Linus' tree. So > lets just say it'll require gdb 6.1 / binutils 2.15 for KGDB to work > best. If we are enforcing this we need to do it correctly: is there any way to check from source code whether binutils version is correct (even a gas check will suffice) -Amit ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: kgdb for mainline kernel: core-lite [patch 1/3] 2004-03-11 4:57 ` Amit S. Kale @ 2004-03-11 5:05 ` Randy.Dunlap 2004-03-11 5:11 ` Andi Kleen 1 sibling, 0 replies; 35+ messages in thread From: Randy.Dunlap @ 2004-03-11 5:05 UTC (permalink / raw) To: Amit S. Kale; +Cc: trini, ak, akpm, linux-kernel, george, pavel On Thu, 11 Mar 2004 10:27:51 +0530 "Amit S. Kale" <amitkale@emsyssoft.com> wrote: | On Wednesday 10 Mar 2004 8:57 pm, Tom Rini wrote: | > On Wed, Mar 10, 2004 at 01:36:05PM +0100, Andi Kleen wrote: | > > > Yes. But as things stand, gdb 6.0 doesn't show stack traces correctly | > > > with esp and eip got from switch_to and gas 2.14 can't handle i386 | > > > dwarf2 CFI. Do we want to enforce getting a CVS version of gdb _and_ | > > > gas to build kgdb? Certainly not. | > > | > > binutils 2.15 should be released soon anyways AFAIK. And for x86-64 this | > > all works just fine (as demonstrated by Jim's/George's stub), so please | > > get rid of it at least for x86-64. I really don't want user_schedule | > > there, because it's completely unnecessary. | > | > I think more importantly, it's probably going to be one of those ugly | > things that will make it so much harder to get it into Linus' tree. So | > lets just say it'll require gdb 6.1 / binutils 2.15 for KGDB to work | > best. | | If we are enforcing this we need to do it correctly: is there any way to check | from source code whether binutils version is correct (even a gas check will | suffice) Documentation/Changes says to use "ld -v" for binutils version. -- ~Randy ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: kgdb for mainline kernel: core-lite [patch 1/3] 2004-03-11 4:57 ` Amit S. Kale 2004-03-11 5:05 ` Randy.Dunlap @ 2004-03-11 5:11 ` Andi Kleen 1 sibling, 0 replies; 35+ messages in thread From: Andi Kleen @ 2004-03-11 5:11 UTC (permalink / raw) To: Amit S. Kale Cc: Tom Rini, Andi Kleen, Andrew Morton, linux-kernel, george, pavel > If we are enforcing this we need to do it correctly: is there any way to check > from source code whether binutils version is correct (even a gas check will > suffice) The latest 2.6 kernel has a makefile macro to check the gcc version. You could probably adapt that to check binutils too. -Andi ^ permalink raw reply [flat|nested] 35+ messages in thread
* kgdb for mainline kernel: core-lite [patch 1/3]
@ 2004-03-08 9:39 Amit S. Kale
2004-03-08 9:54 ` Andrew Morton
0 siblings, 1 reply; 35+ messages in thread
From: Amit S. Kale @ 2004-03-08 9:39 UTC (permalink / raw)
To: Andrew Morton, Linux Kernel; +Cc: Tom Rini, George Anzinger, Pavel Machek
[-- Attachment #1: Type: text/plain, Size: 482 bytes --]
Hi Andrew,
Here is kgdb for mainline kernel in three patches. This is a lite
version of kgdb available from kgdb.sourceforge.net. I believe that all of us
agree on this lite kgdb.
It supports basic debugging of i386 architecture and debugging over a serial
line. Contents of these patches are as follows:
[1] core-lite.patch: architecture indepndent code
[2] i386-lite.patch: i386 architecture dependent code
[3] 8250.patch: support for generic serial driver
Thanks.
-Amit
[-- Attachment #2: core-lite.patch --]
[-- Type: text/x-diff, Size: 41806 bytes --]
Index: linux-2.6.4-rc2-bk3-kgdb/Makefile
===================================================================
--- linux-2.6.4-rc2-bk3-kgdb.orig/Makefile 2004-03-08 14:30:27.382791896 +0530
+++ linux-2.6.4-rc2-bk3-kgdb/Makefile 2004-03-08 14:31:42.813324712 +0530
@@ -440,6 +440,8 @@
ifndef CONFIG_FRAME_POINTER
CFLAGS += -fomit-frame-pointer
+else
+CFLAGS += -fno-omit-frame-pointer
endif
ifdef CONFIG_DEBUG_INFO
Index: linux-2.6.4-rc2-bk3-kgdb/include/linux/debugger.h
===================================================================
--- linux-2.6.4-rc2-bk3-kgdb.orig/include/linux/debugger.h 2003-01-30 15:54:37.000000000 +0530
+++ linux-2.6.4-rc2-bk3-kgdb/include/linux/debugger.h 2004-03-08 14:31:42.814324560 +0530
@@ -0,0 +1,70 @@
+#ifndef _DEBUGGER_H_
+#define _DEBUGGER_H_
+
+/*
+ * Copyright (C) 2003-2004 Amit S. Kale
+ *
+ * Definition switchout for debuggers
+ */
+
+/*
+ * KGDB
+ */
+#ifdef CONFIG_KGDB
+
+typedef int gdb_debug_hook(int exVector, int signo, int err_code,
+ struct pt_regs *regs);
+extern gdb_debug_hook *linux_debug_hook;
+#define CHK_DEBUGGER(trapnr,signr,error_code,regs,after) \
+ { \
+ if (linux_debug_hook != (gdb_debug_hook *) NULL && !user_mode(regs)) \
+ { \
+ (*linux_debug_hook)(trapnr, signr, error_code, regs) ; \
+ after; \
+ } \
+ }
+
+void kgdb_nmihook(int cpu, void *regs);
+static inline void debugger_nmihook(int cpu, void *regs)
+{
+ kgdb_nmihook(cpu, regs);
+}
+
+void kgdb_entry(void);
+static inline void debugger_entry(void)
+{
+ kgdb_entry();
+}
+
+extern int debugger_step;
+extern atomic_t debugger_active;
+
+/*
+ * No debugger in the kernel
+ */
+#else
+
+#define CHK_DEBUGGER(trapnr,signr,error_code,regs,after) \
+{ \
+ if (0) \
+ after; \
+}
+
+static inline void debugger_nmihook(int cpu, void *regs)
+{
+ /* Do nothing */
+}
+
+static inline void debugger_entry(void)
+{
+ /* Do nothing */
+}
+
+#define debugger_step 0
+static const atomic_t debugger_active = { 0 };
+
+#define debugger_memerr_expected 0
+
+#endif
+
+#endif /* _DEBUGGER_H_ */
Index: linux-2.6.4-rc2-bk3-kgdb/include/linux/kgdb.h
===================================================================
--- linux-2.6.4-rc2-bk3-kgdb.orig/include/linux/kgdb.h 2003-01-30 15:54:37.000000000 +0530
+++ linux-2.6.4-rc2-bk3-kgdb/include/linux/kgdb.h 2004-03-08 14:31:42.814324560 +0530
@@ -0,0 +1,128 @@
+#ifndef _KGDB_H_
+#define _KGDB_H_
+
+/*
+ * Copyright (C) 2001-2004 Amit S. Kale
+ */
+
+#include <linux/ptrace.h>
+#include <asm/kgdb.h>
+#include <linux/spinlock.h>
+#include <asm/atomic.h>
+#include <linux/debugger.h>
+
+/*
+ * This file should not include ANY others. This makes it usable
+ * most anywhere without the fear of include order or inclusion.
+ * TODO: Make it so!
+ *
+ * This file may be included all the time. It is only active if
+ * CONFIG_KGDB is defined, otherwise it stubs out all the macros
+ * and entry points.
+ */
+
+#if defined(CONFIG_KGDB) && !defined(__ASSEMBLY__)
+/* To enter the debugger explicitly. */
+extern void breakpoint(void);
+extern void kgdb_schedule_breakpoint(void);
+extern void kgdb_process_breakpoint(void);
+extern volatile int kgdb_connected;
+
+#ifndef KGDB_MAX_NO_CPUS
+#if CONFIG_NR_CPUS > 8
+#error KGDB can handle max 8 CPUs
+#endif
+#define KGDB_MAX_NO_CPUS 8
+#endif
+
+extern atomic_t kgdb_setting_breakpoint;
+
+extern struct task_struct *kgdb_usethread, *kgdb_contthread;
+
+enum kgdb_bptype {
+ bp_breakpoint = '0',
+ bp_hardware_breakpoint,
+ bp_write_watchpoint,
+ bp_read_watchpoint,
+ bp_access_watchpoint
+};
+
+enum kgdb_bpstate {
+ bp_disabled,
+ bp_enabled
+};
+
+struct kgdb_bkpt {
+ unsigned long bpt_addr;
+ unsigned char saved_instr[BREAK_INSTR_SIZE];
+ enum kgdb_bptype type;
+ enum kgdb_bpstate state;
+};
+
+#ifndef BREAK_INSTR_SIZE
+#error BREAK_INSTR_SIZE needed by kgdb
+#endif
+
+#ifndef MAX_BREAKPOINTS
+#define MAX_BREAKPOINTS 16
+#endif
+
+#define KGDB_HW_BREAKPOINT 1
+
+/* These are functions that the arch specific code can, and in some cases
+ * must, provide. */
+extern int kgdb_arch_init(void);
+extern void regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs);
+extern void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs,
+ struct task_struct *p);
+extern void gdb_regs_to_regs(unsigned long *gdb_regs, struct pt_regs *regs);
+extern void kgdb_printexceptioninfo(int exceptionNo, int errorcode,
+ char *buffer);
+extern void kgdb_disable_hw_debug(struct pt_regs *regs);
+extern void kgdb_post_master_code(struct pt_regs *regs, int eVector,
+ int err_code);
+extern int kgdb_arch_handle_exception(int vector, int signo, int err_code,
+ char *InBuffer, char *outBuffer,
+ struct pt_regs *regs);
+extern int kgdb_arch_set_break(unsigned long addr, int type);
+extern int kgdb_arch_remove_break(unsigned long addr, int type);
+extern void kgdb_correct_hw_break(void);
+extern void kgdb_shadowinfo(struct pt_regs *regs, char *buffer,
+ unsigned threadid);
+extern struct task_struct *kgdb_get_shadow_thread(struct pt_regs *regs,
+ int threadid);
+extern struct pt_regs *kgdb_shadow_regs(struct pt_regs *regs, int threadid);
+
+struct kgdb_arch {
+ unsigned char gdb_bpt_instr[BREAK_INSTR_SIZE];
+ unsigned long flags;
+ unsigned shadowth;
+};
+
+/* Thread reference */
+typedef unsigned char threadref[8];
+
+struct kgdb_serial {
+ int (*read_char) (void);
+ void (*write_char) (int);
+ void (*flush) (void);
+ int (*hook) (void);
+};
+
+extern struct kgdb_serial *kgdb_serial;
+extern struct kgdb_arch arch_kgdb_ops;
+extern int kgdb_initialized;
+
+struct uart_port;
+
+extern void kgdb8250_add_port(int i, struct uart_port *serial_req);
+
+int kgdb_hex2long(char **ptr, long *longValue);
+char *kgdb_mem2hex(char *mem, char *buf, int count);
+char *kgdb_hex2mem(char *buf, char *mem, int count);
+int kgdb_get_mem(char *addr, unsigned char *buf, int count);
+
+#else
+#define kgdb_process_breakpoint() do {} while(0)
+#endif /* KGDB && !__ASSEMBLY__ */
+#endif /* _KGDB_H_ */
Index: linux-2.6.4-rc2-bk3-kgdb/init/main.c
===================================================================
--- linux-2.6.4-rc2-bk3-kgdb.orig/init/main.c 2004-03-08 14:30:27.283806944 +0530
+++ linux-2.6.4-rc2-bk3-kgdb/init/main.c 2004-03-08 14:31:42.815324408 +0530
@@ -39,6 +39,7 @@
#include <linux/writeback.h>
#include <linux/cpu.h>
#include <linux/efi.h>
+#include <linux/debugger.h>
#include <asm/io.h>
#include <asm/bugs.h>
@@ -581,6 +582,7 @@
smp_init();
do_basic_setup();
+ debugger_entry();
prepare_namespace();
Index: linux-2.6.4-rc2-bk3-kgdb/kernel/Makefile
===================================================================
--- linux-2.6.4-rc2-bk3-kgdb.orig/kernel/Makefile 2004-03-08 14:30:26.920862120 +0530
+++ linux-2.6.4-rc2-bk3-kgdb/kernel/Makefile 2004-03-08 14:31:42.815324408 +0530
@@ -19,6 +19,7 @@
obj-$(CONFIG_COMPAT) += compat.o
obj-$(CONFIG_IKCONFIG) += configs.o
obj-$(CONFIG_IKCONFIG_PROC) += configs.o
+obj-$(CONFIG_KGDB) += kgdb.o
ifneq ($(CONFIG_IA64),y)
# According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
Index: linux-2.6.4-rc2-bk3-kgdb/kernel/kgdb.c
===================================================================
--- linux-2.6.4-rc2-bk3-kgdb.orig/kernel/kgdb.c 2003-01-30 15:54:37.000000000 +0530
+++ linux-2.6.4-rc2-bk3-kgdb/kernel/kgdb.c 2004-03-08 14:31:42.818323952 +0530
@@ -0,0 +1,1275 @@
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/*
+ * Copyright (C) 2000-2001 VERITAS Software Corporation.
+ * Copyright (C) 2002-2004 Timesys Corporation
+ * Copyright (C) 2003-2004 Amit S. Kale
+ * Copyright (C) 2004 Pavel Machek <pavel@suse.cz>
+ * Copyright (C) 2004 Tom Rini <trini@kernel.crashing.org>
+ *
+ * Restructured KGDB for 2.6 kernels.
+ * thread support, support for multiple processors,support for ia-32(x86)
+ * hardware debugging, Console support, handling nmi watchdog
+ * - Amit S. Kale ( amitkale@emsyssoft.com )
+ *
+ * Several enhancements by George Anzinger <george@mvista.com>
+ * Generic KGDB Support
+ * Implemented by Anurekh Saxena (anurekh.saxena@timesys.com)
+ *
+ * Contributor: Lake Stevens Instrument Division
+ * Written by: Glenn Engel
+ *
+ * Modified for 386 by Jim Kingdon, Cygnus Support.
+ * Origianl kgdb, compatibility with 2.1.xx kernel by David Grothe <dave@gcom.com>
+ * Integrated into 2.2.5 kernel by Tigran Aivazian <tigran@sco.com>
+ */
+
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <asm/system.h>
+#include <asm/ptrace.h>
+#include <asm/uaccess.h>
+#include <linux/kgdb.h>
+#include <asm/atomic.h>
+#include <linux/notifier.h>
+#include <linux/module.h>
+#include <asm/cacheflush.h>
+#ifdef CONFIG_KGDB_CONSOLE
+#include <linux/console.h>
+#endif
+#include <linux/init.h>
+
+extern int pid_max;
+
+#define BUF_THREAD_ID_SIZE 16
+
+/*
+ * kgdb_initialized indicates that kgdb is setup and is all ready to serve
+ * breakpoints and other kernel exceptions. kgdb_connected indicates that kgdb
+ * has connected to kgdb.
+ */
+int kgdb_initialized = 0;
+volatile int kgdb_connected;
+
+/* If non-zero, wait for a gdb connection when kgdb_entry is called */
+int kgdb_enter = 0;
+
+/* Set to 1 to make kgdb allow access to user addresses. Can be set from gdb
+ * also at runtime. */
+int kgdb_useraccess = 0;
+
+struct kgdb_serial *kgdb_serial;
+
+/*
+ * Holds information about breakpoints in a kernel. These breakpoints are
+ * added and removed by gdb.
+ */
+struct kgdb_bkpt kgdb_break[MAX_BREAKPOINTS];
+
+struct kgdb_arch *kgdb_ops = &arch_kgdb_ops;
+
+static const char hexchars[] = "0123456789abcdef";
+
+static spinlock_t slavecpulocks[KGDB_MAX_NO_CPUS];
+static volatile int procindebug[KGDB_MAX_NO_CPUS];
+atomic_t kgdb_setting_breakpoint;
+struct task_struct *kgdb_usethread, *kgdb_contthread;
+
+int debugger_step;
+atomic_t debugger_active;
+
+/* This will point to kgdb_handle_exception by default.
+ * The architecture code can override this in its init function
+ */
+gdb_debug_hook *linux_debug_hook;
+
+static char remcom_in_buffer[BUFMAX];
+static char remcom_out_buffer[BUFMAX];
+
+/*
+ * The following are the stub functions for code which is arch specific
+ * and can be omitted on some arches
+ * This function will handle the initalization of any architecture specific
+ * hooks. If there is a suitable early output driver, kgdb_serial
+ * can be pointed at it now.
+ */
+int __attribute__ ((weak))
+ kgdb_arch_init(void)
+{
+ return 0;
+}
+
+void __attribute__ ((weak))
+ regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+{
+}
+
+void __attribute__ ((weak))
+ sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
+{
+}
+
+void __attribute__ ((weak))
+ gdb_regs_to_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+{
+}
+
+void __attribute__ ((weak))
+ kgdb_printexceptioninfo(int exceptionNo, int errorcode, char *buffer)
+{
+}
+
+void __attribute__ ((weak))
+ kgdb_disable_hw_debug(struct pt_regs *regs)
+{
+}
+
+void __attribute__ ((weak))
+ kgdb_post_master_code(struct pt_regs *regs, int eVector, int err_code)
+{
+}
+
+/*
+ * Handle any additional commands. This must handle the 'c' and 's'
+ * command packets.
+ * Return -1 to loop over other commands, and 0 to exit from KGDB
+ */
+int __attribute__ ((weak))
+ kgdb_arch_handle_exception(int vector, int signo, int err_code, char *InBuffer,
+ char *outBuffer, struct pt_regs *regs)
+{
+ return 0;
+}
+
+int __attribute__ ((weak))
+ kgdb_arch_set_break(unsigned long addr, int type)
+{
+ return 0;
+}
+
+int __attribute__ ((weak))
+ kgdb_arch_remove_break(unsigned long addr, int type)
+{
+ return 0;
+}
+
+void __attribute__ ((weak))
+ kgdb_correct_hw_break(void)
+{
+}
+
+void __attribute__ ((weak))
+ kgdb_shadowinfo(struct pt_regs *regs, char *buffer, unsigned threadid)
+{
+}
+
+struct task_struct __attribute__ ((weak))
+ * kgdb_get_shadow_thread(struct pt_regs *regs, int threadid)
+{
+ return NULL;
+}
+
+struct pt_regs __attribute__ ((weak))
+ * kgdb_shadow_regs(struct pt_regs *regs, int threadid)
+{
+ return NULL;
+}
+
+static int hex(char ch)
+{
+ if ((ch >= 'a') && (ch <= 'f'))
+ return (ch - 'a' + 10);
+ if ((ch >= '0') && (ch <= '9'))
+ return (ch - '0');
+ if ((ch >= 'A') && (ch <= 'F'))
+ return (ch - 'A' + 10);
+ return (-1);
+}
+
+/* scan for the sequence $<data>#<checksum> */
+static void get_packet(char *buffer)
+{
+ unsigned char checksum;
+ unsigned char xmitcsum;
+ int i;
+ int count;
+ char ch;
+
+ do {
+ /* wait around for the start character, ignore all other
+ * characters */
+ while ((ch = (kgdb_serial->read_char() & 0x7f)) != '$')
+ ; /* Spin. */
+ kgdb_connected = 1;
+ checksum = 0;
+ xmitcsum = -1;
+
+ count = 0;
+
+ /* now, read until a # or end of buffer is found */
+ while (count < (BUFMAX - 1)) {
+ ch = kgdb_serial->read_char() & 0x7f;
+ if (ch == '#')
+ break;
+ checksum = checksum + ch;
+ buffer[count] = ch;
+ count = count + 1;
+ }
+ buffer[count] = 0;
+
+ if (ch == '#') {
+ xmitcsum = hex(kgdb_serial->read_char() & 0x7f) << 4;
+ xmitcsum += hex(kgdb_serial->read_char() & 0x7f);
+
+ if (checksum != xmitcsum)
+ kgdb_serial->write_char('-'); /* failed checksum */
+ else
+ kgdb_serial->write_char('+'); /* successful transfer */
+ if (kgdb_serial->flush)
+ kgdb_serial->flush();
+ }
+ } while (checksum != xmitcsum);
+}
+
+/*
+ * Send the packet in buffer.
+ * Check for gdb connection if asked for.
+ */
+static void put_packet(char *buffer)
+{
+ unsigned char checksum;
+ int count;
+ char ch;
+
+ /* $<packet info>#<checksum>. */
+ while (1) {
+ kgdb_serial->write_char('$');
+ checksum = 0;
+ count = 0;
+
+ while ((ch = buffer[count])) {
+ kgdb_serial->write_char(ch);
+ checksum += ch;
+ count++;
+ }
+
+ kgdb_serial->write_char('#');
+ kgdb_serial->write_char(hexchars[checksum >> 4]);
+ kgdb_serial->write_char(hexchars[checksum % 16]);
+ if (kgdb_serial->flush)
+ kgdb_serial->flush();
+
+ /* Now see what we get in reply. */
+ ch = kgdb_serial->read_char();
+
+ if (ch == 3)
+ ch = kgdb_serial->read_char();
+
+ /* If we get an ACK, we are done. */
+ if (ch == '+')
+ return;
+
+ /* If we get the start of another packet, this means
+ * that GDB is attempting to reconnect. We will NAK
+ * the packet being sent, and stop trying to send this
+ * packet. */
+ if (ch == '$') {
+ kgdb_serial->write_char('-');
+ if (kgdb_serial->flush)
+ kgdb_serial->flush();
+ return;
+ }
+ }
+}
+
+static int get_char(char *addr, unsigned char *data)
+{
+ mm_segment_t fs;
+ int ret = 0;
+
+ if (!kgdb_useraccess && (unsigned long)addr < TASK_SIZE) {
+ return -EINVAL;
+ }
+ wmb();
+ fs = get_fs();
+ set_fs(KERNEL_DS);
+
+ if (get_user(*data, addr) != 0) {
+ ret = -EFAULT;
+ }
+
+ set_fs(fs);
+ return ret;
+}
+
+static int set_char(char *addr, int data)
+{
+ mm_segment_t fs;
+ int ret = 0;
+
+ if (!kgdb_useraccess && (unsigned long)addr < TASK_SIZE) {
+ return -EINVAL;
+ }
+ wmb();
+ fs = get_fs();
+ set_fs(KERNEL_DS);
+
+ if (put_user(data, addr) != 0) {
+ ret = -EFAULT;
+ }
+
+ set_fs(fs);
+ return ret;
+}
+
+/*
+ * convert the memory pointed to by mem into hex, placing result in buf
+ * return a pointer to the last char put in buf (null). May return an error.
+ */
+char *kgdb_mem2hex(char *mem, char *buf, int count)
+{
+ int i;
+ unsigned char ch;
+ int error;
+
+ for (i = 0; i < count; i++) {
+
+ if ((error = get_char(mem++, &ch)) < 0)
+ return ERR_PTR(error);
+
+ *buf++ = hexchars[ch >> 4];
+ *buf++ = hexchars[ch % 16];
+ }
+ *buf = 0;
+ return (buf);
+}
+
+/*
+ * convert the hex array pointed to by buf into binary to be placed in mem
+ * return a pointer to the character AFTER the last byte written
+ * May return an error.
+ */
+char *kgdb_hex2mem(char *buf, char *mem, int count)
+{
+ int i;
+ unsigned char ch;
+ int error;
+
+ for (i = 0; i < count; i++) {
+ ch = hex(*buf++) << 4;
+ ch = ch + hex(*buf++);
+ if ((error = set_char(mem++, ch)) < 0)
+ return ERR_PTR(error);
+ }
+ return (mem);
+}
+
+/*
+ * While we find nice hex chars, build a longValue.
+ * Return number of chars processed.
+ */
+int kgdb_hex2long(char **ptr, long *longValue)
+{
+ int numChars = 0;
+ int hexValue;
+
+ *longValue = 0;
+
+ while (**ptr) {
+ hexValue = hex(**ptr);
+ if (hexValue >= 0) {
+ *longValue = (*longValue << 4) | hexValue;
+ numChars++;
+ } else
+ break;
+
+ (*ptr)++;
+ }
+
+ return (numChars);
+}
+
+static inline char *pack_hex_byte(char *pkt, int byte)
+{
+ *pkt++ = hexchars[(byte >> 4) & 0xf];
+ *pkt++ = hexchars[(byte & 0xf)];
+ return pkt;
+}
+
+static inline void error_packet(char *pkt, int error)
+{
+ error = -error;
+ pkt[0] = 'E';
+ pkt[1] = hexchars[(error / 10)];
+ pkt[2] = hexchars[(error % 10)];
+ pkt[3] = '\0';
+}
+
+static char *pack_threadid(char *pkt, threadref * id)
+{
+ char *limit;
+ unsigned char *altid;
+
+ altid = (unsigned char *)id;
+ limit = pkt + BUF_THREAD_ID_SIZE;
+ while (pkt < limit)
+ pkt = pack_hex_byte(pkt, *altid++);
+
+ return pkt;
+}
+
+void int_to_threadref(threadref * id, int value)
+{
+ unsigned char *scan;
+
+ scan = (unsigned char *)id;
+ {
+ int i = 4;
+ while (i--)
+ *scan++ = 0;
+ }
+ *scan++ = (value >> 24) & 0xff;
+ *scan++ = (value >> 16) & 0xff;
+ *scan++ = (value >> 8) & 0xff;
+ *scan++ = (value & 0xff);
+}
+
+static struct task_struct *getthread(struct pt_regs *regs, int tid)
+{
+ int i;
+ struct list_head *l;
+ struct task_struct *p;
+ struct pid *pid;
+
+ if (tid >= pid_max + num_online_cpus() + kgdb_ops->shadowth) {
+ return NULL;
+ }
+ if (tid >= pid_max + num_online_cpus()) {
+ return kgdb_get_shadow_thread(regs, tid - pid_max -
+ num_online_cpus());
+ }
+ if (tid >= pid_max) {
+ i = 0;
+ for_each_task_pid(0, PIDTYPE_PID, p, l, pid) {
+ if (tid == pid_max + i) {
+ return p;
+ }
+ i++;
+ }
+ return NULL;
+ }
+ if (!tid) {
+ return NULL;
+ }
+ return find_task_by_pid(tid);
+}
+
+#ifdef CONFIG_SMP
+void kgdb_wait(struct pt_regs *regs)
+{
+ unsigned long flags;
+ int processor;
+
+ local_irq_save(flags);
+ processor = smp_processor_id();
+ procindebug[processor] = 1;
+ current->thread.debuggerinfo = regs;
+
+ /* Wait till master processor goes completely into the debugger.
+ * FIXME: this looks racy */
+ while (!procindebug[atomic_read(&debugger_active) - 1]) {
+ int i = 10; /* an arbitrary number */
+
+ while (--i)
+ asm volatile ("nop":::"memory");
+ barrier();
+ }
+
+ /* Wait till master processor is done with debugging */
+ spin_lock(slavecpulocks + processor);
+
+ /* This has been taken from x86 kgdb implementation and
+ * will be needed by architectures that have SMP support
+ */
+ kgdb_correct_hw_break();
+
+ /* Signal the master processor that we are done */
+ procindebug[processor] = 0;
+ spin_unlock(slavecpulocks + processor);
+ local_irq_restore(flags);
+}
+#endif
+
+int kgdb_get_mem(char *addr, unsigned char *buf, int count)
+{
+ int error;
+ while (count) {
+ if ((error = get_char(addr++, buf)) < 0)
+ return error;
+ buf++;
+ count--;
+ }
+ return 0;
+}
+
+static int set_mem(char *addr, unsigned char *buf, int count)
+{
+ int error;
+ while (count) {
+ if ((error = set_char(addr++, *buf++)) < 0)
+ return error;
+ count--;
+ }
+ return 0;
+}
+
+static int set_break(unsigned long addr)
+{
+ int i, breakno = -1;
+ int error;
+
+ for (i = 0; i < MAX_BREAKPOINTS; i++) {
+ if ((kgdb_break[i].state == bp_enabled) &&
+ (kgdb_break[i].bpt_addr == addr)) {
+ return -EEXIST;
+ }
+
+ if (kgdb_break[i].state == bp_disabled) {
+ if ((breakno == -1) || (kgdb_break[i].bpt_addr == addr))
+ breakno = i;
+ }
+ }
+ if (breakno == -1)
+ return -E2BIG;
+
+ if ((error = kgdb_get_mem((char *)addr, kgdb_break[breakno].saved_instr,
+ BREAK_INSTR_SIZE)) < 0)
+ return error;
+
+ if ((error = set_mem((char *)addr, kgdb_ops->gdb_bpt_instr,
+ BREAK_INSTR_SIZE)) < 0)
+ return error;
+ flush_cache_range(current->mm, addr, addr + BREAK_INSTR_SIZE);
+ flush_icache_range(addr, addr + BREAK_INSTR_SIZE);
+
+ kgdb_break[breakno].state = bp_enabled;
+ kgdb_break[breakno].type = bp_breakpoint;
+ kgdb_break[breakno].bpt_addr = addr;
+
+ return 0;
+}
+
+static int remove_break(unsigned long addr)
+{
+ int i;
+ int error;
+
+ for (i = 0; i < MAX_BREAKPOINTS; i++) {
+ if ((kgdb_break[i].state == bp_enabled) &&
+ (kgdb_break[i].bpt_addr == addr)) {
+ if ((error =
+ set_mem((char *)addr, kgdb_break[i].saved_instr,
+ BREAK_INSTR_SIZE)) < 0)
+ return error;
+ flush_cache_range(current->mm, addr,
+ addr + BREAK_INSTR_SIZE);
+ flush_icache_range(addr, addr + BREAK_INSTR_SIZE);
+ kgdb_break[i].state = bp_disabled;
+ return 0;
+ }
+ }
+ return -ENOENT;
+}
+
+int remove_all_break(void)
+{
+ int i;
+ int error;
+ for (i = 0; i < MAX_BREAKPOINTS; i++) {
+ if (kgdb_break[i].state == bp_enabled) {
+ unsigned long addr = kgdb_break[i].bpt_addr;
+ if ((error =
+ set_mem((char *)addr, kgdb_break[i].saved_instr,
+ BREAK_INSTR_SIZE)) < 0)
+ return error;
+ flush_cache_range(current->mm, addr,
+ addr + BREAK_INSTR_SIZE);
+ flush_icache_range(addr, addr + BREAK_INSTR_SIZE);
+ }
+ kgdb_break[i].state = bp_disabled;
+ }
+ return 0;
+}
+
+static inline int shadow_pid(int realpid)
+{
+ if (realpid) {
+ return realpid;
+ }
+ return pid_max + smp_processor_id();
+}
+
+/*
+ * This function does all command procesing for interfacing to gdb.
+ *
+ * Locking hierarchy:
+ * interface locks, if any (begin_session)
+ * kgdb lock (debugger_active)
+ *
+ */
+int kgdb_handle_exception(int exVector, int signo, int err_code,
+ struct pt_regs *linux_regs)
+{
+ unsigned long length, addr;
+ char *ptr;
+ unsigned long flags;
+ unsigned long gdb_regs[NUMREGBYTES / sizeof(unsigned long)];
+ int i;
+ long threadid;
+ threadref thref;
+ struct task_struct *thread = NULL;
+ unsigned procid;
+ static char tmpstr[256];
+ int numshadowth = num_online_cpus() + kgdb_ops->shadowth;
+ long kgdb_usethreadid = 0;
+ int error = 0;
+ struct pt_regs *shadowregs;
+
+ /* Panic on recursive debugger calls. */
+ if (atomic_read(&debugger_active) == smp_processor_id() + 1) {
+ return 0;
+ }
+
+ /*
+ * Interrupts will be restored by the 'trap return' code, except when
+ * single stepping.
+ */
+ local_irq_save(flags);
+
+ /* Hold debugger_active */
+ procid = smp_processor_id();
+ while (cmpxchg(&atomic_read(&debugger_active), 0, (procid + 1)) != 0) {
+ int i = 25; /* an arbitrary number */
+
+ while (--i)
+ asm volatile ("nop":::"memory");
+ }
+
+ debugger_step = 0;
+
+ current->thread.debuggerinfo = linux_regs;
+
+ kgdb_disable_hw_debug(linux_regs);
+
+ for (i = 0; i < num_online_cpus(); i++) {
+ spin_lock(&slavecpulocks[i]);
+ }
+
+ /* spin_lock code is good enough as a barrier so we don't
+ * need one here */
+ procindebug[smp_processor_id()] = 1;
+
+ /* Clear the out buffer. */
+ memset(remcom_out_buffer, 0, sizeof(remcom_out_buffer));
+
+ /* Master processor is completely in the debugger */
+ kgdb_post_master_code(linux_regs, exVector, err_code);
+
+ if (kgdb_connected) {
+ /* reply to host that an exception has occurred */
+ ptr = remcom_out_buffer;
+ *ptr++ = 'T';
+ *ptr++ = hexchars[(signo >> 4) % 16];
+ *ptr++ = hexchars[signo % 16];
+ ptr += strlen(strcpy(ptr, "thread:"));
+ int_to_threadref(&thref, shadow_pid(current->pid));
+ ptr = pack_threadid(ptr, &thref);
+ *ptr++ = ';';
+
+ put_packet(remcom_out_buffer);
+ }
+
+ kgdb_usethread = current;
+ kgdb_usethreadid = shadow_pid(current->pid);
+
+ while (1) {
+ int bpt_type = 0;
+ error = 0;
+
+ /* Clear the out buffer. */
+ memset(remcom_out_buffer, 0, sizeof(remcom_out_buffer));
+
+ get_packet(remcom_in_buffer);
+
+ switch (remcom_in_buffer[0]) {
+ case '?':
+ /* We know that this packet is only sent
+ * during initial connect. So to be safe,
+ * we clear out our breakpoints now incase
+ * GDB is reconnecting. */
+ remove_all_break();
+ remcom_out_buffer[0] = 'S';
+ remcom_out_buffer[1] = hexchars[signo >> 4];
+ remcom_out_buffer[2] = hexchars[signo % 16];
+ break;
+
+ case 'g': /* return the value of the CPU registers */
+ thread = kgdb_usethread;
+
+ if (!thread)
+ thread = current;
+
+ /* All threads that don't have debuggerinfo should be
+ in __schedule() sleeping, since all other CPUs
+ are in kgdb_wait, and thus have debuggerinfo. */
+
+ if (kgdb_usethreadid >= pid_max + num_online_cpus()) {
+ shadowregs = kgdb_shadow_regs(linux_regs,
+ kgdb_usethreadid -
+ pid_max -
+ num_online_cpus
+ ());
+ if (!shadowregs) {
+ error_packet(remcom_out_buffer,
+ -EINVAL);
+ break;
+ }
+ regs_to_gdb_regs(gdb_regs, shadowregs);
+ } else if (thread->thread.debuggerinfo) {
+ if ((error =
+ get_char(thread->thread.debuggerinfo,
+ (unsigned char *)gdb_regs)) < 0) {
+ error_packet(remcom_out_buffer, error);
+ break;
+ }
+ regs_to_gdb_regs(gdb_regs, (struct pt_regs *)
+ thread->thread.debuggerinfo);
+ } else {
+ /* Pull stuff saved during
+ * switch_to; nothing else is
+ * accessible (or even particularly relevant).
+ * This should be enough for a stack trace. */
+ sleeping_thread_to_gdb_regs(gdb_regs, thread);
+ }
+
+ kgdb_mem2hex((char *)gdb_regs, remcom_out_buffer,
+ NUMREGBYTES);
+ break;
+
+ case 'G': /* set the value of the CPU registers - return OK */
+ kgdb_hex2mem(&remcom_in_buffer[1], (char *)gdb_regs,
+ NUMREGBYTES);
+
+ if (kgdb_usethread && kgdb_usethread != current)
+ error_packet(remcom_out_buffer, -EINVAL);
+ else {
+ gdb_regs_to_regs(gdb_regs, (struct pt_regs *)
+ current->thread.debuggerinfo);
+ strcpy(remcom_out_buffer, "OK");
+ }
+
+ break;
+
+ /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
+ case 'm':
+ ptr = &remcom_in_buffer[1];
+ if (kgdb_hex2long(&ptr, &addr) > 0 && *ptr++ == ',' &&
+ kgdb_hex2long(&ptr, &length) > 0) {
+ if (IS_ERR(ptr = kgdb_mem2hex((char *)addr,
+ remcom_out_buffer,
+ length)))
+ error_packet(remcom_out_buffer,
+ PTR_ERR(ptr));
+ } else
+ error_packet(remcom_out_buffer, -EINVAL);
+ break;
+
+ /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
+ case 'M':
+ ptr = &remcom_in_buffer[1];
+ if (kgdb_hex2long(&ptr, &addr) > 0 && *(ptr++) == ','
+ && kgdb_hex2long(&ptr, &length) > 0 &&
+ *(ptr++) == ':') {
+ if (IS_ERR(ptr = kgdb_hex2mem(ptr, (char *)addr,
+ length)))
+ error_packet(remcom_out_buffer,
+ PTR_ERR(ptr));
+ } else
+ error_packet(remcom_out_buffer, -EINVAL);
+ break;
+
+ /* kill or detach. KGDB should treat this like a
+ * continue.
+ */
+ case 'D':
+ if ((error = remove_all_break()) < 0) {
+ error_packet(remcom_out_buffer, error);
+ } else {
+ strcpy(remcom_out_buffer, "OK");
+ kgdb_connected = 0;
+ }
+ put_packet(remcom_out_buffer);
+ goto default_handle;
+
+ case 'k':
+ /* Don't care about error from remove_all_break */
+ remove_all_break();
+ kgdb_connected = 0;
+ goto default_handle;
+
+ /* query */
+ case 'q':
+ switch (remcom_in_buffer[1]) {
+ case 's':
+ case 'f':
+ if (memcmp
+ (remcom_in_buffer + 2, "ThreadInfo", 10)) {
+ error_packet(remcom_out_buffer,
+ -EINVAL);
+ break;
+ }
+ if (remcom_in_buffer[1] == 'f') {
+ threadid = 1;
+ }
+ remcom_out_buffer[0] = 'm';
+ ptr = remcom_out_buffer + 1;
+ for (i = 0; i < 32 && threadid < pid_max +
+ numshadowth; threadid++) {
+ thread = getthread(linux_regs,
+ threadid);
+ if (thread) {
+ int_to_threadref(&thref,
+ threadid);
+ pack_threadid(ptr, &thref);
+ ptr += 16;
+ *(ptr++) = ',';
+ i++;
+ }
+ }
+ *(--ptr) = '\0';
+ break;
+
+ case 'C':
+ /* Current thread id */
+ strcpy(remcom_out_buffer, "QC");
+
+ threadid = shadow_pid(current->pid);
+
+ int_to_threadref(&thref, threadid);
+ pack_threadid(remcom_out_buffer + 2, &thref);
+ break;
+
+ case 'E':
+ /* Print exception info */
+ kgdb_printexceptioninfo(exVector, err_code,
+ remcom_out_buffer);
+ break;
+ case 'T':
+ if (memcmp(remcom_in_buffer + 1,
+ "ThreadExtraInfo,", 16)) {
+ error_packet(remcom_out_buffer,
+ -EINVAL);
+ break;
+ }
+ threadid = 0;
+ ptr = remcom_in_buffer + 17;
+ kgdb_hex2long(&ptr, &threadid);
+ if (!getthread(linux_regs, threadid)) {
+ error_packet(remcom_out_buffer,
+ -EINVAL);
+ break;
+ }
+ if (threadid < pid_max) {
+ kgdb_mem2hex(getthread(linux_regs,
+ threadid)->comm,
+ remcom_out_buffer, 16);
+ } else if (threadid >= pid_max +
+ num_online_cpus()) {
+ kgdb_shadowinfo(linux_regs,
+ remcom_out_buffer,
+ threadid - pid_max -
+ num_online_cpus());
+ } else {
+ sprintf(tmpstr, "Shadow task %d"
+ " for pid 0",
+ (int)(threadid - pid_max));
+ kgdb_mem2hex(tmpstr, remcom_out_buffer,
+ strlen(tmpstr));
+ }
+ break;
+ }
+ break;
+
+ /* task related */
+ case 'H':
+ switch (remcom_in_buffer[1]) {
+ case 'g':
+ ptr = &remcom_in_buffer[2];
+ kgdb_hex2long(&ptr, &threadid);
+ thread = getthread(linux_regs, threadid);
+ if (!thread && threadid > 0) {
+ error_packet(remcom_out_buffer,
+ -EINVAL);
+ break;
+ }
+ kgdb_usethread = thread;
+ kgdb_usethreadid = threadid;
+ strcpy(remcom_out_buffer, "OK");
+ break;
+
+ case 'c':
+ ptr = &remcom_in_buffer[2];
+ kgdb_hex2long(&ptr, &threadid);
+ if (!threadid) {
+ kgdb_contthread = 0;
+ } else {
+ thread =
+ getthread(linux_regs, threadid);
+ if (!thread && threadid > 0) {
+ error_packet(remcom_out_buffer,
+ -EINVAL);
+ break;
+ }
+ kgdb_contthread = thread;
+ }
+ strcpy(remcom_out_buffer, "OK");
+ break;
+ }
+ break;
+
+ /* Query thread status */
+ case 'T':
+ ptr = &remcom_in_buffer[1];
+ kgdb_hex2long(&ptr, &threadid);
+ thread = getthread(linux_regs, threadid);
+ if (thread)
+ strcpy(remcom_out_buffer, "OK");
+ else
+ error_packet(remcom_out_buffer, -EINVAL);
+ break;
+ case 'z':
+ case 'Z':
+ ptr = &remcom_in_buffer[2];
+ if (*(ptr++) != ',') {
+ error_packet(remcom_out_buffer, -EINVAL);
+ break;
+ }
+ kgdb_hex2long(&ptr, &addr);
+
+ bpt_type = remcom_in_buffer[1];
+ if (bpt_type != bp_breakpoint) {
+ if (bpt_type == bp_hardware_breakpoint &&
+ !(kgdb_ops->flags & KGDB_HW_BREAKPOINT))
+ break;
+
+ /* if set_break is not defined, then
+ * remove_break does not matter
+ */
+ if (!(kgdb_ops->flags & KGDB_HW_BREAKPOINT))
+ break;
+ }
+
+ if (remcom_in_buffer[0] == 'Z') {
+ if (bpt_type == bp_breakpoint)
+ error = set_break(addr);
+ else
+ error = kgdb_arch_set_break(addr,
+ bpt_type);
+ } else {
+ if (bpt_type == bp_breakpoint)
+ error = remove_break(addr);
+ else
+ error = kgdb_arch_remove_break(addr,
+ bpt_type);
+ }
+
+ if (error == 0)
+ strcpy(remcom_out_buffer, "OK");
+ else
+ error_packet(remcom_out_buffer, error);
+
+ break;
+
+ default:
+ default_handle:
+ error = kgdb_arch_handle_exception(exVector, signo,
+ err_code,
+ remcom_in_buffer,
+ remcom_out_buffer,
+ linux_regs);
+
+ if (error >= 0 || remcom_in_buffer[0] == 'D' ||
+ remcom_in_buffer[0] == 'k')
+ goto kgdb_exit;
+
+ } /* switch */
+
+ /* reply to the request */
+ put_packet(remcom_out_buffer);
+ }
+
+ kgdb_exit:
+ procindebug[smp_processor_id()] = 0;
+
+ for (i = 0; i < num_online_cpus(); i++) {
+ spin_unlock(&slavecpulocks[i]);
+ }
+ /* Wait till all the processors have quit
+ * from the debugger
+ */
+ for (i = 0; i < num_online_cpus(); i++) {
+ while (procindebug[i]) {
+ int j = 10; /* an arbitrary number */
+
+ while (--j) {
+ asm volatile ("nop":::"memory");
+ }
+ barrier();
+ }
+ }
+
+ /* Free debugger_active */
+ atomic_set(&debugger_active, 0);
+ local_irq_restore(flags);
+
+ return error;
+}
+
+/*
+ * GDB places a breakpoint at this function to know dynamically
+ * loaded objects. It's not defined static so that only one instance with this
+ * name exists in the kernel.
+ */
+
+int module_event(struct notifier_block *self, unsigned long val, void *data)
+{
+ return 0;
+}
+
+static struct notifier_block kgdb_module_load_nb = {
+ .notifier_call = module_event,
+};
+
+/* This function will generate a breakpoint exception. It is used at the
+ beginning of a program to sync up with a debugger and can be used
+ otherwise as a quick means to stop program execution and "break" into
+ the debugger. */
+
+void breakpoint(void)
+{
+ if (!kgdb_initialized) {
+ kgdb_enter = 1;
+ kgdb_entry();
+ if (!kgdb_initialized) {
+ printk("kgdb not enabled. Cannot do breakpoint\n");
+ return;
+ }
+ }
+
+ atomic_set(&kgdb_setting_breakpoint, 1);
+ wmb();
+ BREAKPOINT();
+ wmb();
+ atomic_set(&kgdb_setting_breakpoint, 0);
+}
+
+void kgdb_nmihook(int cpu, void *regs)
+{
+#ifdef CONFIG_SMP
+ if (!procindebug[cpu] && atomic_read(&debugger_active) != (cpu + 1)) {
+ kgdb_wait((struct pt_regs *)regs);
+ }
+#endif
+}
+
+void kgdb_entry(void)
+{
+ int i;
+
+ if (kgdb_initialized) {
+ /* KGDB was initialized */
+ return;
+ }
+
+ for (i = 0; i < KGDB_MAX_NO_CPUS; i++)
+ spin_lock_init(&slavecpulocks[i]);
+
+ /* Free debugger_active */
+ atomic_set(&debugger_active, 0);
+
+ for (i = 0; i < MAX_BREAKPOINTS; i++)
+ kgdb_break[i].state = bp_disabled;
+
+ linux_debug_hook = kgdb_handle_exception;
+
+ /* Let the arch do any initalization it needs to, including
+ * pointing to a suitable early output device. */
+ kgdb_arch_init();
+
+ /* We can't do much if this fails */
+ register_module_notifier(&kgdb_module_load_nb);
+
+ atomic_set(&kgdb_setting_breakpoint, 0);
+
+ if (!kgdb_serial || kgdb_serial->hook() < 0) {
+ /* KGDB interface isn't ready yet */
+ return;
+ }
+ kgdb_initialized = 1;
+ if (!kgdb_enter) {
+ return;
+ }
+ /*
+ * Call the breakpoint() routine in GDB to start the debugging
+ * session
+ */
+ printk(KERN_CRIT "Waiting for connection from remote gdb... ");
+ breakpoint();
+ printk("Connected.\n");
+}
+
+/*
+ * Sometimes we need to schedule a breakpoint because we can't break
+ * right where we are.
+ */
+static int kgdb_need_breakpoint[NR_CPUS];
+
+void kgdb_schedule_breakpoint(void)
+{
+ kgdb_need_breakpoint[smp_processor_id()] = 1;
+}
+
+void kgdb_process_breakpoint(void)
+{
+ /*
+ * Handle a breakpoint queued from inside network driver code
+ * to avoid reentrancy issues
+ */
+ if (kgdb_need_breakpoint[smp_processor_id()]) {
+ kgdb_need_breakpoint[smp_processor_id()] = 0;
+ breakpoint();
+ }
+}
+
+#ifdef CONFIG_KGDB_CONSOLE
+char kgdbconbuf[BUFMAX];
+
+void kgdb_console_write(struct console *co, const char *s, unsigned count)
+{
+ int i;
+ int wcount;
+ char *bufptr;
+ unsigned long flags;
+
+ if (!kgdb_connected) {
+ return;
+ }
+ local_irq_save(flags);
+
+ kgdbconbuf[0] = 'O';
+ bufptr = kgdbconbuf + 1;
+ while (count > 0) {
+ if ((count << 1) > (BUFMAX - 2)) {
+ wcount = (BUFMAX - 2) >> 1;
+ } else {
+ wcount = count;
+ }
+ count -= wcount;
+ for (i = 0; i < wcount; i++) {
+ bufptr = pack_hex_byte(bufptr, s[i]);
+ }
+ *bufptr = '\0';
+ s += wcount;
+
+ put_packet(kgdbconbuf);
+
+ }
+ local_irq_restore(flags);
+}
+
+/* Always fail so that kgdb console doesn't become the default console */
+static int __init kgdb_console_setup(struct console *co, char *options)
+{
+ return -1;
+}
+
+static struct console kgdbcons = {
+ .name = "kgdb",
+ .write = kgdb_console_write,
+ .setup = kgdb_console_setup,
+ .flags = CON_PRINTBUFFER | CON_ENABLED,
+ .index = -1,
+};
+
+static int __init kgdb_console_init(void)
+{
+ register_console(&kgdbcons);
+ return 0;
+}
+
+console_initcall(kgdb_console_init);
+#endif
+
+EXPORT_SYMBOL(breakpoint);
+#ifdef CONFIG_KGDB_THREAD
+EXPORT_SYMBOL(kern_schedule);
+#endif
+
+static int __init opt_kgdb_enter(char *str)
+{
+ kgdb_enter = 1;
+ return 1;
+}
+
+static int __init opt_gdb(char *str)
+{
+ kgdb_enter = 1;
+ return 1;
+}
+
+/*
+ * These options have been deprecated and are present only to maintain
+ * compatibility with kgdb for 2.4 and earlier kernels.
+ */
+#ifdef CONFIG_KGDB_8250
+extern int kgdb8250_baud;
+extern int kgdb8250_ttyS;
+static int __init opt_gdbttyS(char *str)
+{
+ kgdb8250_ttyS = simple_strtoul(str, NULL, 10);
+ return 1;
+}
+static int __init opt_gdbbaud(char *str)
+{
+ kgdb8250_baud = simple_strtoul(str, NULL, 10);
+ return 1;
+}
+#endif
+
+/*
+ *
+ * Sequence of following lines has to be maintained because gdb option is a
+ * prefix of the other two options
+ */
+
+#ifdef CONFIG_KGDB_8250
+__setup("gdbttyS=", opt_gdbttyS);
+__setup("gdbbaud=", opt_gdbbaud);
+#endif
+__setup("gdb", opt_gdb);
+__setup("kgdbwait", opt_kgdb_enter);
Index: linux-2.6.4-rc2-bk3-kgdb/kernel/sched.c
===================================================================
--- linux-2.6.4-rc2-bk3-kgdb.orig/kernel/sched.c 2004-03-08 14:30:26.958856344 +0530
+++ linux-2.6.4-rc2-bk3-kgdb/kernel/sched.c 2004-03-08 14:31:42.819323800 +0530
@@ -37,6 +37,7 @@
#include <linux/rcupdate.h>
#include <linux/cpu.h>
#include <linux/percpu.h>
+#include <linux/debugger.h>
#ifdef CONFIG_NUMA
#define cpu_to_node_mask(cpu) node_to_cpumask(cpu_to_node(cpu))
@@ -2961,6 +2962,8 @@
#if defined(in_atomic)
static unsigned long prev_jiffy; /* ratelimiting */
+ if (atomic_read(&debugger_active))
+ return;
if ((in_atomic() || irqs_disabled()) && system_running) {
if (time_before(jiffies, prev_jiffy + HZ) && prev_jiffy)
return;
Index: linux-2.6.4-rc2-bk3-kgdb/kernel/Kconfig.kgdb
===================================================================
--- linux-2.6.4-rc2-bk3-kgdb.orig/kernel/Kconfig.kgdb 2003-01-30 15:54:37.000000000 +0530
+++ linux-2.6.4-rc2-bk3-kgdb/kernel/Kconfig.kgdb 2004-03-08 14:31:42.820323648 +0530
@@ -0,0 +1,13 @@
+config KGDB
+ bool "KGDB: kernel debugging with remote gdb"
+ depends on DEBUG_KERNEL
+ select DEBUG_INFO
+ select FRAME_POINTER
+ help
+ If you say Y here, it will be possible to remotely debug the
+ kernel using gdb. This enlarges your kernel image disk size by
+ several megabytes and requires a machine with more than 128 MB
+ RAM to avoid excessive linking time.
+ Documentation of kernel debugger available at
+ http://kgdb.sourceforge.net
+ This is only useful for kernel hackers. If unsure, say N.
Index: linux-2.6.4-rc2-bk3-kgdb/Documentation/kgdb.txt
===================================================================
--- linux-2.6.4-rc2-bk3-kgdb.orig/Documentation/kgdb.txt 2003-01-30 15:54:37.000000000 +0530
+++ linux-2.6.4-rc2-bk3-kgdb/Documentation/kgdb.txt 2004-03-08 14:31:42.820323648 +0530
@@ -0,0 +1,49 @@
+KGDB Linux kernel source level debugger
+
+Amit S. Kale <amitkale@emsyssoft.com>
+Last updated March 2004.
+
+Introduction:
+kgdb is a source level debugger for linux kernel. It is used along with gdb to
+debug a linux kernel. Kernel developers can debug a kernel similar to
+application programs with the use of kgdb. It makes it possible to place
+breakpoints in kernel code, step through the code and observe variables.
+
+Two machines are required for using kgdb. One of these machines is a
+development machine and the other is a test machine. The machines are
+connected through a serial line, a null-modem cable which connects their
+serial ports. The kernel to be debugged runs on the test machine. gdb runs on
+the development machine. The serial line is used by gdb to communicate to the
+kernel being debugged.
+
+This version of kgdb is a lite version. It is available on i386 platform uses
+a serial line for communicating to gdb. Full kgdb containing more features and
+supporting more architecture is available along with plenty of documentation
+at http://kgdb.sourceforge.net/
+
+Compiling a kernel:
+Enable Kernel hacking -> Kernel Debugging -> KGDB: kernel debugging with
+remote gdb
+
+Only generic serial port (8250) is supported in the lite version. Configure
+8250 options.
+
+Booting the kernel:
+Kernel command line option "kgdbwait" makes kgdb wait for gdb connection
+during booting of a kernel. If you have configured simple serial port, the
+port number and speed can be overriden on command line by using option
+"kgdb8250=portnumber,speed", where port numbers are 0-3 for COM1 to COM4
+respectively and supported speeds are 9600, 19200, 38400, 57600, 115200.
+Example: kgdbwait kgdb8250=0,115200
+
+Connecting gdb:
+If you have used "kgdbwait", kgdb prints a message "Waiting for connection
+from remote gdb..." on the console and waits for connection from gdb. At this
+point you connect gdb to kgdb.
+Example:
+ % gdb ./vmlinux
+ (gdb) set remotebaud 115200
+ (gdb) target remote /dev/ttyS0
+
+Once connected, you can debug a kernel the way you would debug an application
+program.
^ permalink raw reply [flat|nested] 35+ messages in thread* Re: kgdb for mainline kernel: core-lite [patch 1/3] 2004-03-08 9:39 Amit S. Kale @ 2004-03-08 9:54 ` Andrew Morton 2004-03-08 10:15 ` Amit S. Kale 0 siblings, 1 reply; 35+ messages in thread From: Andrew Morton @ 2004-03-08 9:54 UTC (permalink / raw) To: Amit S. Kale; +Cc: linux-kernel, trini, george, pavel "Amit S. Kale" <amitkale@emsyssoft.com> wrote: > > Here is kgdb for mainline kernel in three patches. Thanks for working on this. > This is a lite > version of kgdb available from kgdb.sourceforge.net. I believe that all of us > agree on this lite kgdb. What is "lite" about it? As in, what features have been removed? > It supports basic debugging of i386 architecture and debugging over a serial > line. Contents of these patches are as follows: > > [1] core-lite.patch: architecture indepndent code > [2] i386-lite.patch: i386 architecture dependent code > [3] 8250.patch: support for generic serial driver What is the story on kgdboe? ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: kgdb for mainline kernel: core-lite [patch 1/3] 2004-03-08 9:54 ` Andrew Morton @ 2004-03-08 10:15 ` Amit S. Kale 2004-03-08 10:26 ` Andrew Morton 0 siblings, 1 reply; 35+ messages in thread From: Amit S. Kale @ 2004-03-08 10:15 UTC (permalink / raw) To: Andrew Morton; +Cc: linux-kernel, trini, george, pavel On Monday 08 Mar 2004 3:24 pm, Andrew Morton wrote: > "Amit S. Kale" <amitkale@emsyssoft.com> wrote: > > Here is kgdb for mainline kernel in three patches. > > Thanks for working on this. Credits go to all the kgdb developers. > > > This is a lite > > version of kgdb available from kgdb.sourceforge.net. I believe that all > > of us agree on this lite kgdb. > > What is "lite" about it? As in, what features have been removed? Here are features that are present only in full kgdb: 1. Thread support (aka info threads) 2. console messages through gdb 3. Automatic loading of modules in gdb 4. Support for x86_64 5. Support for powerpc 6. kgdb over ethernet [This isn't ready in the full version as well at this point of time] -Amit > > > It supports basic debugging of i386 architecture and debugging over a > > serial line. Contents of these patches are as follows: > > > > [1] core-lite.patch: architecture indepndent code > > [2] i386-lite.patch: i386 architecture dependent code > > [3] 8250.patch: support for generic serial driver > > What is the story on kgdboe? ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: kgdb for mainline kernel: core-lite [patch 1/3] 2004-03-08 10:15 ` Amit S. Kale @ 2004-03-08 10:26 ` Andrew Morton 2004-03-08 10:49 ` Amit S. Kale 0 siblings, 1 reply; 35+ messages in thread From: Andrew Morton @ 2004-03-08 10:26 UTC (permalink / raw) To: Amit S. Kale; +Cc: linux-kernel, trini, george, pavel "Amit S. Kale" <amitkale@emsyssoft.com> wrote: > > Here are features that are present only in full kgdb: > 1. Thread support (aka info threads) argh, disaster. I discussed this with Tom a week or so ago when it looked like this it was being chopped out and I recall being told that the discussion was referring to something else. Ho-hum, sorry. Can we please put this back in? > 2. console messages through gdb hm, it was occasionally handy. Is there a lot of code involved? > 3. Automatic loading of modules in gdb OK. I think. What does this feature actually do? > 4. Support for x86_64 > 5. Support for powerpc These are planned, I assume? > 6. kgdb over ethernet [This isn't ready in the full version as well at this > point of time] OK. But the version in -mm and -mpm works OK, does it not? Is there some difference in implementation which causes it to be broken in your tree? ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: kgdb for mainline kernel: core-lite [patch 1/3] 2004-03-08 10:26 ` Andrew Morton @ 2004-03-08 10:49 ` Amit S. Kale 2004-03-08 11:07 ` Andrew Morton ` (2 more replies) 0 siblings, 3 replies; 35+ messages in thread From: Amit S. Kale @ 2004-03-08 10:49 UTC (permalink / raw) To: Andrew Morton; +Cc: linux-kernel, trini, george, pavel On Monday 08 Mar 2004 3:56 pm, Andrew Morton wrote: > "Amit S. Kale" <amitkale@emsyssoft.com> wrote: > > Here are features that are present only in full kgdb: > > 1. Thread support (aka info threads) > > argh, disaster. I discussed this with Tom a week or so ago when it looked > like this it was being chopped out and I recall being told that the > discussion was referring to something else. > > Ho-hum, sorry. Can we please put this back in? Err., well this is one of the particularly dirty parts of kgdb. That's why it's been kept away. It takes care of correct thread backtraces in some rare cases. If you consider it an absolutely must, we can do something so that the dirty part is kept away and info threads almost always works. > > > 2. console messages through gdb > > hm, it was occasionally handy. Is there a lot of code involved? Nope. Code is already in, it's just a matter of adding a config option. > > > 3. Automatic loading of modules in gdb > > OK. I think. What does this feature actually do? This feature lets gdb hook onto a kernel function to detect loading and unloading of modules and preserves module section information for later use by gdb. At present this is broken for 2.6 kernels. I am working on this. > > > 4. Support for x86_64 > > 5. Support for powerpc > > These are planned, I assume? Yes. As soon as i386 goes in. x86_64 is already very clean. There was another opinion about whether x86_64 should be the first one to go in! ppc might need some work. > > 6. kgdb over ethernet [This isn't ready in the full version as well at > > this point of time] > > OK. But the version in -mm and -mpm works OK, does it not? Is there some > difference in implementation which causes it to be broken in your tree? There are some differences. The one in my tree also apparently works to some extent. It's being worked on. -Amit ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: kgdb for mainline kernel: core-lite [patch 1/3] 2004-03-08 10:49 ` Amit S. Kale @ 2004-03-08 11:07 ` Andrew Morton 2004-03-08 11:20 ` Amit S. Kale 2004-03-08 22:15 ` George Anzinger 2004-03-09 9:29 ` Amit S. Kale 2 siblings, 1 reply; 35+ messages in thread From: Andrew Morton @ 2004-03-08 11:07 UTC (permalink / raw) To: Amit S. Kale; +Cc: linux-kernel, trini, george, pavel "Amit S. Kale" <amitkale@emsyssoft.com> wrote: > > On Monday 08 Mar 2004 3:56 pm, Andrew Morton wrote: > > "Amit S. Kale" <amitkale@emsyssoft.com> wrote: > > > Here are features that are present only in full kgdb: > > > 1. Thread support (aka info threads) > > > > argh, disaster. I discussed this with Tom a week or so ago when it looked > > like this it was being chopped out and I recall being told that the > > discussion was referring to something else. > > > > Ho-hum, sorry. Can we please put this back in? > > Err., well this is one of the particularly dirty parts of kgdb. That's why > it's been kept away. It takes care of correct thread backtraces in some rare > cases. Let me just make sure we're taking about the same thing here. Are you saying that with kgdb-lite, `info threads' is completely missing, or does it just not work correctly with threads (as opposed to heavyweight processes)? > If you consider it an absolutely must, we can do something so that the dirty > part is kept away and info threads almost always works. Yes, I'd consider `info threads' support a must-have. I'm rather surprised that others do not? ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: kgdb for mainline kernel: core-lite [patch 1/3] 2004-03-08 11:07 ` Andrew Morton @ 2004-03-08 11:20 ` Amit S. Kale 2004-03-08 11:44 ` Amit S. Kale ` (2 more replies) 0 siblings, 3 replies; 35+ messages in thread From: Amit S. Kale @ 2004-03-08 11:20 UTC (permalink / raw) To: Andrew Morton; +Cc: linux-kernel, trini, george, pavel On Monday 08 Mar 2004 4:37 pm, Andrew Morton wrote: > "Amit S. Kale" <amitkale@emsyssoft.com> wrote: > > On Monday 08 Mar 2004 3:56 pm, Andrew Morton wrote: > > > "Amit S. Kale" <amitkale@emsyssoft.com> wrote: > > > > Here are features that are present only in full kgdb: > > > > 1. Thread support (aka info threads) > > > > > > argh, disaster. I discussed this with Tom a week or so ago when it > > > looked like this it was being chopped out and I recall being told that > > > the discussion was referring to something else. > > > > > > Ho-hum, sorry. Can we please put this back in? > > > > Err., well this is one of the particularly dirty parts of kgdb. That's > > why it's been kept away. It takes care of correct thread backtraces in > > some rare cases. > > Let me just make sure we're taking about the same thing here. Are you > saying that with kgdb-lite, `info threads' is completely missing, or does > it just not work correctly with threads (as opposed to heavyweight > processes)? info threads shows a list of threads. Heavy/light weight processes doesn't matter. Thread frame shown is incorrect. I looked at i386 dependent code again. Following code in it is incorrect. I never noticed it because this code is rarely used in full version of kgdb: +void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) .... + gdb_regs[_EBP] = *(int *)p->thread.esp; We can't guss ebp this way. This line should be removed. + gdb_regs[_DS] = __KERNEL_DS; + gdb_regs[_ES] = __KERNEL_DS; + gdb_regs[_PS] = 0; + gdb_regs[_CS] = __KERNEL_CS; + gdb_regs[_PC] = p->thread.eip; + gdb_regs[_ESP] = p->thread.esp; This should be gdb_regs[_ESP] = &p->thread.esp > > > If you consider it an absolutely must, we can do something so that the > > dirty part is kept away and info threads almost always works. > > Yes, I'd consider `info threads' support a must-have. I'm rather surprised > that others do not? Present threads support code changes calling convention of do_IRQ. Most believe that to be an absolute no. Since you consider it a must-have, I'll check whether above changes suggested by me make info threads listing correct in most cases. -Amit ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: kgdb for mainline kernel: core-lite [patch 1/3] 2004-03-08 11:20 ` Amit S. Kale @ 2004-03-08 11:44 ` Amit S. Kale 2004-03-08 11:54 ` Andrew Morton ` (2 more replies) 2004-03-08 11:48 ` Andrew Morton 2004-03-08 15:22 ` Tom Rini 2 siblings, 3 replies; 35+ messages in thread From: Amit S. Kale @ 2004-03-08 11:44 UTC (permalink / raw) To: Andrew Morton; +Cc: linux-kernel, trini, george, pavel On Monday 08 Mar 2004 4:50 pm, Amit S. Kale wrote: > On Monday 08 Mar 2004 4:37 pm, Andrew Morton wrote: > > "Amit S. Kale" <amitkale@emsyssoft.com> wrote: > > > On Monday 08 Mar 2004 3:56 pm, Andrew Morton wrote: > > > > "Amit S. Kale" <amitkale@emsyssoft.com> wrote: > > > > > Here are features that are present only in full kgdb: > > > > > 1. Thread support (aka info threads) > > > > > > > > argh, disaster. I discussed this with Tom a week or so ago when it > > > > looked like this it was being chopped out and I recall being told > > > > that the discussion was referring to something else. > > > > > > > > Ho-hum, sorry. Can we please put this back in? > > > > > > Err., well this is one of the particularly dirty parts of kgdb. That's > > > why it's been kept away. It takes care of correct thread backtraces in > > > some rare cases. > > > > Let me just make sure we're taking about the same thing here. Are you > > saying that with kgdb-lite, `info threads' is completely missing, or does > > it just not work correctly with threads (as opposed to heavyweight > > processes)? > > info threads shows a list of threads. Heavy/light weight processes doesn't > matter. Thread frame shown is incorrect. > > I looked at i386 dependent code again. Following code in it is incorrect. I > never noticed it because this code is rarely used in full version of kgdb: > > +void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct > task_struct *p) > .... > + gdb_regs[_EBP] = *(int *)p->thread.esp; > > We can't guss ebp this way. This line should be removed. > > + gdb_regs[_DS] = __KERNEL_DS; > + gdb_regs[_ES] = __KERNEL_DS; > + gdb_regs[_PS] = 0; > + gdb_regs[_CS] = __KERNEL_CS; > + gdb_regs[_PC] = p->thread.eip; > + gdb_regs[_ESP] = p->thread.esp; > > This should be gdb_regs[_ESP] = &p->thread.esp That's not correct it. It should be gdb_regs[_ESP] = p->thread.esp; Even with these changes I can't get thread listing correctly. Here is the intrusive piece of code that helps get thread state correctly. Any ideas on cleaning it? --- linux-2.6.3-kgdb.orig/include/linux/sched.h 2004-02-24 10:44:47.000000000 +0530 +++ linux-2.6.3-kgdb/include/linux/sched.h 2004-03-04 18:42:56.324188184 +0530 @@ -173,7 +173,9 @@ #define MAX_SCHEDULE_TIMEOUT LONG_MAX extern signed long FASTCALL(schedule_timeout(signed long timeout)); -asmlinkage void schedule(void); +asmlinkage void do_schedule(void); +asmlinkage void kern_schedule(void); +asmlinkage void kern_do_schedule(struct pt_regs); struct namespace; @@ -907,6 +909,15 @@ #endif /* CONFIG_SMP */ +static inline void schedule(void) +{ +#ifdef CONFIG_KGDB_THREAD + kern_schedule(); +#else + do_schedule(); +#endif +} + --- linux-2.6.3-kgdb.orig/kernel/sched.c 2004-03-04 13:38:03.000000000 +0530 +++ linux-2.6.3-kgdb/kernel/sched.c 2004-03-04 18:42:56.327187728 +0530 @@ -1592,7 +1592,7 @@ /* * schedule() is the main scheduler function. */ -asmlinkage void schedule(void) +asmlinkage void do_schedule(void) { long *switch_count; task_t *prev, *next; @@ -1764,6 +1764,23 @@ EXPORT_SYMBOL(default_wake_function); +asmlinkage void user_schedule(void) +{ +#ifdef CONFIG_KGDB_THREAD + current->thread.debuggerinfo = NULL; +#endif + do_schedule(); +} + +#ifdef CONFIG_KGDB_THREAD +asmlinkage void kern_do_schedule(struct pt_regs regs) +{ + current->thread.debuggerinfo = ®s; + do_schedule(); + current->thread.debuggerinfo = NULL; +} +#endif + -Amit > > > > If you consider it an absolutely must, we can do something so that the > > > dirty part is kept away and info threads almost always works. > > > > Yes, I'd consider `info threads' support a must-have. I'm rather > > surprised that others do not? > > Present threads support code changes calling convention of do_IRQ. Most > believe that to be an absolute no. > > Since you consider it a must-have, I'll check whether above changes > suggested by me make info threads listing correct in most cases. > > -Amit ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: kgdb for mainline kernel: core-lite [patch 1/3] 2004-03-08 11:44 ` Amit S. Kale @ 2004-03-08 11:54 ` Andrew Morton 2004-03-08 12:00 ` Amit S. Kale 2004-03-08 15:19 ` Tom Rini 2004-03-08 22:19 ` George Anzinger 2 siblings, 1 reply; 35+ messages in thread From: Andrew Morton @ 2004-03-08 11:54 UTC (permalink / raw) To: Amit S. Kale; +Cc: linux-kernel, trini, george, pavel "Amit S. Kale" <amitkale@emsyssoft.com> wrote: > > Here is the intrusive piece of code that helps get thread state correctly. Any > ideas on cleaning it? I think George's stub has diverged rather a lot from yours. Much more than I was aware. > --- linux-2.6.3-kgdb.orig/include/linux/sched.h 2004-02-24 10:44:47.000000000 > +0530 > +++ linux-2.6.3-kgdb/include/linux/sched.h 2004-03-04 18:42:56.324188184 +0530 > @@ -173,7 +173,9 @@ > > #define MAX_SCHEDULE_TIMEOUT LONG_MAX > extern signed long FASTCALL(schedule_timeout(signed long timeout)); > -asmlinkage void schedule(void); > +asmlinkage void do_schedule(void); > +asmlinkage void kern_schedule(void); > +asmlinkage void kern_do_schedule(struct pt_regs); The stub in -mm has only a single change to sched.c: diff -puN kernel/sched.c~kgdb-ga kernel/sched.c --- 25/kernel/sched.c~kgdb-ga 2004-03-07 01:57:48.000000000 -0800 +++ 25-akpm/kernel/sched.c 2004-03-07 01:57:48.000000000 -0800 @@ -2015,6 +2015,13 @@ out_unlock: EXPORT_SYMBOL(set_user_nice); +#if defined( CONFIG_KGDB) +struct task_struct * kgdb_get_idle(int this_cpu) +{ + return cpu_rq(this_cpu)->idle; +} +#endif + #ifndef __alpha__ /* ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: kgdb for mainline kernel: core-lite [patch 1/3] 2004-03-08 11:54 ` Andrew Morton @ 2004-03-08 12:00 ` Amit S. Kale 0 siblings, 0 replies; 35+ messages in thread From: Amit S. Kale @ 2004-03-08 12:00 UTC (permalink / raw) To: Andrew Morton; +Cc: linux-kernel, trini, george, pavel On Monday 08 Mar 2004 5:24 pm, Andrew Morton wrote: > "Amit S. Kale" <amitkale@emsyssoft.com> wrote: > > Here is the intrusive piece of code that helps get thread state > > correctly. Any ideas on cleaning it? > > I think George's stub has diverged rather a lot from yours. Much more than > I was aware. Yes. It has. At this point of time no one knows precisely where all they differ and how/whether they could be merged. The threads code in my version saves all registers during a context switch. This provides two benefits: 1. GDB doesn't lose track of registers when going up a stack trace starting with switch_to. 2. If a thread calls schedule, the thread backtrace starts from caller of schedule rather than schedule itself. So info threads command shows a more meaningful output. -Amit > > > --- linux-2.6.3-kgdb.orig/include/linux/sched.h 2004-02-24 > > 10:44:47.000000000 +0530 > > +++ linux-2.6.3-kgdb/include/linux/sched.h 2004-03-04 18:42:56.324188184 > > +0530 @@ -173,7 +173,9 @@ > > > > #define MAX_SCHEDULE_TIMEOUT LONG_MAX > > extern signed long FASTCALL(schedule_timeout(signed long timeout)); > > -asmlinkage void schedule(void); > > +asmlinkage void do_schedule(void); > > +asmlinkage void kern_schedule(void); > > +asmlinkage void kern_do_schedule(struct pt_regs); > > The stub in -mm has only a single change to sched.c: > > diff -puN kernel/sched.c~kgdb-ga kernel/sched.c > --- 25/kernel/sched.c~kgdb-ga 2004-03-07 01:57:48.000000000 -0800 > +++ 25-akpm/kernel/sched.c 2004-03-07 01:57:48.000000000 -0800 > @@ -2015,6 +2015,13 @@ out_unlock: > > EXPORT_SYMBOL(set_user_nice); > > +#if defined( CONFIG_KGDB) > +struct task_struct * kgdb_get_idle(int this_cpu) > +{ > + return cpu_rq(this_cpu)->idle; > +} > +#endif > + > #ifndef __alpha__ > > /* ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: kgdb for mainline kernel: core-lite [patch 1/3] 2004-03-08 11:44 ` Amit S. Kale 2004-03-08 11:54 ` Andrew Morton @ 2004-03-08 15:19 ` Tom Rini 2004-03-08 22:26 ` George Anzinger 2004-03-09 8:58 ` Amit S. Kale 2004-03-08 22:19 ` George Anzinger 2 siblings, 2 replies; 35+ messages in thread From: Tom Rini @ 2004-03-08 15:19 UTC (permalink / raw) To: Amit S. Kale; +Cc: Andrew Morton, linux-kernel, george, pavel On Mon, Mar 08, 2004 at 05:14:05PM +0530, Amit S. Kale wrote: > On Monday 08 Mar 2004 4:50 pm, Amit S. Kale wrote: > > On Monday 08 Mar 2004 4:37 pm, Andrew Morton wrote: > > > "Amit S. Kale" <amitkale@emsyssoft.com> wrote: > > > > On Monday 08 Mar 2004 3:56 pm, Andrew Morton wrote: > > > > > "Amit S. Kale" <amitkale@emsyssoft.com> wrote: > > > > > > Here are features that are present only in full kgdb: > > > > > > 1. Thread support (aka info threads) > > > > > > > > > > argh, disaster. I discussed this with Tom a week or so ago when it > > > > > looked like this it was being chopped out and I recall being told > > > > > that the discussion was referring to something else. > > > > > > > > > > Ho-hum, sorry. Can we please put this back in? > > > > > > > > Err., well this is one of the particularly dirty parts of kgdb. That's > > > > why it's been kept away. It takes care of correct thread backtraces in > > > > some rare cases. > > > > > > Let me just make sure we're taking about the same thing here. Are you > > > saying that with kgdb-lite, `info threads' is completely missing, or does > > > it just not work correctly with threads (as opposed to heavyweight > > > processes)? > > > > info threads shows a list of threads. Heavy/light weight processes doesn't > > matter. Thread frame shown is incorrect. > > > > I looked at i386 dependent code again. Following code in it is incorrect. I > > never noticed it because this code is rarely used in full version of kgdb: > > > > +void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct > > task_struct *p) > > .... > > + gdb_regs[_EBP] = *(int *)p->thread.esp; > > > > We can't guss ebp this way. This line should be removed. > > > > + gdb_regs[_DS] = __KERNEL_DS; > > + gdb_regs[_ES] = __KERNEL_DS; > > + gdb_regs[_PS] = 0; > > + gdb_regs[_CS] = __KERNEL_CS; > > + gdb_regs[_PC] = p->thread.eip; > > + gdb_regs[_ESP] = p->thread.esp; > > > > This should be gdb_regs[_ESP] = &p->thread.esp > > That's not correct it. It should be gdb_regs[_ESP] = p->thread.esp; > Even with these changes I can't get thread listing correctly. > > Here is the intrusive piece of code that helps get thread state correctly. Any > ideas on cleaning it? Here's where what Andi said about being able to get the pt_regs stuff off the stack (I think that's what he said at least) started to confuse me slightly. But if I understand it right (and I never got around to testing this) we can replace the do_schedule() stuffs at least with something like kgdb_get_pt_regs(), since (and I lost my notes on this, so it's probably not quite right) (thread_info->esp0)-1 -- Tom Rini http://gate.crashing.org/~trini/ ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: kgdb for mainline kernel: core-lite [patch 1/3] 2004-03-08 15:19 ` Tom Rini @ 2004-03-08 22:26 ` George Anzinger 2004-03-09 8:58 ` Amit S. Kale 1 sibling, 0 replies; 35+ messages in thread From: George Anzinger @ 2004-03-08 22:26 UTC (permalink / raw) To: Tom Rini; +Cc: Amit S. Kale, Andrew Morton, linux-kernel, pavel Tom Rini wrote: > On Mon, Mar 08, 2004 at 05:14:05PM +0530, Amit S. Kale wrote: > >>On Monday 08 Mar 2004 4:50 pm, Amit S. Kale wrote: >> >>>On Monday 08 Mar 2004 4:37 pm, Andrew Morton wrote: >>> >>>>"Amit S. Kale" <amitkale@emsyssoft.com> wrote: >>>> >>>>>On Monday 08 Mar 2004 3:56 pm, Andrew Morton wrote: >>>>> > "Amit S. Kale" <amitkale@emsyssoft.com> wrote: >>>>> > > Here are features that are present only in full kgdb: >>>>> > > 1. Thread support (aka info threads) >>>>> > >>>>> > argh, disaster. I discussed this with Tom a week or so ago when it >>>>> > looked like this it was being chopped out and I recall being told >>>>> > that the discussion was referring to something else. >>>>> > >>>>> > Ho-hum, sorry. Can we please put this back in? >>>>> >>>>> Err., well this is one of the particularly dirty parts of kgdb. That's >>>>>why it's been kept away. It takes care of correct thread backtraces in >>>>>some rare cases. >>>> >>>>Let me just make sure we're taking about the same thing here. Are you >>>>saying that with kgdb-lite, `info threads' is completely missing, or does >>>>it just not work correctly with threads (as opposed to heavyweight >>>>processes)? >>> >>>info threads shows a list of threads. Heavy/light weight processes doesn't >>>matter. Thread frame shown is incorrect. >>> >>>I looked at i386 dependent code again. Following code in it is incorrect. I >>>never noticed it because this code is rarely used in full version of kgdb: >>> >>>+void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct >>>task_struct *p) >>>.... >>>+ gdb_regs[_EBP] = *(int *)p->thread.esp; >>> >>>We can't guss ebp this way. This line should be removed. >>> >>>+ gdb_regs[_DS] = __KERNEL_DS; >>>+ gdb_regs[_ES] = __KERNEL_DS; >>>+ gdb_regs[_PS] = 0; >>>+ gdb_regs[_CS] = __KERNEL_CS; >>>+ gdb_regs[_PC] = p->thread.eip; >>>+ gdb_regs[_ESP] = p->thread.esp; >>> >>>This should be gdb_regs[_ESP] = &p->thread.esp >> >>That's not correct it. It should be gdb_regs[_ESP] = p->thread.esp; >>Even with these changes I can't get thread listing correctly. >> >>Here is the intrusive piece of code that helps get thread state correctly. Any >>ideas on cleaning it? > > > Here's where what Andi said about being able to get the pt_regs stuff > off the stack (I think that's what he said at least) started to confuse > me slightly. But if I understand it right (and I never got around to > testing this) we can replace the do_schedule() stuffs at least with > something like kgdb_get_pt_regs(), since (and I lost my notes on this, > so it's probably not quite right) (thread_info->esp0)-1 I don't see any problem here. All I do is to detect that the thread is not current on ANY cpu and send up the regs that switch to saved in the task struct. GDB can then figure out the rest from the dwarft2 frames. At this time it helps to have the compile option to do frames turned on. This is so that gdb will use the frame register to back out of switch to. It all works well in my kgdb. > -- George Anzinger george@mvista.com High-res-timers: http://sourceforge.net/projects/high-res-timers/ Preemption patch: http://www.kernel.org/pub/linux/kernel/people/rml ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: kgdb for mainline kernel: core-lite [patch 1/3] 2004-03-08 15:19 ` Tom Rini 2004-03-08 22:26 ` George Anzinger @ 2004-03-09 8:58 ` Amit S. Kale 1 sibling, 0 replies; 35+ messages in thread From: Amit S. Kale @ 2004-03-09 8:58 UTC (permalink / raw) To: Tom Rini; +Cc: Andrew Morton, linux-kernel, george, pavel On Monday 08 Mar 2004 8:49 pm, Tom Rini wrote: > On Mon, Mar 08, 2004 at 05:14:05PM +0530, Amit S. Kale wrote: > > On Monday 08 Mar 2004 4:50 pm, Amit S. Kale wrote: > > > On Monday 08 Mar 2004 4:37 pm, Andrew Morton wrote: > > > > "Amit S. Kale" <amitkale@emsyssoft.com> wrote: > > > > > On Monday 08 Mar 2004 3:56 pm, Andrew Morton wrote: > > > > > > "Amit S. Kale" <amitkale@emsyssoft.com> wrote: > > > > > > > Here are features that are present only in full kgdb: > > > > > > > 1. Thread support (aka info threads) > > > > > > > > > > > > argh, disaster. I discussed this with Tom a week or so ago when > > > > > > it looked like this it was being chopped out and I recall being > > > > > > told that the discussion was referring to something else. > > > > > > > > > > > > Ho-hum, sorry. Can we please put this back in? > > > > > > > > > > Err., well this is one of the particularly dirty parts of kgdb. > > > > > That's why it's been kept away. It takes care of correct thread > > > > > backtraces in some rare cases. > > > > > > > > Let me just make sure we're taking about the same thing here. Are > > > > you saying that with kgdb-lite, `info threads' is completely missing, > > > > or does it just not work correctly with threads (as opposed to > > > > heavyweight processes)? > > > > > > info threads shows a list of threads. Heavy/light weight processes > > > doesn't matter. Thread frame shown is incorrect. > > > > > > I looked at i386 dependent code again. Following code in it is > > > incorrect. I never noticed it because this code is rarely used in full > > > version of kgdb: > > > > > > +void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct > > > task_struct *p) > > > .... > > > + gdb_regs[_EBP] = *(int *)p->thread.esp; > > > > > > We can't guss ebp this way. This line should be removed. > > > > > > + gdb_regs[_DS] = __KERNEL_DS; > > > + gdb_regs[_ES] = __KERNEL_DS; > > > + gdb_regs[_PS] = 0; > > > + gdb_regs[_CS] = __KERNEL_CS; > > > + gdb_regs[_PC] = p->thread.eip; > > > + gdb_regs[_ESP] = p->thread.esp; > > > > > > This should be gdb_regs[_ESP] = &p->thread.esp > > > > That's not correct it. It should be gdb_regs[_ESP] = p->thread.esp; > > Even with these changes I can't get thread listing correctly. > > > > Here is the intrusive piece of code that helps get thread state > > correctly. Any ideas on cleaning it? > > Here's where what Andi said about being able to get the pt_regs stuff > off the stack (I think that's what he said at least) started to confuse > me slightly. But if I understand it right (and I never got around to That's an in interesting idea. We can at least get first pt_regs from the stack. That way we can get to user space eip in case a thread is in user space. The do_schedule and save all regs is definitely required if we want _exact_ state of all kernel threads. [exact state: all registers] Finding function frames below pt_regs becomes difficult or impossible, as exact dept of stack for each function in a stack is not known. EBP chains allow walking "up" but not "down". -Amit > testing this) we can replace the do_schedule() stuffs at least with > something like kgdb_get_pt_regs(), since (and I lost my notes on this, > so it's probably not quite right) (thread_info->esp0)-1 ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: kgdb for mainline kernel: core-lite [patch 1/3] 2004-03-08 11:44 ` Amit S. Kale 2004-03-08 11:54 ` Andrew Morton 2004-03-08 15:19 ` Tom Rini @ 2004-03-08 22:19 ` George Anzinger 2004-03-09 5:08 ` Amit S. Kale 2 siblings, 1 reply; 35+ messages in thread From: George Anzinger @ 2004-03-08 22:19 UTC (permalink / raw) To: Amit S. Kale; +Cc: Andrew Morton, linux-kernel, trini, pavel Amit S. Kale wrote: > On Monday 08 Mar 2004 4:50 pm, Amit S. Kale wrote: > >>On Monday 08 Mar 2004 4:37 pm, Andrew Morton wrote: >> >>>"Amit S. Kale" <amitkale@emsyssoft.com> wrote: >>> >>>>On Monday 08 Mar 2004 3:56 pm, Andrew Morton wrote: >>>> > "Amit S. Kale" <amitkale@emsyssoft.com> wrote: >>>> > > Here are features that are present only in full kgdb: >>>> > > 1. Thread support (aka info threads) >>>> > >>>> > argh, disaster. I discussed this with Tom a week or so ago when it >>>> > looked like this it was being chopped out and I recall being told >>>> > that the discussion was referring to something else. >>>> > >>>> > Ho-hum, sorry. Can we please put this back in? >>>> >>>> Err., well this is one of the particularly dirty parts of kgdb. That's >>>>why it's been kept away. It takes care of correct thread backtraces in >>>>some rare cases. >>> >>>Let me just make sure we're taking about the same thing here. Are you >>>saying that with kgdb-lite, `info threads' is completely missing, or does >>>it just not work correctly with threads (as opposed to heavyweight >>>processes)? >> >>info threads shows a list of threads. Heavy/light weight processes doesn't >>matter. Thread frame shown is incorrect. >> >>I looked at i386 dependent code again. Following code in it is incorrect. I >>never noticed it because this code is rarely used in full version of kgdb: >> >>+void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct >>task_struct *p) >>.... >>+ gdb_regs[_EBP] = *(int *)p->thread.esp; >> >>We can't guss ebp this way. This line should be removed. >> >>+ gdb_regs[_DS] = __KERNEL_DS; >>+ gdb_regs[_ES] = __KERNEL_DS; >>+ gdb_regs[_PS] = 0; >>+ gdb_regs[_CS] = __KERNEL_CS; >>+ gdb_regs[_PC] = p->thread.eip; >>+ gdb_regs[_ESP] = p->thread.esp; >> >>This should be gdb_regs[_ESP] = &p->thread.esp > > > That's not correct it. It should be gdb_regs[_ESP] = p->thread.esp; > Even with these changes I can't get thread listing correctly. > > Here is the intrusive piece of code that helps get thread state correctly. Any > ideas on cleaning it? I wonder what version of gdb you are using. What is it that you see? You really do need a gdb that handles the dwarft2 frames. This is a rather new gdb (I use the CVS version). -g ~ -- George Anzinger george@mvista.com High-res-timers: http://sourceforge.net/projects/high-res-timers/ Preemption patch: http://www.kernel.org/pub/linux/kernel/people/rml ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: kgdb for mainline kernel: core-lite [patch 1/3] 2004-03-08 22:19 ` George Anzinger @ 2004-03-09 5:08 ` Amit S. Kale 2004-03-09 15:37 ` Tom Rini 0 siblings, 1 reply; 35+ messages in thread From: Amit S. Kale @ 2004-03-09 5:08 UTC (permalink / raw) To: George Anzinger; +Cc: Andrew Morton, linux-kernel, trini, pavel On Tuesday 09 Mar 2004 3:49 am, George Anzinger wrote: > Amit S. Kale wrote: > > On Monday 08 Mar 2004 4:50 pm, Amit S. Kale wrote: > >>On Monday 08 Mar 2004 4:37 pm, Andrew Morton wrote: > >>>"Amit S. Kale" <amitkale@emsyssoft.com> wrote: > >>>>On Monday 08 Mar 2004 3:56 pm, Andrew Morton wrote: > >>>> > "Amit S. Kale" <amitkale@emsyssoft.com> wrote: > >>>> > > Here are features that are present only in full kgdb: > >>>> > > 1. Thread support (aka info threads) > >>>> > > >>>> > argh, disaster. I discussed this with Tom a week or so ago when it > >>>> > looked like this it was being chopped out and I recall being told > >>>> > that the discussion was referring to something else. > >>>> > > >>>> > Ho-hum, sorry. Can we please put this back in? > >>>> > >>>> Err., well this is one of the particularly dirty parts of kgdb. That's > >>>>why it's been kept away. It takes care of correct thread backtraces in > >>>>some rare cases. > >>> > >>>Let me just make sure we're taking about the same thing here. Are you > >>>saying that with kgdb-lite, `info threads' is completely missing, or > >>> does it just not work correctly with threads (as opposed to heavyweight > >>> processes)? > >> > >>info threads shows a list of threads. Heavy/light weight processes > >> doesn't matter. Thread frame shown is incorrect. > >> > >>I looked at i386 dependent code again. Following code in it is incorrect. > >> I never noticed it because this code is rarely used in full version of > >> kgdb: > >> > >>+void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct > >>task_struct *p) > >>.... > >>+ gdb_regs[_EBP] = *(int *)p->thread.esp; > >> > >>We can't guss ebp this way. This line should be removed. > >> > >>+ gdb_regs[_DS] = __KERNEL_DS; > >>+ gdb_regs[_ES] = __KERNEL_DS; > >>+ gdb_regs[_PS] = 0; > >>+ gdb_regs[_CS] = __KERNEL_CS; > >>+ gdb_regs[_PC] = p->thread.eip; > >>+ gdb_regs[_ESP] = p->thread.esp; > >> > >>This should be gdb_regs[_ESP] = &p->thread.esp > > > > That's not correct it. It should be gdb_regs[_ESP] = p->thread.esp; > > Even with these changes I can't get thread listing correctly. > > > > Here is the intrusive piece of code that helps get thread state > > correctly. Any ideas on cleaning it? > > I wonder what version of gdb you are using. What is it that you see? I am pasting below the output I see with gdb_regs[_PC] = p->thread.eip; gdb_regs[_ESP] = p->thread.esp; providing thread state information. > > You really do need a gdb that handles the dwarft2 frames. This is a rather > new gdb (I use the CVS version). Let's just stick to gdb 6.0 and binutils 2.14. CVS versions of gdb and binutils are too risky for someone who is trying to learn linux kernel by using kgdb. Let's face it, more people use kgdb to _learn_ some part of the kernel than kernel gurus :-) -Amit (gdb) info thr 42 Thread 32768 (Shadow task 0 for pid 0) 0xc011a27f in schedule () at /home/amitkale/work/linux-2.6.4-rc2-bk3-kgdb/kernel/sched.c:920 41 Thread 1129 (cupsd) 0xc1146000 in ?? () 40 Thread 1128 (initlog) 0xc1146000 in ?? () 39 Thread 1123 (S90cups) 0xc1146000 in ?? () 38 Thread 1119 (crond) 0xc1146000 in ?? () 37 Thread 1110 (gpm) 0xc1146000 in ?? () 36 Thread 1100 (sendmail) 0xc1146000 in ?? () 35 Thread 1090 (sendmail) 0xc1146000 in ?? () 34 Thread 1068 (rpc.mountd) 0xc1146000 in ?? () 33 Thread 1062 (rpciod) 0xc1146000 in ?? () 32 Thread 1061 (lockd) 0xc1146000 in ?? () 31 Thread 1060 (nfsd) 0xc1146000 in ?? () 30 Thread 1059 (nfsd) 0xc1146000 in ?? () 29 Thread 1058 (nfsd) 0xc1146000 in ?? () 28 Thread 1057 (nfsd) 0xc1146000 in ?? () 27 Thread 1056 (nfsd) 0xc1146000 in ?? () 26 Thread 1055 (nfsd) 0xc1146000 in ?? () 25 Thread 1054 (nfsd) 0xc1146000 in ?? () 24 Thread 1053 (nfsd) 0xc1146000 in ?? () 23 Thread 1049 (rpc.rquotad) 0xc1146000 in ?? () 22 Thread 1036 (xinetd) 0xc1146000 in ?? () 21 Thread 1021 (sshd) 0xc1146000 in ?? () ---Type <return> to continue, or q <return> to quit--- 20 Thread 925 (rpc.statd) 0xc1146000 in ?? () 19 Thread 906 (portmap) 0xc1146000 in ?? () 18 Thread 888 (klogd) 0xc1146000 in ?? () 17 Thread 884 (syslogd) 0xc1146000 in ?? () 16 Thread 706 (rc) 0xc1146000 in ?? () 15 Thread 626 (kjournald) 0xc1146000 in ?? () 14 Thread 625 (kjournald) 0xc1146000 in ?? () 13 Thread 624 (kjournald) 0xc1146000 in ?? () 12 Thread 11 (kjournald) 0xc1146000 in ?? () 11 Thread 10 (kseriod) 0xc011a27f in schedule () at /home/amitkale/work/linux-2.6.4-rc2-bk3-kgdb/kernel/sched.c:920 10 Thread 9 (aio/0) 0xc011a27f in schedule () at /home/amitkale/work/linux-2.6.4-rc2-bk3-kgdb/kernel/sched.c:920 9 Thread 8 (kswapd0) 0xc011a27f in schedule () at /home/amitkale/work/linux-2.6.4-rc2-bk3-kgdb/kernel/sched.c:920 8 Thread 7 (pdflush) 0xc011a27f in schedule () at /home/amitkale/work/linux-2.6.4-rc2-bk3-kgdb/kernel/sched.c:920 7 Thread 6 (pdflush) 0xc011a27f in schedule () at /home/amitkale/work/linux-2.6.4-rc2-bk3-kgdb/kernel/sched.c:920 6 Thread 5 (khubd) 0xc011a27f in schedule () at /home/amitkale/work/linux-2.6.4-rc2-bk3-kgdb/kernel/sched.c:920 5 Thread 4 (kblockd/0) 0xc011a27f in schedule () at /home/amitkale/work/linux-2.6.4-rc2-bk3-kgdb/kernel/sched.c:920 ---Type <return> to continue, or q <return> to quit--- 4 Thread 3 (events/0) 0xc011a27f in schedule () at /home/amitkale/work/linux-2.6.4-rc2-bk3-kgdb/kernel/sched.c:920 3 Thread 2 (ksoftirqd/0) 0xc011a27f in schedule () at /home/amitkale/work/linux-2.6.4-rc2-bk3-kgdb/kernel/sched.c:920 2 Thread 1 (init) 0xc1146000 in ?? () * 1 Thread 1130 (cupsd) breakpoint () at /home/amitkale/work/linux-2.6.4-rc2-bk3-kgdb/kernel/kgdb.c:1088 (gdb) thr 11 [Switching to thread 11 (Thread 10)]#0 0xc011a27f in schedule () at /home/amitkale/work/linux-2.6.4-rc2-bk3-kgdb/kernel/sched.c:920 920 switch_to(prev, next, prev); (gdb) bt #0 0xc011a27f in schedule () at /home/amitkale/work/linux-2.6.4-rc2-bk3-kgdb/kernel/sched.c:920 Cannot access memory at address 0x4 (gdb) info fr Stack level 0, frame at 0x8: eip = 0xc011a27f in schedule (/home/amitkale/work/linux-2.6.4-rc2-bk3-kgdb/kernel/sched.c:920); saved eip Cannot access memory at address 0x4 (gdb) info regi eax 0x0 0 ecx 0x0 0 edx 0x0 0 ebx 0x0 0 esp 0xc7da3f5c 0xc7da3f5c ebp 0x0 0x0 esi 0x0 0 edi 0x0 0 eip 0xc011a27f 0xc011a27f eflags 0x0 0 cs 0x60 96 ss 0x68 104 ds 0x68 104 es 0x68 104 fs 0xffff 65535 gs 0xffff 65535 (gdb) disas 0xc011a270 0xc011a288 Dump of assembler code from 0xc011a270 to 0xc011a288: 0xc011a270 <schedule+784>: jg 0xc011a214 <schedule+692> 0xc011a272 <schedule+786>: adc %eax,%eax 0xc011a274 <schedule+788>: pushl 0x350(%esi) 0xc011a27a <schedule+794>: jmp 0xc01079d0 <__switch_to> 0xc011a27f <schedule+799>: pop %ebp 0xc011a280 <schedule+800>: popf 0xc011a281 <schedule+801>: mov %eax,0xffffffd0(%ebp) 0xc011a284 <schedule+804>: xor %edx,%edx 0xc011a286 <schedule+806>: mov 0xc04b8edc,%esi End of assembler dump. (gdb) ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: kgdb for mainline kernel: core-lite [patch 1/3] 2004-03-09 5:08 ` Amit S. Kale @ 2004-03-09 15:37 ` Tom Rini 0 siblings, 0 replies; 35+ messages in thread From: Tom Rini @ 2004-03-09 15:37 UTC (permalink / raw) To: Amit S. Kale; +Cc: George Anzinger, Andrew Morton, linux-kernel, pavel On Tue, Mar 09, 2004 at 10:38:55AM +0530, Amit S. Kale wrote: > On Tuesday 09 Mar 2004 3:49 am, George Anzinger wrote: [snip] > > You really do need a gdb that handles the dwarft2 frames. This is a rather > > new gdb (I use the CVS version). > > Let's just stick to gdb 6.0 and binutils 2.14. CVS versions of gdb and > binutils are too risky for someone who is trying to learn linux kernel by > using kgdb. I think that depends on the level of crap we have to do compared to how it would be done with a newer version of gdb or binutils. GDB 6.1 for example should be out soon. -- Tom Rini http://gate.crashing.org/~trini/ ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: kgdb for mainline kernel: core-lite [patch 1/3] 2004-03-08 11:20 ` Amit S. Kale 2004-03-08 11:44 ` Amit S. Kale @ 2004-03-08 11:48 ` Andrew Morton 2004-03-08 22:21 ` George Anzinger 2004-03-08 15:22 ` Tom Rini 2 siblings, 1 reply; 35+ messages in thread From: Andrew Morton @ 2004-03-08 11:48 UTC (permalink / raw) To: Amit S. Kale; +Cc: linux-kernel, trini, george, pavel "Amit S. Kale" <amitkale@emsyssoft.com> wrote: > > > Let me just make sure we're taking about the same thing here. Are you > > saying that with kgdb-lite, `info threads' is completely missing, or does > > it just not work correctly with threads (as opposed to heavyweight > > processes)? > > info threads shows a list of threads. Heavy/light weight processes doesn't > matter. Thread frame shown is incorrect. It is? I haven't noticed any problems with it here. George recently changed it to also display the process name in the gdb output, which is valuable. > I looked at i386 dependent code again. Following code in it is incorrect. I > never noticed it because this code is rarely used in full version of kgdb: > > +void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct > *p) There is no such function in the stub in -mm kernels. > > Present threads support code changes calling convention of do_IRQ. Most > believe that to be an absolute no. I see no such change in George's stub, unless I'm missing something again. > Since you consider it a must-have, I'll check whether above changes suggested > by me make info threads listing correct in most cases. The only problem I have with it is that sometimes after listing all threads the debugger can lose control of the target and will start complaining about communication errors. I assume the target has died. This happens very rarely. Usually when you're about to find the bug ;) ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: kgdb for mainline kernel: core-lite [patch 1/3] 2004-03-08 11:48 ` Andrew Morton @ 2004-03-08 22:21 ` George Anzinger 0 siblings, 0 replies; 35+ messages in thread From: George Anzinger @ 2004-03-08 22:21 UTC (permalink / raw) To: Andrew Morton; +Cc: Amit S. Kale, linux-kernel, trini, pavel Andrew Morton wrote: > "Amit S. Kale" <amitkale@emsyssoft.com> wrote: > >>>Let me just make sure we're taking about the same thing here. Are you >>>saying that with kgdb-lite, `info threads' is completely missing, or does >>>it just not work correctly with threads (as opposed to heavyweight >>>processes)? >> >>info threads shows a list of threads. Heavy/light weight processes doesn't >>matter. Thread frame shown is incorrect. > > > It is? I haven't noticed any problems with it here. George recently > changed it to also display the process name in the gdb output, which is > valuable. > > >>I looked at i386 dependent code again. Following code in it is incorrect. I >>never noticed it because this code is rarely used in full version of kgdb: >> >>+void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct >>*p) > > > There is no such function in the stub in -mm kernels. > > >>Present threads support code changes calling convention of do_IRQ. Most >>believe that to be an absolute no. > > > I see no such change in George's stub, unless I'm missing something again. Amit and I went after the problem in rather different ways... > > >>Since you consider it a must-have, I'll check whether above changes suggested >>by me make info threads listing correct in most cases. > > > The only problem I have with it is that sometimes after listing all threads > the debugger can lose control of the target and will start complaining > about communication errors. I assume the target has died. This happens > very rarely. Usually when you're about to find the bug ;) Yeah, you won't believe how much work it took to detect that ;) -- George Anzinger george@mvista.com High-res-timers: http://sourceforge.net/projects/high-res-timers/ Preemption patch: http://www.kernel.org/pub/linux/kernel/people/rml ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: kgdb for mainline kernel: core-lite [patch 1/3] 2004-03-08 11:20 ` Amit S. Kale 2004-03-08 11:44 ` Amit S. Kale 2004-03-08 11:48 ` Andrew Morton @ 2004-03-08 15:22 ` Tom Rini 2004-03-08 16:32 ` Amit S. Kale 2004-03-08 22:29 ` George Anzinger 2 siblings, 2 replies; 35+ messages in thread From: Tom Rini @ 2004-03-08 15:22 UTC (permalink / raw) To: Amit S. Kale; +Cc: Andrew Morton, linux-kernel, george, pavel On Mon, Mar 08, 2004 at 04:50:18PM +0530, Amit S. Kale wrote: > On Monday 08 Mar 2004 4:37 pm, Andrew Morton wrote: > > "Amit S. Kale" <amitkale@emsyssoft.com> wrote: [snip] > > > If you consider it an absolutely must, we can do something so that the > > > dirty part is kept away and info threads almost always works. > > > > Yes, I'd consider `info threads' support a must-have. I'm rather surprised > > that others do not? > > Present threads support code changes calling convention of do_IRQ. Most > believe that to be an absolute no. I believe that George's version does something totally different, with some macros at compile time (and binutils support, I _think_) to not have to change do_IRQ. -- Tom Rini http://gate.crashing.org/~trini/ ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: kgdb for mainline kernel: core-lite [patch 1/3] 2004-03-08 15:22 ` Tom Rini @ 2004-03-08 16:32 ` Amit S. Kale 2004-03-08 22:29 ` George Anzinger 1 sibling, 0 replies; 35+ messages in thread From: Amit S. Kale @ 2004-03-08 16:32 UTC (permalink / raw) To: Tom Rini; +Cc: Andrew Morton, linux-kernel, george, pavel On Monday 08 Mar 2004 8:52 pm, Tom Rini wrote: > On Mon, Mar 08, 2004 at 04:50:18PM +0530, Amit S. Kale wrote: > > On Monday 08 Mar 2004 4:37 pm, Andrew Morton wrote: > > > "Amit S. Kale" <amitkale@emsyssoft.com> wrote: > > [snip] > > > > > If you consider it an absolutely must, we can do something so that > > > > the dirty part is kept away and info threads almost always works. > > > > > > Yes, I'd consider `info threads' support a must-have. I'm rather > > > surprised that others do not? > > > > Present threads support code changes calling convention of do_IRQ. Most > > believe that to be an absolute no. > > I believe that George's version does something totally different, with > some macros at compile time (and binutils support, I _think_) to not > have to change do_IRQ. OOPS! Present code doesn't change calling convention of do_IRQ. I changed that some time ago. -Amit ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: kgdb for mainline kernel: core-lite [patch 1/3] 2004-03-08 15:22 ` Tom Rini 2004-03-08 16:32 ` Amit S. Kale @ 2004-03-08 22:29 ` George Anzinger 1 sibling, 0 replies; 35+ messages in thread From: George Anzinger @ 2004-03-08 22:29 UTC (permalink / raw) To: Tom Rini; +Cc: Amit S. Kale, Andrew Morton, linux-kernel, pavel Tom Rini wrote: > On Mon, Mar 08, 2004 at 04:50:18PM +0530, Amit S. Kale wrote: > >>On Monday 08 Mar 2004 4:37 pm, Andrew Morton wrote: >> >>>"Amit S. Kale" <amitkale@emsyssoft.com> wrote: > > [snip] > >>>> If you consider it an absolutely must, we can do something so that the >>>>dirty part is kept away and info threads almost always works. >>> >>>Yes, I'd consider `info threads' support a must-have. I'm rather surprised >>>that others do not? >> >>Present threads support code changes calling convention of do_IRQ. Most >>believe that to be an absolute no. > > > I believe that George's version does something totally different, with > some macros at compile time (and binutils support, I _think_) to not > have to change do_IRQ. No, nothing at compile time, at least WRT the threads issue. There is a completely different problem with backtracing through an interrupt or trap. I have sent the patch for that which makes only minimal changes to code (one line I think, and that an asm line). The rest is a dwarft2 set of code to build the frame description for the trap/interrupt frame. > -- George Anzinger george@mvista.com High-res-timers: http://sourceforge.net/projects/high-res-timers/ Preemption patch: http://www.kernel.org/pub/linux/kernel/people/rml ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: kgdb for mainline kernel: core-lite [patch 1/3] 2004-03-08 10:49 ` Amit S. Kale 2004-03-08 11:07 ` Andrew Morton @ 2004-03-08 22:15 ` George Anzinger 2004-03-09 4:46 ` Amit S. Kale 2004-03-09 9:29 ` Amit S. Kale 2 siblings, 1 reply; 35+ messages in thread From: George Anzinger @ 2004-03-08 22:15 UTC (permalink / raw) To: Amit S. Kale; +Cc: Andrew Morton, linux-kernel, trini, pavel Amit S. Kale wrote: > On Monday 08 Mar 2004 3:56 pm, Andrew Morton wrote: > >>"Amit S. Kale" <amitkale@emsyssoft.com> wrote: >> >>>Here are features that are present only in full kgdb: >>> 1. Thread support (aka info threads) >> >>argh, disaster. I discussed this with Tom a week or so ago when it looked >>like this it was being chopped out and I recall being told that the >>discussion was referring to something else. >> >>Ho-hum, sorry. Can we please put this back in? > > > Err., well this is one of the particularly dirty parts of kgdb. That's why > it's been kept away. It takes care of correct thread backtraces in some rare > cases. > > If you consider it an absolutely must, we can do something so that the dirty > part is kept away and info threads almost always works. > Amit, I think we should just put the info threads in the core. No attempt to do any trace back from kgdb. Let them all show up in the switch code. I have a script (gdb macro) that will give a rather decent "info threads" display. Oh, we need to add one other responce to kgdb for the process info gdb command. * This query allows the target stub to return an arbitrary string * (or strings) giving arbitrary information about the target process. * This is optional; the target stub isn't required to implement it. * * Syntax: qfProcessInfo request first string * qsProcessInfo request subsequent string * reply: 'O'<hex-encoded-string> * 'l' last reply (empty) */ What we want here is the thread name. Here is the macro set: set var $low_sched=0 define do_threads if (void)$low_sched==(void)0 set_b end thread apply all do_th_lines end define do_th_lines set var $do_th_co=0 while ($pc > $low_sched) && ($pc < $high_sched) up-silent set var $do_th_co=$do_th_co+1 end if $do_th_co==0 info remote-process bt else up-silent info remote-process down end end define set_b set var $low_sched=scheduling_functions_start_here set var $high_sched=scheduling_functions_end_here end ~ -- George Anzinger george@mvista.com High-res-timers: http://sourceforge.net/projects/high-res-timers/ Preemption patch: http://www.kernel.org/pub/linux/kernel/people/rml ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: kgdb for mainline kernel: core-lite [patch 1/3] 2004-03-08 22:15 ` George Anzinger @ 2004-03-09 4:46 ` Amit S. Kale 0 siblings, 0 replies; 35+ messages in thread From: Amit S. Kale @ 2004-03-09 4:46 UTC (permalink / raw) To: George Anzinger; +Cc: Andrew Morton, linux-kernel, trini, pavel On Tuesday 09 Mar 2004 3:45 am, George Anzinger wrote: > Amit S. Kale wrote: > > On Monday 08 Mar 2004 3:56 pm, Andrew Morton wrote: > >>"Amit S. Kale" <amitkale@emsyssoft.com> wrote: > >>>Here are features that are present only in full kgdb: > >>> 1. Thread support (aka info threads) > >> > >>argh, disaster. I discussed this with Tom a week or so ago when it > >> looked like this it was being chopped out and I recall being told that > >> the discussion was referring to something else. > >> > >>Ho-hum, sorry. Can we please put this back in? > > > > Err., well this is one of the particularly dirty parts of kgdb. That's > > why it's been kept away. It takes care of correct thread backtraces in > > some rare cases. > > > > If you consider it an absolutely must, we can do something so that the > > dirty part is kept away and info threads almost always works. > > Amit, > > I think we should just put the info threads in the core. No attempt to do > any trace back from kgdb. Let them all show up in the switch code. I have > a script (gdb macro) that will give a rather decent "info threads" display. > Oh, we need to add one other responce to kgdb for the process info gdb > command. qfProcessInfo looks like a very useful command. This is still a hack. These kinds of hacks are difficult to maintain over a long time because they are based on undocumented information. While setting up kgdb for the first time isn't easy, macros add to that complexity. Have you experienced "shakyness" of macros? I have used process information macros at kgdb.sourceforge.net to display a "ps" command like output since the days of 2.4.0. I had to change them 3-4 times till now because of kernel structure changes. The "changing" part is typically a 2-3 hour regorous exercise :-) -Amit > * This query allows the target stub to return an arbitrary string > * (or strings) giving arbitrary information about the target process. > * This is optional; the target stub isn't required to implement it. > * > * Syntax: qfProcessInfo request first string > * qsProcessInfo request subsequent string > * reply: 'O'<hex-encoded-string> > * 'l' last reply (empty) > */ > What we want here is the thread name. > > Here is the macro set: > > set var $low_sched=0 > > define do_threads > if (void)$low_sched==(void)0 > set_b > end > thread apply all do_th_lines > end > > define do_th_lines > set var $do_th_co=0 > while ($pc > $low_sched) && ($pc < $high_sched) > up-silent > set var $do_th_co=$do_th_co+1 > end > if $do_th_co==0 > info remote-process > bt > else > up-silent > info remote-process > down > end > end > > define set_b > set var $low_sched=scheduling_functions_start_here > set var $high_sched=scheduling_functions_end_here > end > > > ~ ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: kgdb for mainline kernel: core-lite [patch 1/3] 2004-03-08 10:49 ` Amit S. Kale 2004-03-08 11:07 ` Andrew Morton 2004-03-08 22:15 ` George Anzinger @ 2004-03-09 9:29 ` Amit S. Kale 2004-03-09 15:06 ` Tom Rini 2 siblings, 1 reply; 35+ messages in thread From: Amit S. Kale @ 2004-03-09 9:29 UTC (permalink / raw) To: Andrew Morton; +Cc: linux-kernel, trini, george, pavel [-- Attachment #1: Type: text/plain, Size: 2628 bytes --] On Monday 08 Mar 2004 4:19 pm, Amit S. Kale wrote: > On Monday 08 Mar 2004 3:56 pm, Andrew Morton wrote: > > "Amit S. Kale" <amitkale@emsyssoft.com> wrote: > > > Here are features that are present only in full kgdb: > > > 1. Thread support (aka info threads) > > > > argh, disaster. I discussed this with Tom a week or so ago when it > > looked like this it was being chopped out and I recall being told that > > the discussion was referring to something else. > > > > Ho-hum, sorry. Can we please put this back in? > > Err., well this is one of the particularly dirty parts of kgdb. That's why > it's been kept away. It takes care of correct thread backtraces in some > rare cases. > > If you consider it an absolutely must, we can do something so that the > dirty part is kept away and info threads almost always works. I attempted it and found that it works better than my expectation! I am attaching revised core-lite.patch with this email and sending i386-lite.patch as a reply. Here is the code that extract registers of a sleeping thread: /* * Extracts ebp, esp and eip values understandable by gdb from the values * saved by switch_to. * thread.esp points to ebp. flags and ebp are pushed in switch_to hence esp * prior to entering switch_to is 8 greater then the value that is saved. * If switch_to changes, change following code appropriately. */ void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) { gdb_regs[_EAX] = 0; gdb_regs[_EBX] = 0; gdb_regs[_ECX] = 0; gdb_regs[_EDX] = 0; gdb_regs[_ESI] = 0; gdb_regs[_EDI] = 0; gdb_regs[_EBP] = *(unsigned long *)p->thread.esp; gdb_regs[_DS] = __KERNEL_DS; gdb_regs[_ES] = __KERNEL_DS; gdb_regs[_PS] = 0; gdb_regs[_CS] = __KERNEL_CS; gdb_regs[_PC] = p->thread.eip; gdb_regs[_ESP] = p->thread.esp + 8; gdb_regs[_SS] = __KERNEL_DS; gdb_regs[_FS] = 0xFFFF; gdb_regs[_GS] = 0xFFFF; } Here is the prologue for schedule 0xc0119f70 <schedule+0>: push %ebp 0xc0119f71 <schedule+1>: mov %esp,%ebp 0xc0119f73 <schedule+3>: mov $0xffffe000,%edx 0xc0119f78 <schedule+8>: push %edi 0xc0119f79 <schedule+9>: push %esi 0xc0119f7a <schedule+10>: push %ebx 0xc0119f7b <schedule+11>: sub $0x3c,%esp gdb is capable of parsing this prolog and figure out saved registers even in absence of dwarf debugging information. edi, esi, ebx and ebp are saved in standard pattern. eax, ecx and edx are call clobbered, hence not used to store locals in a function calling schedule. Hence gdb can print correct backtraces with _all_ locals even in callers of schedule!! -Amit [-- Attachment #2: core-lite.patch --] [-- Type: text/x-diff, Size: 41886 bytes --] Index: linux-2.6.4-rc2-bk3-kgdb/Makefile =================================================================== --- linux-2.6.4-rc2-bk3-kgdb.orig/Makefile 2004-03-08 14:30:27.000000000 +0530 +++ linux-2.6.4-rc2-bk3-kgdb/Makefile 2004-03-08 14:31:42.000000000 +0530 @@ -440,6 +440,8 @@ ifndef CONFIG_FRAME_POINTER CFLAGS += -fomit-frame-pointer +else +CFLAGS += -fno-omit-frame-pointer endif ifdef CONFIG_DEBUG_INFO Index: linux-2.6.4-rc2-bk3-kgdb/include/linux/debugger.h =================================================================== --- linux-2.6.4-rc2-bk3-kgdb.orig/include/linux/debugger.h 2003-01-30 15:54:37.000000000 +0530 +++ linux-2.6.4-rc2-bk3-kgdb/include/linux/debugger.h 2004-03-08 14:31:42.000000000 +0530 @@ -0,0 +1,70 @@ +#ifndef _DEBUGGER_H_ +#define _DEBUGGER_H_ + +/* + * Copyright (C) 2003-2004 Amit S. Kale + * + * Definition switchout for debuggers + */ + +/* + * KGDB + */ +#ifdef CONFIG_KGDB + +typedef int gdb_debug_hook(int exVector, int signo, int err_code, + struct pt_regs *regs); +extern gdb_debug_hook *linux_debug_hook; +#define CHK_DEBUGGER(trapnr,signr,error_code,regs,after) \ + { \ + if (linux_debug_hook != (gdb_debug_hook *) NULL && !user_mode(regs)) \ + { \ + (*linux_debug_hook)(trapnr, signr, error_code, regs) ; \ + after; \ + } \ + } + +void kgdb_nmihook(int cpu, void *regs); +static inline void debugger_nmihook(int cpu, void *regs) +{ + kgdb_nmihook(cpu, regs); +} + +void kgdb_entry(void); +static inline void debugger_entry(void) +{ + kgdb_entry(); +} + +extern int debugger_step; +extern atomic_t debugger_active; + +/* + * No debugger in the kernel + */ +#else + +#define CHK_DEBUGGER(trapnr,signr,error_code,regs,after) \ +{ \ + if (0) \ + after; \ +} + +static inline void debugger_nmihook(int cpu, void *regs) +{ + /* Do nothing */ +} + +static inline void debugger_entry(void) +{ + /* Do nothing */ +} + +#define debugger_step 0 +static const atomic_t debugger_active = { 0 }; + +#define debugger_memerr_expected 0 + +#endif + +#endif /* _DEBUGGER_H_ */ Index: linux-2.6.4-rc2-bk3-kgdb/include/linux/kgdb.h =================================================================== --- linux-2.6.4-rc2-bk3-kgdb.orig/include/linux/kgdb.h 2003-01-30 15:54:37.000000000 +0530 +++ linux-2.6.4-rc2-bk3-kgdb/include/linux/kgdb.h 2004-03-08 14:31:42.000000000 +0530 @@ -0,0 +1,128 @@ +#ifndef _KGDB_H_ +#define _KGDB_H_ + +/* + * Copyright (C) 2001-2004 Amit S. Kale + */ + +#include <linux/ptrace.h> +#include <asm/kgdb.h> +#include <linux/spinlock.h> +#include <asm/atomic.h> +#include <linux/debugger.h> + +/* + * This file should not include ANY others. This makes it usable + * most anywhere without the fear of include order or inclusion. + * TODO: Make it so! + * + * This file may be included all the time. It is only active if + * CONFIG_KGDB is defined, otherwise it stubs out all the macros + * and entry points. + */ + +#if defined(CONFIG_KGDB) && !defined(__ASSEMBLY__) +/* To enter the debugger explicitly. */ +extern void breakpoint(void); +extern void kgdb_schedule_breakpoint(void); +extern void kgdb_process_breakpoint(void); +extern volatile int kgdb_connected; + +#ifndef KGDB_MAX_NO_CPUS +#if CONFIG_NR_CPUS > 8 +#error KGDB can handle max 8 CPUs +#endif +#define KGDB_MAX_NO_CPUS 8 +#endif + +extern atomic_t kgdb_setting_breakpoint; + +extern struct task_struct *kgdb_usethread, *kgdb_contthread; + +enum kgdb_bptype { + bp_breakpoint = '0', + bp_hardware_breakpoint, + bp_write_watchpoint, + bp_read_watchpoint, + bp_access_watchpoint +}; + +enum kgdb_bpstate { + bp_disabled, + bp_enabled +}; + +struct kgdb_bkpt { + unsigned long bpt_addr; + unsigned char saved_instr[BREAK_INSTR_SIZE]; + enum kgdb_bptype type; + enum kgdb_bpstate state; +}; + +#ifndef BREAK_INSTR_SIZE +#error BREAK_INSTR_SIZE needed by kgdb +#endif + +#ifndef MAX_BREAKPOINTS +#define MAX_BREAKPOINTS 16 +#endif + +#define KGDB_HW_BREAKPOINT 1 + +/* These are functions that the arch specific code can, and in some cases + * must, provide. */ +extern int kgdb_arch_init(void); +extern void regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs); +extern void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, + struct task_struct *p); +extern void gdb_regs_to_regs(unsigned long *gdb_regs, struct pt_regs *regs); +extern void kgdb_printexceptioninfo(int exceptionNo, int errorcode, + char *buffer); +extern void kgdb_disable_hw_debug(struct pt_regs *regs); +extern void kgdb_post_master_code(struct pt_regs *regs, int eVector, + int err_code); +extern int kgdb_arch_handle_exception(int vector, int signo, int err_code, + char *InBuffer, char *outBuffer, + struct pt_regs *regs); +extern int kgdb_arch_set_break(unsigned long addr, int type); +extern int kgdb_arch_remove_break(unsigned long addr, int type); +extern void kgdb_correct_hw_break(void); +extern void kgdb_shadowinfo(struct pt_regs *regs, char *buffer, + unsigned threadid); +extern struct task_struct *kgdb_get_shadow_thread(struct pt_regs *regs, + int threadid); +extern struct pt_regs *kgdb_shadow_regs(struct pt_regs *regs, int threadid); + +struct kgdb_arch { + unsigned char gdb_bpt_instr[BREAK_INSTR_SIZE]; + unsigned long flags; + unsigned shadowth; +}; + +/* Thread reference */ +typedef unsigned char threadref[8]; + +struct kgdb_serial { + int (*read_char) (void); + void (*write_char) (int); + void (*flush) (void); + int (*hook) (void); +}; + +extern struct kgdb_serial *kgdb_serial; +extern struct kgdb_arch arch_kgdb_ops; +extern int kgdb_initialized; + +struct uart_port; + +extern void kgdb8250_add_port(int i, struct uart_port *serial_req); + +int kgdb_hex2long(char **ptr, long *longValue); +char *kgdb_mem2hex(char *mem, char *buf, int count); +char *kgdb_hex2mem(char *buf, char *mem, int count); +int kgdb_get_mem(char *addr, unsigned char *buf, int count); + +#else +#define kgdb_process_breakpoint() do {} while(0) +#endif /* KGDB && !__ASSEMBLY__ */ +#endif /* _KGDB_H_ */ Index: linux-2.6.4-rc2-bk3-kgdb/init/main.c =================================================================== --- linux-2.6.4-rc2-bk3-kgdb.orig/init/main.c 2004-03-08 14:30:27.000000000 +0530 +++ linux-2.6.4-rc2-bk3-kgdb/init/main.c 2004-03-08 14:31:42.000000000 +0530 @@ -39,6 +39,7 @@ #include <linux/writeback.h> #include <linux/cpu.h> #include <linux/efi.h> +#include <linux/debugger.h> #include <asm/io.h> #include <asm/bugs.h> @@ -581,6 +582,7 @@ smp_init(); do_basic_setup(); + debugger_entry(); prepare_namespace(); Index: linux-2.6.4-rc2-bk3-kgdb/kernel/Makefile =================================================================== --- linux-2.6.4-rc2-bk3-kgdb.orig/kernel/Makefile 2004-03-08 14:30:26.000000000 +0530 +++ linux-2.6.4-rc2-bk3-kgdb/kernel/Makefile 2004-03-08 14:31:42.000000000 +0530 @@ -19,6 +19,7 @@ obj-$(CONFIG_COMPAT) += compat.o obj-$(CONFIG_IKCONFIG) += configs.o obj-$(CONFIG_IKCONFIG_PROC) += configs.o +obj-$(CONFIG_KGDB) += kgdb.o ifneq ($(CONFIG_IA64),y) # According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is Index: linux-2.6.4-rc2-bk3-kgdb/kernel/kgdb.c =================================================================== --- linux-2.6.4-rc2-bk3-kgdb.orig/kernel/kgdb.c 2003-01-30 15:54:37.000000000 +0530 +++ linux-2.6.4-rc2-bk3-kgdb/kernel/kgdb.c 2004-03-09 14:16:45.250879088 +0530 @@ -0,0 +1,1278 @@ +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +/* + * Copyright (C) 2000-2001 VERITAS Software Corporation. + * Copyright (C) 2002-2004 Timesys Corporation + * Copyright (C) 2003-2004 Amit S. Kale + * Copyright (C) 2004 Pavel Machek <pavel@suse.cz> + * Copyright (C) 2004 Tom Rini <trini@kernel.crashing.org> + * + * Restructured KGDB for 2.6 kernels. + * thread support, support for multiple processors,support for ia-32(x86) + * hardware debugging, Console support, handling nmi watchdog + * - Amit S. Kale ( amitkale@emsyssoft.com ) + * + * Several enhancements by George Anzinger <george@mvista.com> + * Generic KGDB Support + * Implemented by Anurekh Saxena (anurekh.saxena@timesys.com) + * + * Contributor: Lake Stevens Instrument Division + * Written by: Glenn Engel + * + * Modified for 386 by Jim Kingdon, Cygnus Support. + * Origianl kgdb, compatibility with 2.1.xx kernel by David Grothe <dave@gcom.com> + * Integrated into 2.2.5 kernel by Tigran Aivazian <tigran@sco.com> + */ + +#include <linux/string.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/smp.h> +#include <linux/spinlock.h> +#include <linux/delay.h> +#include <linux/mm.h> +#include <asm/system.h> +#include <asm/ptrace.h> +#include <asm/uaccess.h> +#include <linux/kgdb.h> +#include <asm/atomic.h> +#include <linux/notifier.h> +#include <linux/module.h> +#include <asm/cacheflush.h> +#ifdef CONFIG_KGDB_CONSOLE +#include <linux/console.h> +#endif +#include <linux/init.h> + +extern int pid_max; + +#define BUF_THREAD_ID_SIZE 16 + +/* + * kgdb_initialized indicates that kgdb is setup and is all ready to serve + * breakpoints and other kernel exceptions. kgdb_connected indicates that kgdb + * has connected to kgdb. + */ +int kgdb_initialized = 0; +volatile int kgdb_connected; + +/* If non-zero, wait for a gdb connection when kgdb_entry is called */ +int kgdb_enter = 0; + +/* Set to 1 to make kgdb allow access to user addresses. Can be set from gdb + * also at runtime. */ +int kgdb_useraccess = 0; + +struct kgdb_serial *kgdb_serial; + +/* + * Holds information about breakpoints in a kernel. These breakpoints are + * added and removed by gdb. + */ +struct kgdb_bkpt kgdb_break[MAX_BREAKPOINTS]; + +struct kgdb_arch *kgdb_ops = &arch_kgdb_ops; + +static const char hexchars[] = "0123456789abcdef"; + +static spinlock_t slavecpulocks[KGDB_MAX_NO_CPUS]; +static volatile int procindebug[KGDB_MAX_NO_CPUS]; +atomic_t kgdb_setting_breakpoint; +struct task_struct *kgdb_usethread, *kgdb_contthread; + +int debugger_step; +atomic_t debugger_active; + +/* This will point to kgdb_handle_exception by default. + * The architecture code can override this in its init function + */ +gdb_debug_hook *linux_debug_hook; + +static char remcom_in_buffer[BUFMAX]; +static char remcom_out_buffer[BUFMAX]; + +/* + * The following are the stub functions for code which is arch specific + * and can be omitted on some arches + * This function will handle the initalization of any architecture specific + * hooks. If there is a suitable early output driver, kgdb_serial + * can be pointed at it now. + */ +int __attribute__ ((weak)) + kgdb_arch_init(void) +{ + return 0; +} + +void __attribute__ ((weak)) + regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) +{ +} + +void __attribute__ ((weak)) + sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) +{ +} + +void __attribute__ ((weak)) + gdb_regs_to_regs(unsigned long *gdb_regs, struct pt_regs *regs) +{ +} + +void __attribute__ ((weak)) + kgdb_printexceptioninfo(int exceptionNo, int errorcode, char *buffer) +{ +} + +void __attribute__ ((weak)) + kgdb_disable_hw_debug(struct pt_regs *regs) +{ +} + +void __attribute__ ((weak)) + kgdb_post_master_code(struct pt_regs *regs, int eVector, int err_code) +{ +} + +/* + * Handle any additional commands. This must handle the 'c' and 's' + * command packets. + * Return -1 to loop over other commands, and 0 to exit from KGDB + */ +int __attribute__ ((weak)) + kgdb_arch_handle_exception(int vector, int signo, int err_code, char *InBuffer, + char *outBuffer, struct pt_regs *regs) +{ + return 0; +} + +int __attribute__ ((weak)) + kgdb_arch_set_break(unsigned long addr, int type) +{ + return 0; +} + +int __attribute__ ((weak)) + kgdb_arch_remove_break(unsigned long addr, int type) +{ + return 0; +} + +void __attribute__ ((weak)) + kgdb_correct_hw_break(void) +{ +} + +void __attribute__ ((weak)) + kgdb_shadowinfo(struct pt_regs *regs, char *buffer, unsigned threadid) +{ +} + +struct task_struct __attribute__ ((weak)) + * kgdb_get_shadow_thread(struct pt_regs *regs, int threadid) +{ + return NULL; +} + +struct pt_regs __attribute__ ((weak)) + * kgdb_shadow_regs(struct pt_regs *regs, int threadid) +{ + return NULL; +} + +static int hex(char ch) +{ + if ((ch >= 'a') && (ch <= 'f')) + return (ch - 'a' + 10); + if ((ch >= '0') && (ch <= '9')) + return (ch - '0'); + if ((ch >= 'A') && (ch <= 'F')) + return (ch - 'A' + 10); + return (-1); +} + +/* scan for the sequence $<data>#<checksum> */ +static void get_packet(char *buffer) +{ + unsigned char checksum; + unsigned char xmitcsum; + int i; + int count; + char ch; + + do { + /* wait around for the start character, ignore all other + * characters */ + while ((ch = (kgdb_serial->read_char() & 0x7f)) != '$') + ; /* Spin. */ + kgdb_connected = 1; + checksum = 0; + xmitcsum = -1; + + count = 0; + + /* now, read until a # or end of buffer is found */ + while (count < (BUFMAX - 1)) { + ch = kgdb_serial->read_char() & 0x7f; + if (ch == '#') + break; + checksum = checksum + ch; + buffer[count] = ch; + count = count + 1; + } + buffer[count] = 0; + + if (ch == '#') { + xmitcsum = hex(kgdb_serial->read_char() & 0x7f) << 4; + xmitcsum += hex(kgdb_serial->read_char() & 0x7f); + + if (checksum != xmitcsum) + kgdb_serial->write_char('-'); /* failed checksum */ + else + kgdb_serial->write_char('+'); /* successful transfer */ + if (kgdb_serial->flush) + kgdb_serial->flush(); + } + } while (checksum != xmitcsum); +} + +/* + * Send the packet in buffer. + * Check for gdb connection if asked for. + */ +static void put_packet(char *buffer) +{ + unsigned char checksum; + int count; + char ch; + + /* $<packet info>#<checksum>. */ + while (1) { + kgdb_serial->write_char('$'); + checksum = 0; + count = 0; + + while ((ch = buffer[count])) { + kgdb_serial->write_char(ch); + checksum += ch; + count++; + } + + kgdb_serial->write_char('#'); + kgdb_serial->write_char(hexchars[checksum >> 4]); + kgdb_serial->write_char(hexchars[checksum % 16]); + if (kgdb_serial->flush) + kgdb_serial->flush(); + + /* Now see what we get in reply. */ + ch = kgdb_serial->read_char(); + + if (ch == 3) + ch = kgdb_serial->read_char(); + + /* If we get an ACK, we are done. */ + if (ch == '+') + return; + + /* If we get the start of another packet, this means + * that GDB is attempting to reconnect. We will NAK + * the packet being sent, and stop trying to send this + * packet. */ + if (ch == '$') { + kgdb_serial->write_char('-'); + if (kgdb_serial->flush) + kgdb_serial->flush(); + return; + } + } +} + +static int get_char(char *addr, unsigned char *data) +{ + mm_segment_t fs; + int ret = 0; + + if (!kgdb_useraccess && (unsigned long)addr < TASK_SIZE) { + return -EINVAL; + } + wmb(); + fs = get_fs(); + set_fs(KERNEL_DS); + + if (get_user(*data, addr) != 0) { + ret = -EFAULT; + } + + set_fs(fs); + return ret; +} + +static int set_char(char *addr, int data) +{ + mm_segment_t fs; + int ret = 0; + + if (!kgdb_useraccess && (unsigned long)addr < TASK_SIZE) { + return -EINVAL; + } + wmb(); + fs = get_fs(); + set_fs(KERNEL_DS); + + if (put_user(data, addr) != 0) { + ret = -EFAULT; + } + + set_fs(fs); + return ret; +} + +/* + * convert the memory pointed to by mem into hex, placing result in buf + * return a pointer to the last char put in buf (null). May return an error. + */ +char *kgdb_mem2hex(char *mem, char *buf, int count) +{ + int i; + unsigned char ch; + int error; + + for (i = 0; i < count; i++) { + + if ((error = get_char(mem++, &ch)) < 0) + return ERR_PTR(error); + + *buf++ = hexchars[ch >> 4]; + *buf++ = hexchars[ch % 16]; + } + *buf = 0; + return (buf); +} + +/* + * convert the hex array pointed to by buf into binary to be placed in mem + * return a pointer to the character AFTER the last byte written + * May return an error. + */ +char *kgdb_hex2mem(char *buf, char *mem, int count) +{ + int i; + unsigned char ch; + int error; + + for (i = 0; i < count; i++) { + ch = hex(*buf++) << 4; + ch = ch + hex(*buf++); + if ((error = set_char(mem++, ch)) < 0) + return ERR_PTR(error); + } + return (mem); +} + +/* + * While we find nice hex chars, build a longValue. + * Return number of chars processed. + */ +int kgdb_hex2long(char **ptr, long *longValue) +{ + int numChars = 0; + int hexValue; + + *longValue = 0; + + while (**ptr) { + hexValue = hex(**ptr); + if (hexValue >= 0) { + *longValue = (*longValue << 4) | hexValue; + numChars++; + } else + break; + + (*ptr)++; + } + + return (numChars); +} + +static inline char *pack_hex_byte(char *pkt, int byte) +{ + *pkt++ = hexchars[(byte >> 4) & 0xf]; + *pkt++ = hexchars[(byte & 0xf)]; + return pkt; +} + +static inline void error_packet(char *pkt, int error) +{ + error = -error; + pkt[0] = 'E'; + pkt[1] = hexchars[(error / 10)]; + pkt[2] = hexchars[(error % 10)]; + pkt[3] = '\0'; +} + +static char *pack_threadid(char *pkt, threadref * id) +{ + char *limit; + unsigned char *altid; + + altid = (unsigned char *)id; + limit = pkt + BUF_THREAD_ID_SIZE; + while (pkt < limit) + pkt = pack_hex_byte(pkt, *altid++); + + return pkt; +} + +void int_to_threadref(threadref * id, int value) +{ + unsigned char *scan; + + scan = (unsigned char *)id; + { + int i = 4; + while (i--) + *scan++ = 0; + } + *scan++ = (value >> 24) & 0xff; + *scan++ = (value >> 16) & 0xff; + *scan++ = (value >> 8) & 0xff; + *scan++ = (value & 0xff); +} + +static struct task_struct *getthread(struct pt_regs *regs, int tid) +{ + int i; + struct list_head *l; + struct task_struct *p; + struct pid *pid; + + if (tid >= pid_max + num_online_cpus() + kgdb_ops->shadowth) { + return NULL; + } + if (tid >= pid_max + num_online_cpus()) { + return kgdb_get_shadow_thread(regs, tid - pid_max - + num_online_cpus()); + } + if (tid >= pid_max) { + i = 0; + for_each_task_pid(0, PIDTYPE_PID, p, l, pid) { + if (tid == pid_max + i) { + return p; + } + i++; + } + return NULL; + } + if (!tid) { + return NULL; + } + return find_task_by_pid(tid); +} + +#ifdef CONFIG_SMP +void kgdb_wait(struct pt_regs *regs) +{ + unsigned long flags; + int processor; + + local_irq_save(flags); + processor = smp_processor_id(); + procindebug[processor] = 1; + current->thread.debuggerinfo = regs; + + /* Wait till master processor goes completely into the debugger. + * FIXME: this looks racy */ + while (!procindebug[atomic_read(&debugger_active) - 1]) { + int i = 10; /* an arbitrary number */ + + while (--i) + asm volatile ("nop":::"memory"); + barrier(); + } + + /* Wait till master processor is done with debugging */ + spin_lock(slavecpulocks + processor); + + /* This has been taken from x86 kgdb implementation and + * will be needed by architectures that have SMP support + */ + kgdb_correct_hw_break(); + + current->thread.debuggerinfo = NULL; + + /* Signal the master processor that we are done */ + procindebug[processor] = 0; + spin_unlock(slavecpulocks + processor); + local_irq_restore(flags); +} +#endif + +int kgdb_get_mem(char *addr, unsigned char *buf, int count) +{ + int error; + while (count) { + if ((error = get_char(addr++, buf)) < 0) + return error; + buf++; + count--; + } + return 0; +} + +static int set_mem(char *addr, unsigned char *buf, int count) +{ + int error; + while (count) { + if ((error = set_char(addr++, *buf++)) < 0) + return error; + count--; + } + return 0; +} + +static int set_break(unsigned long addr) +{ + int i, breakno = -1; + int error; + + for (i = 0; i < MAX_BREAKPOINTS; i++) { + if ((kgdb_break[i].state == bp_enabled) && + (kgdb_break[i].bpt_addr == addr)) { + return -EEXIST; + } + + if (kgdb_break[i].state == bp_disabled) { + if ((breakno == -1) || (kgdb_break[i].bpt_addr == addr)) + breakno = i; + } + } + if (breakno == -1) + return -E2BIG; + + if ((error = kgdb_get_mem((char *)addr, kgdb_break[breakno].saved_instr, + BREAK_INSTR_SIZE)) < 0) + return error; + + if ((error = set_mem((char *)addr, kgdb_ops->gdb_bpt_instr, + BREAK_INSTR_SIZE)) < 0) + return error; + flush_cache_range(current->mm, addr, addr + BREAK_INSTR_SIZE); + flush_icache_range(addr, addr + BREAK_INSTR_SIZE); + + kgdb_break[breakno].state = bp_enabled; + kgdb_break[breakno].type = bp_breakpoint; + kgdb_break[breakno].bpt_addr = addr; + + return 0; +} + +static int remove_break(unsigned long addr) +{ + int i; + int error; + + for (i = 0; i < MAX_BREAKPOINTS; i++) { + if ((kgdb_break[i].state == bp_enabled) && + (kgdb_break[i].bpt_addr == addr)) { + if ((error = + set_mem((char *)addr, kgdb_break[i].saved_instr, + BREAK_INSTR_SIZE)) < 0) + return error; + flush_cache_range(current->mm, addr, + addr + BREAK_INSTR_SIZE); + flush_icache_range(addr, addr + BREAK_INSTR_SIZE); + kgdb_break[i].state = bp_disabled; + return 0; + } + } + return -ENOENT; +} + +int remove_all_break(void) +{ + int i; + int error; + for (i = 0; i < MAX_BREAKPOINTS; i++) { + if (kgdb_break[i].state == bp_enabled) { + unsigned long addr = kgdb_break[i].bpt_addr; + if ((error = + set_mem((char *)addr, kgdb_break[i].saved_instr, + BREAK_INSTR_SIZE)) < 0) + return error; + flush_cache_range(current->mm, addr, + addr + BREAK_INSTR_SIZE); + flush_icache_range(addr, addr + BREAK_INSTR_SIZE); + } + kgdb_break[i].state = bp_disabled; + } + return 0; +} + +static inline int shadow_pid(int realpid) +{ + if (realpid) { + return realpid; + } + return pid_max + smp_processor_id(); +} + +/* + * This function does all command procesing for interfacing to gdb. + * + * Locking hierarchy: + * interface locks, if any (begin_session) + * kgdb lock (debugger_active) + * + */ +int kgdb_handle_exception(int exVector, int signo, int err_code, + struct pt_regs *linux_regs) +{ + unsigned long length, addr; + char *ptr; + unsigned long flags; + unsigned long gdb_regs[NUMREGBYTES / sizeof(unsigned long)]; + int i; + long threadid; + threadref thref; + struct task_struct *thread = NULL; + unsigned procid; + static char tmpstr[256]; + int numshadowth = num_online_cpus() + kgdb_ops->shadowth; + long kgdb_usethreadid = 0; + int error = 0; + struct pt_regs *shadowregs; + + /* Panic on recursive debugger calls. */ + if (atomic_read(&debugger_active) == smp_processor_id() + 1) { + return 0; + } + + /* + * Interrupts will be restored by the 'trap return' code, except when + * single stepping. + */ + local_irq_save(flags); + + /* Hold debugger_active */ + procid = smp_processor_id(); + while (cmpxchg(&atomic_read(&debugger_active), 0, (procid + 1)) != 0) { + int i = 25; /* an arbitrary number */ + + while (--i) + asm volatile ("nop":::"memory"); + } + + debugger_step = 0; + + current->thread.debuggerinfo = linux_regs; + + kgdb_disable_hw_debug(linux_regs); + + for (i = 0; i < num_online_cpus(); i++) { + spin_lock(&slavecpulocks[i]); + } + + /* spin_lock code is good enough as a barrier so we don't + * need one here */ + procindebug[smp_processor_id()] = 1; + + /* Clear the out buffer. */ + memset(remcom_out_buffer, 0, sizeof(remcom_out_buffer)); + + /* Master processor is completely in the debugger */ + kgdb_post_master_code(linux_regs, exVector, err_code); + + if (kgdb_connected) { + /* reply to host that an exception has occurred */ + ptr = remcom_out_buffer; + *ptr++ = 'T'; + *ptr++ = hexchars[(signo >> 4) % 16]; + *ptr++ = hexchars[signo % 16]; + ptr += strlen(strcpy(ptr, "thread:")); + int_to_threadref(&thref, shadow_pid(current->pid)); + ptr = pack_threadid(ptr, &thref); + *ptr++ = ';'; + + put_packet(remcom_out_buffer); + } + + kgdb_usethread = current; + kgdb_usethreadid = shadow_pid(current->pid); + + while (1) { + int bpt_type = 0; + error = 0; + + /* Clear the out buffer. */ + memset(remcom_out_buffer, 0, sizeof(remcom_out_buffer)); + + get_packet(remcom_in_buffer); + + switch (remcom_in_buffer[0]) { + case '?': + /* We know that this packet is only sent + * during initial connect. So to be safe, + * we clear out our breakpoints now incase + * GDB is reconnecting. */ + remove_all_break(); + remcom_out_buffer[0] = 'S'; + remcom_out_buffer[1] = hexchars[signo >> 4]; + remcom_out_buffer[2] = hexchars[signo % 16]; + break; + + case 'g': /* return the value of the CPU registers */ + thread = kgdb_usethread; + + if (!thread) + thread = current; + + /* All threads that don't have debuggerinfo should be + in __schedule() sleeping, since all other CPUs + are in kgdb_wait, and thus have debuggerinfo. */ + + if (kgdb_usethreadid >= pid_max + num_online_cpus()) { + shadowregs = kgdb_shadow_regs(linux_regs, + kgdb_usethreadid - + pid_max - + num_online_cpus + ()); + if (!shadowregs) { + error_packet(remcom_out_buffer, + -EINVAL); + break; + } + regs_to_gdb_regs(gdb_regs, shadowregs); + } else if (thread->thread.debuggerinfo) { + if ((error = + get_char(thread->thread.debuggerinfo, + (unsigned char *)gdb_regs)) < 0) { + error_packet(remcom_out_buffer, error); + break; + } + regs_to_gdb_regs(gdb_regs, (struct pt_regs *) + thread->thread.debuggerinfo); + } else { + /* Pull stuff saved during + * switch_to; nothing else is + * accessible (or even particularly relevant). + * This should be enough for a stack trace. */ + sleeping_thread_to_gdb_regs(gdb_regs, thread); + } + + kgdb_mem2hex((char *)gdb_regs, remcom_out_buffer, + NUMREGBYTES); + break; + + case 'G': /* set the value of the CPU registers - return OK */ + kgdb_hex2mem(&remcom_in_buffer[1], (char *)gdb_regs, + NUMREGBYTES); + + if (kgdb_usethread && kgdb_usethread != current) + error_packet(remcom_out_buffer, -EINVAL); + else { + gdb_regs_to_regs(gdb_regs, (struct pt_regs *) + current->thread.debuggerinfo); + strcpy(remcom_out_buffer, "OK"); + } + + break; + + /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */ + case 'm': + ptr = &remcom_in_buffer[1]; + if (kgdb_hex2long(&ptr, &addr) > 0 && *ptr++ == ',' && + kgdb_hex2long(&ptr, &length) > 0) { + if (IS_ERR(ptr = kgdb_mem2hex((char *)addr, + remcom_out_buffer, + length))) + error_packet(remcom_out_buffer, + PTR_ERR(ptr)); + } else + error_packet(remcom_out_buffer, -EINVAL); + break; + + /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */ + case 'M': + ptr = &remcom_in_buffer[1]; + if (kgdb_hex2long(&ptr, &addr) > 0 && *(ptr++) == ',' + && kgdb_hex2long(&ptr, &length) > 0 && + *(ptr++) == ':') { + if (IS_ERR(ptr = kgdb_hex2mem(ptr, (char *)addr, + length))) + error_packet(remcom_out_buffer, + PTR_ERR(ptr)); + } else + error_packet(remcom_out_buffer, -EINVAL); + break; + + /* kill or detach. KGDB should treat this like a + * continue. + */ + case 'D': + if ((error = remove_all_break()) < 0) { + error_packet(remcom_out_buffer, error); + } else { + strcpy(remcom_out_buffer, "OK"); + kgdb_connected = 0; + } + put_packet(remcom_out_buffer); + goto default_handle; + + case 'k': + /* Don't care about error from remove_all_break */ + remove_all_break(); + kgdb_connected = 0; + goto default_handle; + + /* query */ + case 'q': + switch (remcom_in_buffer[1]) { + case 's': + case 'f': + if (memcmp + (remcom_in_buffer + 2, "ThreadInfo", 10)) { + error_packet(remcom_out_buffer, + -EINVAL); + break; + } + if (remcom_in_buffer[1] == 'f') { + threadid = 1; + } + remcom_out_buffer[0] = 'm'; + ptr = remcom_out_buffer + 1; + for (i = 0; i < 32 && threadid < pid_max + + numshadowth; threadid++) { + thread = getthread(linux_regs, + threadid); + if (thread) { + int_to_threadref(&thref, + threadid); + pack_threadid(ptr, &thref); + ptr += 16; + *(ptr++) = ','; + i++; + } + } + *(--ptr) = '\0'; + break; + + case 'C': + /* Current thread id */ + strcpy(remcom_out_buffer, "QC"); + + threadid = shadow_pid(current->pid); + + int_to_threadref(&thref, threadid); + pack_threadid(remcom_out_buffer + 2, &thref); + break; + + case 'E': + /* Print exception info */ + kgdb_printexceptioninfo(exVector, err_code, + remcom_out_buffer); + break; + case 'T': + if (memcmp(remcom_in_buffer + 1, + "ThreadExtraInfo,", 16)) { + error_packet(remcom_out_buffer, + -EINVAL); + break; + } + threadid = 0; + ptr = remcom_in_buffer + 17; + kgdb_hex2long(&ptr, &threadid); + if (!getthread(linux_regs, threadid)) { + error_packet(remcom_out_buffer, + -EINVAL); + break; + } + if (threadid < pid_max) { + kgdb_mem2hex(getthread(linux_regs, + threadid)->comm, + remcom_out_buffer, 16); + } else if (threadid >= pid_max + + num_online_cpus()) { + kgdb_shadowinfo(linux_regs, + remcom_out_buffer, + threadid - pid_max - + num_online_cpus()); + } else { + sprintf(tmpstr, "Shadow task %d" + " for pid 0", + (int)(threadid - pid_max)); + kgdb_mem2hex(tmpstr, remcom_out_buffer, + strlen(tmpstr)); + } + break; + } + break; + + /* task related */ + case 'H': + switch (remcom_in_buffer[1]) { + case 'g': + ptr = &remcom_in_buffer[2]; + kgdb_hex2long(&ptr, &threadid); + thread = getthread(linux_regs, threadid); + if (!thread && threadid > 0) { + error_packet(remcom_out_buffer, + -EINVAL); + break; + } + kgdb_usethread = thread; + kgdb_usethreadid = threadid; + strcpy(remcom_out_buffer, "OK"); + break; + + case 'c': + ptr = &remcom_in_buffer[2]; + kgdb_hex2long(&ptr, &threadid); + if (!threadid) { + kgdb_contthread = 0; + } else { + thread = + getthread(linux_regs, threadid); + if (!thread && threadid > 0) { + error_packet(remcom_out_buffer, + -EINVAL); + break; + } + kgdb_contthread = thread; + } + strcpy(remcom_out_buffer, "OK"); + break; + } + break; + + /* Query thread status */ + case 'T': + ptr = &remcom_in_buffer[1]; + kgdb_hex2long(&ptr, &threadid); + thread = getthread(linux_regs, threadid); + if (thread) + strcpy(remcom_out_buffer, "OK"); + else + error_packet(remcom_out_buffer, -EINVAL); + break; + case 'z': + case 'Z': + ptr = &remcom_in_buffer[2]; + if (*(ptr++) != ',') { + error_packet(remcom_out_buffer, -EINVAL); + break; + } + kgdb_hex2long(&ptr, &addr); + + bpt_type = remcom_in_buffer[1]; + if (bpt_type != bp_breakpoint) { + if (bpt_type == bp_hardware_breakpoint && + !(kgdb_ops->flags & KGDB_HW_BREAKPOINT)) + break; + + /* if set_break is not defined, then + * remove_break does not matter + */ + if (!(kgdb_ops->flags & KGDB_HW_BREAKPOINT)) + break; + } + + if (remcom_in_buffer[0] == 'Z') { + if (bpt_type == bp_breakpoint) + error = set_break(addr); + else + error = kgdb_arch_set_break(addr, + bpt_type); + } else { + if (bpt_type == bp_breakpoint) + error = remove_break(addr); + else + error = kgdb_arch_remove_break(addr, + bpt_type); + } + + if (error == 0) + strcpy(remcom_out_buffer, "OK"); + else + error_packet(remcom_out_buffer, error); + + break; + + default: + default_handle: + error = kgdb_arch_handle_exception(exVector, signo, + err_code, + remcom_in_buffer, + remcom_out_buffer, + linux_regs); + + if (error >= 0 || remcom_in_buffer[0] == 'D' || + remcom_in_buffer[0] == 'k') + goto kgdb_exit; + + } /* switch */ + + /* reply to the request */ + put_packet(remcom_out_buffer); + } + + kgdb_exit: + current->thread.debuggerinfo = NULL; + procindebug[smp_processor_id()] = 0; + + for (i = 0; i < num_online_cpus(); i++) { + spin_unlock(&slavecpulocks[i]); + } + /* Wait till all the processors have quit + * from the debugger + */ + for (i = 0; i < num_online_cpus(); i++) { + while (procindebug[i]) { + int j = 10; /* an arbitrary number */ + + while (--j) { + asm volatile ("nop":::"memory"); + } + barrier(); + } + } + + /* Free debugger_active */ + atomic_set(&debugger_active, 0); + local_irq_restore(flags); + + return error; +} + +/* + * GDB places a breakpoint at this function to know dynamically + * loaded objects. It's not defined static so that only one instance with this + * name exists in the kernel. + */ + +int module_event(struct notifier_block *self, unsigned long val, void *data) +{ + return 0; +} + +static struct notifier_block kgdb_module_load_nb = { + .notifier_call = module_event, +}; + +/* This function will generate a breakpoint exception. It is used at the + beginning of a program to sync up with a debugger and can be used + otherwise as a quick means to stop program execution and "break" into + the debugger. */ + +void breakpoint(void) +{ + if (!kgdb_initialized) { + kgdb_enter = 1; + kgdb_entry(); + if (!kgdb_initialized) { + printk("kgdb not enabled. Cannot do breakpoint\n"); + return; + } + } + + atomic_set(&kgdb_setting_breakpoint, 1); + wmb(); + BREAKPOINT(); + wmb(); + atomic_set(&kgdb_setting_breakpoint, 0); +} + +void kgdb_nmihook(int cpu, void *regs) +{ +#ifdef CONFIG_SMP + if (!procindebug[cpu] && atomic_read(&debugger_active) != (cpu + 1)) { + kgdb_wait((struct pt_regs *)regs); + } +#endif +} + +void kgdb_entry(void) +{ + int i; + + if (kgdb_initialized) { + /* KGDB was initialized */ + return; + } + + for (i = 0; i < KGDB_MAX_NO_CPUS; i++) + spin_lock_init(&slavecpulocks[i]); + + /* Free debugger_active */ + atomic_set(&debugger_active, 0); + + for (i = 0; i < MAX_BREAKPOINTS; i++) + kgdb_break[i].state = bp_disabled; + + linux_debug_hook = kgdb_handle_exception; + + /* Let the arch do any initalization it needs to, including + * pointing to a suitable early output device. */ + kgdb_arch_init(); + + /* We can't do much if this fails */ + register_module_notifier(&kgdb_module_load_nb); + + atomic_set(&kgdb_setting_breakpoint, 0); + + if (!kgdb_serial || kgdb_serial->hook() < 0) { + /* KGDB interface isn't ready yet */ + return; + } + kgdb_initialized = 1; + if (!kgdb_enter) { + return; + } + /* + * Call the breakpoint() routine in GDB to start the debugging + * session + */ + printk(KERN_CRIT "Waiting for connection from remote gdb... "); + breakpoint(); + printk("Connected.\n"); +} + +/* + * Sometimes we need to schedule a breakpoint because we can't break + * right where we are. + */ +static int kgdb_need_breakpoint[NR_CPUS]; + +void kgdb_schedule_breakpoint(void) +{ + kgdb_need_breakpoint[smp_processor_id()] = 1; +} + +void kgdb_process_breakpoint(void) +{ + /* + * Handle a breakpoint queued from inside network driver code + * to avoid reentrancy issues + */ + if (kgdb_need_breakpoint[smp_processor_id()]) { + kgdb_need_breakpoint[smp_processor_id()] = 0; + breakpoint(); + } +} + +#ifdef CONFIG_KGDB_CONSOLE +char kgdbconbuf[BUFMAX]; + +void kgdb_console_write(struct console *co, const char *s, unsigned count) +{ + int i; + int wcount; + char *bufptr; + unsigned long flags; + + if (!kgdb_connected) { + return; + } + local_irq_save(flags); + + kgdbconbuf[0] = 'O'; + bufptr = kgdbconbuf + 1; + while (count > 0) { + if ((count << 1) > (BUFMAX - 2)) { + wcount = (BUFMAX - 2) >> 1; + } else { + wcount = count; + } + count -= wcount; + for (i = 0; i < wcount; i++) { + bufptr = pack_hex_byte(bufptr, s[i]); + } + *bufptr = '\0'; + s += wcount; + + put_packet(kgdbconbuf); + + } + local_irq_restore(flags); +} + +/* Always fail so that kgdb console doesn't become the default console */ +static int __init kgdb_console_setup(struct console *co, char *options) +{ + return -1; +} + +static struct console kgdbcons = { + .name = "kgdb", + .write = kgdb_console_write, + .setup = kgdb_console_setup, + .flags = CON_PRINTBUFFER | CON_ENABLED, + .index = -1, +}; + +static int __init kgdb_console_init(void) +{ + register_console(&kgdbcons); + return 0; +} + +console_initcall(kgdb_console_init); +#endif + +EXPORT_SYMBOL(breakpoint); +#ifdef CONFIG_KGDB_THREAD +EXPORT_SYMBOL(kern_schedule); +#endif + +static int __init opt_kgdb_enter(char *str) +{ + kgdb_enter = 1; + return 1; +} + +static int __init opt_gdb(char *str) +{ + kgdb_enter = 1; + return 1; +} + +/* + * These options have been deprecated and are present only to maintain + * compatibility with kgdb for 2.4 and earlier kernels. + */ +#ifdef CONFIG_KGDB_8250 +extern int kgdb8250_baud; +extern int kgdb8250_ttyS; +static int __init opt_gdbttyS(char *str) +{ + kgdb8250_ttyS = simple_strtoul(str, NULL, 10); + return 1; +} +static int __init opt_gdbbaud(char *str) +{ + kgdb8250_baud = simple_strtoul(str, NULL, 10); + return 1; +} +#endif + +/* + * + * Sequence of following lines has to be maintained because gdb option is a + * prefix of the other two options + */ + +#ifdef CONFIG_KGDB_8250 +__setup("gdbttyS=", opt_gdbttyS); +__setup("gdbbaud=", opt_gdbbaud); +#endif +__setup("gdb", opt_gdb); +__setup("kgdbwait", opt_kgdb_enter); Index: linux-2.6.4-rc2-bk3-kgdb/kernel/sched.c =================================================================== --- linux-2.6.4-rc2-bk3-kgdb.orig/kernel/sched.c 2004-03-08 14:30:26.000000000 +0530 +++ linux-2.6.4-rc2-bk3-kgdb/kernel/sched.c 2004-03-08 14:31:42.000000000 +0530 @@ -37,6 +37,7 @@ #include <linux/rcupdate.h> #include <linux/cpu.h> #include <linux/percpu.h> +#include <linux/debugger.h> #ifdef CONFIG_NUMA #define cpu_to_node_mask(cpu) node_to_cpumask(cpu_to_node(cpu)) @@ -2961,6 +2962,8 @@ #if defined(in_atomic) static unsigned long prev_jiffy; /* ratelimiting */ + if (atomic_read(&debugger_active)) + return; if ((in_atomic() || irqs_disabled()) && system_running) { if (time_before(jiffies, prev_jiffy + HZ) && prev_jiffy) return; Index: linux-2.6.4-rc2-bk3-kgdb/kernel/Kconfig.kgdb =================================================================== --- linux-2.6.4-rc2-bk3-kgdb.orig/kernel/Kconfig.kgdb 2003-01-30 15:54:37.000000000 +0530 +++ linux-2.6.4-rc2-bk3-kgdb/kernel/Kconfig.kgdb 2004-03-08 14:31:42.000000000 +0530 @@ -0,0 +1,13 @@ +config KGDB + bool "KGDB: kernel debugging with remote gdb" + depends on DEBUG_KERNEL + select DEBUG_INFO + select FRAME_POINTER + help + If you say Y here, it will be possible to remotely debug the + kernel using gdb. This enlarges your kernel image disk size by + several megabytes and requires a machine with more than 128 MB + RAM to avoid excessive linking time. + Documentation of kernel debugger available at + http://kgdb.sourceforge.net + This is only useful for kernel hackers. If unsure, say N. Index: linux-2.6.4-rc2-bk3-kgdb/Documentation/kgdb.txt =================================================================== --- linux-2.6.4-rc2-bk3-kgdb.orig/Documentation/kgdb.txt 2003-01-30 15:54:37.000000000 +0530 +++ linux-2.6.4-rc2-bk3-kgdb/Documentation/kgdb.txt 2004-03-08 14:31:42.000000000 +0530 @@ -0,0 +1,49 @@ +KGDB Linux kernel source level debugger + +Amit S. Kale <amitkale@emsyssoft.com> +Last updated March 2004. + +Introduction: +kgdb is a source level debugger for linux kernel. It is used along with gdb to +debug a linux kernel. Kernel developers can debug a kernel similar to +application programs with the use of kgdb. It makes it possible to place +breakpoints in kernel code, step through the code and observe variables. + +Two machines are required for using kgdb. One of these machines is a +development machine and the other is a test machine. The machines are +connected through a serial line, a null-modem cable which connects their +serial ports. The kernel to be debugged runs on the test machine. gdb runs on +the development machine. The serial line is used by gdb to communicate to the +kernel being debugged. + +This version of kgdb is a lite version. It is available on i386 platform uses +a serial line for communicating to gdb. Full kgdb containing more features and +supporting more architecture is available along with plenty of documentation +at http://kgdb.sourceforge.net/ + +Compiling a kernel: +Enable Kernel hacking -> Kernel Debugging -> KGDB: kernel debugging with +remote gdb + +Only generic serial port (8250) is supported in the lite version. Configure +8250 options. + +Booting the kernel: +Kernel command line option "kgdbwait" makes kgdb wait for gdb connection +during booting of a kernel. If you have configured simple serial port, the +port number and speed can be overriden on command line by using option +"kgdb8250=portnumber,speed", where port numbers are 0-3 for COM1 to COM4 +respectively and supported speeds are 9600, 19200, 38400, 57600, 115200. +Example: kgdbwait kgdb8250=0,115200 + +Connecting gdb: +If you have used "kgdbwait", kgdb prints a message "Waiting for connection +from remote gdb..." on the console and waits for connection from gdb. At this +point you connect gdb to kgdb. +Example: + % gdb ./vmlinux + (gdb) set remotebaud 115200 + (gdb) target remote /dev/ttyS0 + +Once connected, you can debug a kernel the way you would debug an application +program. ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: kgdb for mainline kernel: core-lite [patch 1/3] 2004-03-09 9:29 ` Amit S. Kale @ 2004-03-09 15:06 ` Tom Rini 2004-03-10 4:05 ` Amit S. Kale 0 siblings, 1 reply; 35+ messages in thread From: Tom Rini @ 2004-03-09 15:06 UTC (permalink / raw) To: Amit S. Kale; +Cc: Andrew Morton, linux-kernel, george, pavel On Tue, Mar 09, 2004 at 02:59:54PM +0530, Amit S. Kale wrote: [snip] > I attempted it and found that it works better than my expectation! I am > attaching revised core-lite.patch with this email and sending i386-lite.patch > as a reply. [snip] > Index: linux-2.6.4-rc2-bk3-kgdb/include/linux/kgdb.h [snip] > +#ifndef KGDB_MAX_NO_CPUS > +#if CONFIG_NR_CPUS > 8 > +#error KGDB can handle max 8 CPUs > +#endif > +#define KGDB_MAX_NO_CPUS 8 > +#endif We need to remove all of that in favor of s/KGDB_MAX_NO_CPUS/NR_CPUS/g, and remove the check on 8. -- Tom Rini http://gate.crashing.org/~trini/ ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: kgdb for mainline kernel: core-lite [patch 1/3] 2004-03-09 15:06 ` Tom Rini @ 2004-03-10 4:05 ` Amit S. Kale 0 siblings, 0 replies; 35+ messages in thread From: Amit S. Kale @ 2004-03-10 4:05 UTC (permalink / raw) To: Tom Rini; +Cc: Andrew Morton, linux-kernel, george, pavel On Tuesday 09 Mar 2004 8:36 pm, Tom Rini wrote: > On Tue, Mar 09, 2004 at 02:59:54PM +0530, Amit S. Kale wrote: > [snip] > > > I attempted it and found that it works better than my expectation! I am > > attaching revised core-lite.patch with this email and sending > > i386-lite.patch as a reply. > > [snip] > > > Index: linux-2.6.4-rc2-bk3-kgdb/include/linux/kgdb.h > > [snip] > > > +#ifndef KGDB_MAX_NO_CPUS > > +#if CONFIG_NR_CPUS > 8 > > +#error KGDB can handle max 8 CPUs > > +#endif > > +#define KGDB_MAX_NO_CPUS 8 > > +#endif > > We need to remove all of that in favor of s/KGDB_MAX_NO_CPUS/NR_CPUS/g, > and remove the check on 8. Yes. I'll do that. -Amit ^ permalink raw reply [flat|nested] 35+ messages in thread
end of thread, other threads:[~2004-03-11 5:11 UTC | newest]
Thread overview: 35+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <1xpyM-2Op-21@gated-at.bofh.it>
[not found] ` <1xqXN-44F-13@gated-at.bofh.it>
[not found] ` <1xr7w-4c4-9@gated-at.bofh.it>
[not found] ` <1xrqW-4rh-51@gated-at.bofh.it>
[not found] ` <1xuS8-83Q-11@gated-at.bofh.it>
2004-03-08 16:57 ` kgdb for mainline kernel: core-lite [patch 1/3] Andi Kleen
2004-03-08 17:18 ` Tom Rini
2004-03-09 4:29 ` Amit S. Kale
2004-03-09 4:36 ` Amit S. Kale
2004-03-10 12:36 ` Andi Kleen
2004-03-10 15:27 ` Tom Rini
2004-03-11 4:57 ` Amit S. Kale
2004-03-11 5:05 ` Randy.Dunlap
2004-03-11 5:11 ` Andi Kleen
2004-03-08 9:39 Amit S. Kale
2004-03-08 9:54 ` Andrew Morton
2004-03-08 10:15 ` Amit S. Kale
2004-03-08 10:26 ` Andrew Morton
2004-03-08 10:49 ` Amit S. Kale
2004-03-08 11:07 ` Andrew Morton
2004-03-08 11:20 ` Amit S. Kale
2004-03-08 11:44 ` Amit S. Kale
2004-03-08 11:54 ` Andrew Morton
2004-03-08 12:00 ` Amit S. Kale
2004-03-08 15:19 ` Tom Rini
2004-03-08 22:26 ` George Anzinger
2004-03-09 8:58 ` Amit S. Kale
2004-03-08 22:19 ` George Anzinger
2004-03-09 5:08 ` Amit S. Kale
2004-03-09 15:37 ` Tom Rini
2004-03-08 11:48 ` Andrew Morton
2004-03-08 22:21 ` George Anzinger
2004-03-08 15:22 ` Tom Rini
2004-03-08 16:32 ` Amit S. Kale
2004-03-08 22:29 ` George Anzinger
2004-03-08 22:15 ` George Anzinger
2004-03-09 4:46 ` Amit S. Kale
2004-03-09 9:29 ` Amit S. Kale
2004-03-09 15:06 ` Tom Rini
2004-03-10 4:05 ` Amit S. Kale
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox