Skip to contentSkip to conversation

kgdb for 2.6.3

PATCH In review Pavel Machek 1 participant 1 message Feb 22, 2004 Scheduler

lore
Share & tools
lore
#0 lore raw

PATCH 2/3 kgdb for 2.6.3

Hi!

This adds some more intrusive features to kgdb (thread display, kgdb-over-netconsole), and support for non-i386 architectures (core + i386 + x86_64 + ppc). Probably good enough for -mm but not for vanilla.

Pavel

include/linux/sched.h +12 -1
Index: linux-2.6.3-kgdb-lite/include/linux/sched.h
===================================================================
@@ -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
+}
+
 #endif /* __KERNEL__ */
 
 #endif
kernel/module.c +10 -0
Index: linux-2.6.3-kgdb-lite/kernel/module.c
===================================================================
@@ -727,6 +727,11 @@
 	mod->state = MODULE_STATE_GOING;
 	restart_refcounts();
 
+	down(&notify_mutex);
+	notifier_call_chain(&module_notify_list, MODULE_STATE_GOING,
+				mod);
+	up(&notify_mutex);
+
 	/* Never wait if forced. */
 	if (!forced && module_refcount(mod) != 0)
 		wait_for_zero_refcount(mod);
@@ -1758,7 +1763,12 @@
 	if (ret < 0) {
 		/* Init routine failed: abort.  Try to protect us from
                    buggy refcounters. */
+
 		mod->state = MODULE_STATE_GOING;
+		down(&notify_mutex);
+		notifier_call_chain(&module_notify_list, MODULE_STATE_GOING,
+					mod);
+		up(&notify_mutex);
 		synchronize_kernel();
 		if (mod->unsafe)
 			printk(KERN_ERR "%s: module is now stuck!\n",
kernel/sched.c +18 -1
Index: linux-2.6.3-kgdb-lite/kernel/sched.c
===================================================================
@@ -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 = &regs;
+	do_schedule();
+	current->thread.debuggerinfo = NULL;
+}
+#endif
+
 /*
  * The core wakeup function.  Non-exclusive wakeups (nr_exclusive == 0) just
  * wake everything up.  If it's an exclusive wakeup (nr_exclusive == small +ve
arch/i386/Kconfig +17 -0
Index: linux-2.6.3-kgdb/arch/i386/Kconfig
===================================================================
@@ -1267,6 +1267,23 @@
 	  http://kgdb.sourceforge.net
 	  This is only useful for kernel hackers. If unsure, say N.
 
+config KGDB_THREAD
+	bool "KGDB: Thread analysis"
+	depends on KGDB
+	help
+	  With thread analysis enabled, gdb can talk to kgdb stub to list
+	  threads and to get stack trace for a thread. This option also enables
+	  some code which helps gdb get exact status of thread. Thread analysis
+	  adds some overhead to schedule and down functions. You can disable
+	  this option if you do not want to compromise on speed.
+
+config KGDB_CONSOLE
+	bool "KGDB: Console messages through gdb"
+	depends on KGDB
+	help
+	  If you say Y here, console messages will appear through gdb.
+	  Other consoles such as tty or ttyS will continue to work as usual.
+
 config FRAME_POINTER
 	bool "Compile the kernel with frame pointers"
 	help
arch/i386/kernel/entry.S +27 -2
Index: linux-2.6.3-kgdb/arch/i386/kernel/entry.S
===================================================================
@@ -226,7 +226,7 @@
 	jz restore_all
 	movl $PREEMPT_ACTIVE,TI_PRE_COUNT(%ebp)
 	sti
-	call schedule
+	call user_schedule
 	movl $0,TI_PRE_COUNT(%ebp)
 	cli
 	jmp need_resched
@@ -308,7 +308,7 @@
 	testb $_TIF_NEED_RESCHED, %cl
 	jz work_notifysig
 work_resched:
-	call schedule
+	call user_schedule
 	cli				# make sure we don't miss an interrupt
 					# setting need_resched or sigpending
 					# between sampling and the iret
@@ -606,6 +606,31 @@
 	pushl $do_spurious_interrupt_bug
 	jmp error_code
 
+#ifdef CONFIG_KGDB_THREAD
+ENTRY(kern_schedule)
+	pushl	%ebp
+	movl	%esp, %ebp
+	pushl	%ss		
+	pushl	%ebp
+	pushfl
+	pushl	%cs
+	pushl	4(%ebp)
+	pushl	%eax		
+	pushl	%es
+	pushl	%ds
+	pushl	%eax
+	pushl	(%ebp)
+	pushl	%edi
+	pushl	%esi
+	pushl	%edx
+	pushl	%ecx
+	pushl	%ebx
+	call	kern_do_schedule
+	movl	%ebp, %esp
+	pop	%ebp
+	ret
+#endif
+
 .data
 ENTRY(sys_call_table)
 	.long sys_restart_syscall	/* 0 - old "setup()" system call, used for restarting */
arch/x86_64/Kconfig +30 -2
Index: linux-2.6.3-kgdb/arch/x86_64/Kconfig
===================================================================
@@ -465,8 +465,36 @@
          Add a simple leak tracer to the IOMMU code. This is useful when you
 	 are debugging a buggy device driver that leaks IOMMU mappings.
        
-#config X86_REMOTE_DEBUG
-#       bool "kgdb debugging stub"
+config KGDB
+	bool "KGDB: kernel debugging with remote gdb"
+	depends on DEBUG_KERNEL
+	select DEBUG_INFO
+	select FRAME_POINTER
+	help
+	  If you say Y here, it will be possible to remotely debug the
+	  kernel using gdb. This enlarges your kernel image disk size by
+	  several megabytes and requires a machine with more than 128 MB
+	  RAM to avoid excessive linking time. 
+	  Documentation of kernel debugger available at
+	  http://kgdb.sourceforge.net
+	  This is only useful for kernel hackers. If unsure, say N.
+
+config KGDB_THREAD
+	bool "KGDB: Thread analysis"
+	depends on KGDB
+	help
+	  With thread analysis enabled, gdb can talk to kgdb stub to list
+	  threads and to get stack trace for a thread. This option also enables
+	  some code which helps gdb get exact status of thread. Thread analysis
+	  adds some overhead to schedule and down functions. You can disable
+	  this option if you do not want to compromise on speed.
+
+config KGDB_CONSOLE
+	bool "KGDB: Console messages through gdb"
+	depends on KGDB
+	help
+	  If you say Y here, console messages will appear through gdb.
+	  Other consoles such as tty or ttyS will continue to work as usual.
 
 endmenu
 
arch/x86_64/kernel/entry.S +38 -3

62 lines not on this page · raw message

arch/x86_64/kernel/Makefile +1 -0
Index: linux-2.6.3-kgdb/arch/x86_64/kernel/Makefile
===================================================================
@@ -24,6 +24,7 @@
 obj-$(CONFIG_DUMMY_IOMMU)	+= pci-nommu.o pci-dma.o
 
 obj-$(CONFIG_MODULES)		+= module.o
+obj-$(CONFIG_KGDB)		+= x86_64-stub.o
 
 obj-y				+= topology.o
 
arch/x86_64/kernel/nmi.c +15 -1
Index: linux-2.6.3-kgdb/arch/x86_64/kernel/nmi.c
===================================================================
@@ -24,6 +24,7 @@
 #include <linux/module.h>
 #include <linux/sysdev.h>
 #include <linux/nmi.h>
+#include <linux/debugger.h>
 
 #include <asm/smp.h>
 #include <asm/mtrr.h>
@@ -317,13 +318,26 @@
 		return;
 
 	sum = read_pda(apic_timer_irqs);
-	if (last_irq_sums[cpu] == sum) {
+	if (atomic_read(&debugger_active)) {
+
+		/*
+		 * The machine is in debugger, hold this cpu if already
+		 * not held.
+		 */
+		debugger_nmihook(cpu, regs);
+		alert_counter[cpu] = 0;
+
+	} else if (last_irq_sums[cpu] == sum) {
+
 		/*
 		 * Ayiee, looks like this CPU is stuck ...
 		 * wait a few IRQs (5 seconds) before doing the oops ...
 		 */
 		alert_counter[cpu]++;
 		if (alert_counter[cpu] == 5*nmi_hz) {
+
+			CHK_DEBUGGER(2,SIGSEGV,0,regs,)
+
 			if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) == NOTIFY_BAD) { 
 				alert_counter[cpu] = 0; 
 				return;
arch/x86_64/kernel/traps.c +5 -1
Index: linux-2.6.3-kgdb/arch/x86_64/kernel/traps.c
===================================================================
@@ -28,6 +28,7 @@
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
+#include <linux/debugger.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -363,6 +364,7 @@
 
 void die(const char * str, struct pt_regs * regs, long err)
 {
+	CHK_DEBUGGER(1,SIGTRAP,err,regs,)
 	oops_begin();
 	handle_BUG(regs);
 	__die(str, regs, err);
@@ -436,6 +438,7 @@
 #define DO_ERROR(trapnr, signr, str, name) \
 asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
 { \
+	CHK_DEBUGGER(1,SIGTRAP,error_code,regs,return) \
 	if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) == NOTIFY_BAD) \
 		return; \
 	do_trap(trapnr, signr, str, regs, error_code, NULL); \
@@ -614,7 +617,7 @@
 	tsk->thread.debugreg6 = condition;
 
 	/* Mask out spurious TF errors due to lazy TF clearing */
-	if (condition & DR_STEP) {
+	if (condition & DR_STEP && !debugger_step) {
 		/*
 		 * The TF error should be masked out only if the current
 		 * process is not traced and if the TRAP flag has been set
@@ -643,6 +646,7 @@
 	force_sig_info(SIGTRAP, &info, tsk);	
 clear_dr7:
 	asm volatile("movq %0,%%db7"::"r"(0UL));
+	CHK_DEBUGGER(1,SIGTRAP,error_code,regs,return)
 	notify_die(DIE_DEBUG, "debug", regs, error_code, 1, SIGTRAP);
 	return;
 
arch/x86_64/kernel/x86_64-stub.c +454 -0

454 lines not on this page · raw message

arch/x86_64/mm/fault.c +2 -0
Index: linux-2.6.3-kgdb/arch/x86_64/mm/fault.c
===================================================================
@@ -23,6 +23,7 @@
 #include <linux/vt_kern.h>		/* For unblank_screen() */
 #include <linux/compiler.h>
 #include <linux/module.h>
+#include <linux/debugger.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -407,6 +408,7 @@
 
  	if (is_prefetch(regs, address))
  		return;
+	CHK_DEBUGGER(14, SIGSEGV,error_code, regs,)
 
 	if (is_errata93(regs, address))
 		return; 
include/asm-x86_64/calling.h +1 -1
Index: linux-2.6.3-kgdb/include/asm-x86_64/calling.h
===================================================================
@@ -12,7 +12,7 @@
 #define RBX 40
 /* arguments: interrupts/non tracing syscalls only save upto here*/
 #define R11 48
-#define R10 56	
+#define R10 56
 #define R9 64
 #define R8 72
 #define RAX 80
include/asm-x86_64/kgdb.h +53 -0

53 lines not on this page · raw message

include/asm-x86_64/processor.h +1 -0
Index: linux-2.6.3-kgdb/include/asm-x86_64/processor.h
===================================================================
@@ -252,6 +252,7 @@
 	unsigned long	*io_bitmap_ptr;
 /* cached TLS descriptors. */
 	u64 tls_array[GDT_ENTRY_TLS_ENTRIES];
+	void		*debuggerinfo;
 };
 
 #define INIT_THREAD  {}
arch/ppc/8260_io/uart.c +18 -5
Index: linux-2.6.3-kgdb/arch/ppc/8260_io/uart.c
===================================================================
@@ -43,6 +43,7 @@
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/delay.h>
+#include <linux/kgdb.h>
 #include <asm/uaccess.h>
 #include <asm/immap_8260.h>
 #include <asm/mpc8260.h>
@@ -394,8 +395,21 @@
 		status = bdp->cbd_sc;
 #ifdef CONFIG_KGDB
 		if (info->state->smc_scc_num == KGDB_SER_IDX) {
-			if (*cp == 0x03 || *cp == '$')
-				breakpoint();
+			while (i-- > 0) {
+				if (*cp == 0x03) {
+					breakpoint();
+					return;
+				}
+				if (*cp == '$') {
+					atomic_set(&kgdb_might_be_resumed, 1);
+					breakpoint();
+					atomic_set(&kgdb_might_be_resumed, 0);
+					return;
+				}
+				cp++;
+			}
+			bdp->cbd_sc |= BD_SC_EMPTY;
+			bdp->cbd_sc &= ~(BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV);
 			return;
 		}
 #endif
@@ -2275,9 +2289,8 @@
 static void serial_console_write(struct console *c, const char *s,
 				unsigned count)
 {
-#if defined(CONFIG_KGDB_CONSOLE) && !defined(CONFIG_USE_SERIAL2_KGDB)
-	/* Try to let stub handle output. Returns true if it did. */
-	if (kgdb_output_string(s, count))
+#ifdef CONFIG_KGDB
+	if (kgdb_initialized)
 		return;
 #endif
 	my_console_write(c->index, s, count);
arch/ppc/Kconfig +11 -0
Index: linux-2.6.3-kgdb/arch/ppc/Kconfig
===================================================================
@@ -1174,6 +1174,7 @@
 	bool "Include kgdb kernel debugger"
 	depends on DEBUG_KERNEL
 	select DEBUG_INFO
+	select FRAME_POINTER
 	help
 	  Include in-kernel hooks for kgdb, the Linux kernel source level
 	  debugger.  See <http://kgdb.sourceforge.net/> for more information.
@@ -1198,6 +1199,16 @@
 
 endchoice
 
+config KGDB_THREAD
+	bool "KGDB: Thread analysis"
+	depends on KGDB
+	help
+	  With thread analysis enabled, gdb can talk to kgdb stub to list
+	  threads and to get stack trace for a thread. This option also enables
+	  some code which helps gdb get exact status of thread. Thread analysis
+	  adds some overhead to schedule and down functions. You can disable
+	  this option if you do not want to compromise on speed.
+
 config KGDB_CONSOLE
 	bool "Enable serial console thru kgdb port"
 	depends on KGDB && 8xx || 8260
arch/ppc/kernel/entry.S +66 -3

93 lines not on this page · raw message

arch/ppc/kernel/irq.c +6 -0
Index: linux-2.6.3-kgdb/arch/ppc/kernel/irq.c
===================================================================
@@ -513,6 +513,12 @@
 void do_IRQ(struct pt_regs *regs)
 {
 	int irq, first = 1;
+	unsigned long *lrptr;
+	if (!(regs->msr & MSR_PR)) {
+		/* Came in from the kernel. Save call link. */
+		lrptr = (unsigned long *)(regs->gpr[1] + 4);
+		*lrptr = regs->nip;
+	}
         irq_enter();
 
 	/*
arch/ppc/kernel/ppc-stub.c +225 -772

1,082 lines not on this page · raw message

arch/ppc/kernel/setup.c +1 -9
Index: linux-2.6.3-kgdb/arch/ppc/kernel/setup.c
===================================================================
@@ -643,15 +643,7 @@
 	if ( ppc_md.progress ) ppc_md.progress("setup_arch: enter", 0x3eab);
 
 #if defined(CONFIG_KGDB)
-	if (ppc_md.kgdb_map_scc)
-		ppc_md.kgdb_map_scc();
-	set_debug_traps();
-	if (strstr(cmd_line, "gdb")) {
-		if (ppc_md.progress)
-			ppc_md.progress("setup_arch: kgdb breakpoint", 0x4000);
-		printk("kgdb breakpoint activated\n");
-		breakpoint();
-	}
+	kgdbppc_init();
 #endif
 
 	/*
arch/ppc/mm/fault.c +13 -1
Index: linux-2.6.3-kgdb/arch/ppc/mm/fault.c
===================================================================
@@ -28,6 +28,7 @@
 #include <linux/interrupt.h>
 #include <linux/highmem.h>
 #include <linux/module.h>
+#include <linux/debugger.h>
 
 #include <asm/page.h>
 #include <asm/pgtable.h>
@@ -139,6 +140,13 @@
 		bad_page_fault(regs, address, SIGSEGV);
 		return;
 	}
+
+	if (debugger_memerr_expected) {
+		/* This fault was caused by memory access through a debugger.
+		 * Don't handle it like user accesses */
+		goto no_context;
+	}
+
 	down_read(&mm->mmap_sem);
 	vma = find_vma(mm, address);
 	if (!vma)
@@ -293,6 +301,7 @@
 		return;
 	}
 
+no_context:
 	bad_page_fault(regs, address, SIGSEGV);
 	return;
 
@@ -342,10 +351,13 @@
 	}
 
 	/* kernel has accessed a bad area */
-#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
+#if defined(CONFIG_XMON)
 	if (debugger_kernel_faults)
 		debugger(regs);
 #endif
+
+	CHK_DEBUGGER(14, sig,0, regs,)
+
 	die("kernel access of bad area", regs, sig);
 }
 
arch/ppc/platforms/sandpoint.c +0 -32
Index: linux-2.6.3-kgdb/arch/ppc/platforms/sandpoint.c
===================================================================
@@ -252,38 +252,6 @@
 	return;
 }
 
-#if defined(CONFIG_SERIAL_8250) && \
-	(defined(CONFIG_KGDB) || defined(CONFIG_SERIAL_TEXT_DEBUG))
-static void __init
-sandpoint_early_serial_map(void)
-{
-	struct uart_port serial_req;
-
-	/* Setup serial port access */
-	memset(&serial_req, 0, sizeof(serial_req));
-	serial_req.uartclk = UART_CLK;
-	serial_req.irq = 4;
-	serial_req.flags = STD_COM_FLAGS;
-	serial_req.iotype = SERIAL_IO_MEM;
-	serial_req.membase = (u_char *)SANDPOINT_SERIAL_0;
-
-	gen550_init(0, &serial_req);
-
-	if (early_serial_setup(&serial_req) != 0)
-		printk(KERN_ERR "Early serial init of port 0 failed\n");
-
-	/* Assume early_serial_setup() doesn't modify serial_req */
-	serial_req.line = 1;
-	serial_req.irq = 3; /* XXXX */
-	serial_req.membase = (u_char *)SANDPOINT_SERIAL_1;
-
-	gen550_init(1, &serial_req);
-
-	if (early_serial_setup(&serial_req) != 0)
-		printk(KERN_ERR "Early serial init of port 1 failed\n");
-}
-#endif
-
 static void __init
 sandpoint_setup_arch(void)
 {
Signature · 2 lines
When do you have a heart between your knees?
[Johanka's followup: and *two* hearts?]