A different KGDB stub
PATCH 4/6 A different KGDB stub
The following is the i386-specific bits to this KGDB stub.
arch/i386/Kconfig | 2 arch/i386/kernel/Makefile | 1 arch/i386/kernel/entry.S | 39 +++ arch/i386/kernel/i386-stub.c | 442 +++++++++++++++++++++++++++++++++++++++++++ arch/i386/kernel/irq.c | 9 arch/i386/kernel/nmi.c | 14 + arch/i386/kernel/signal.c | 3 arch/i386/kernel/traps.c | 20 + arch/i386/mm/fault.c | 15 + include/asm-i386/kgdb.h | 53 +++++ include/asm-i386/processor.h | 1 11 files changed, 586 insertions(+), 13 deletions(-)
arch/i386/Kconfig +2 -0
@@ -1361,6 +1361,8 @@ If you say Y here, various routines which may sleep will become very noisy if they are called with a spinlock held. +source "kernel/Kconfig.kgdb" + config FRAME_POINTER bool "Compile the kernel with frame pointers" help
arch/i386/kernel/Makefile +1 -0
@@ -32,6 +32,7 @@ obj-$(CONFIG_HPET_TIMER) += time_hpet.o obj-$(CONFIG_EFI) += efi.o efi_stub.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o +obj-$(CONFIG_KGDB) += i386-stub.o EXTRA_AFLAGS := -traditional
arch/i386/kernel/entry.S +37 -2
@@ -330,7 +330,7 @@ jz restore_all movl $PREEMPT_ACTIVE,TI_preempt_count(%ebp) sti - call schedule + call user_schedule movl $0,TI_preempt_count(%ebp) cli jmp need_resched
@@ -438,7 +438,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
@@ -545,7 +545,17 @@ ALIGN common_interrupt: SAVE_ALL + movl %esp, %eax +/* Create a fake function call followed by a fake function prologue to fool + * gdb into believing that this is a normal function call. */ + pushl EIP(%eax) + +common_interrupt_1: + pushl %ebp + movl %esp, %ebp + pushl %eax call do_IRQ + addl $12, %esp jmp ret_from_intr #define BUILD_INTERRUPT(name, nr) \
@@ -758,6 +768,31 @@ jmp error_code .previous + +#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)
arch/i386/kernel/i386-stub.c new file +442 -0
442 lines not on this page · raw message
arch/i386/kernel/irq.c +6 -3
@@ -36,6 +36,7 @@#include <linux/kallsyms.h> #include <linux/notifier.h> #include <linux/cpu.h> +#include <linux/kgdb.h> #include <asm/atomic.h> #include <asm/io.h>
@@ -412,7 +413,7 @@* SMP cross-CPU interrupts have their own specific * handlers). */ -asmlinkage unsigned int do_IRQ(struct pt_regs regs) +asmlinkage unsigned int do_IRQ(struct pt_regs *regs) {/* * We ack quickly, we don't want the irq controller
@@ -424,7 +425,7 @@* 0 return value means that this irq is already being * handled by some other CPU. (or is disabled) */ -int irq = regs.orig_eax &0xff ;/* high bits used in ret_from_ code */ +int irq = regs->orig_eax &0xff ;/* high bits used in ret_from_ code */ irq_desc_t *desc = irq_desc + irq;struct irqaction * action;unsigned int status;
@@ -490,7 +491,7 @@irqreturn_t action_ret;spin_unlock (&desc->lock); - action_ret =handle_IRQ_event (irq, ®s, action); + action_ret =handle_IRQ_event (irq, regs, action);spin_lock (&desc->lock);if (!noirqdebug)note_interrupt (irq, desc, action_ret);
@@ -509,6 +510,8 @@spin_unlock (&desc->lock);irq_exit (); + +kgdb_process_breakpoint ();return 1 ; }
arch/i386/kernel/nmi.c +13 -1
@@ -25,6 +25,7 @@#include <linux/module.h> #include <linux/nmi.h> #include <linux/sysdev.h> +#include <linux/debugger.h> #include <asm/smp.h> #include <asm/mtrr.h>
@@ -420,14 +421,25 @@int sum, cpu =smp_processor_id (); sum = irq_stat[cpu].apic_timer_irqs; +if (atomic_read (&debugger_active)) { -if (last_irq_sums[cpu] == sum) { +/* +* The machine is in debugger, hold this cpu if already +* not held. +*/ +debugger_nmihook (cpu, regs); + alert_counter[cpu] =0 ; + + }else if (last_irq_sums[cpu] == sum) {/* * Ayiee, looks like this CPU is stuck ... * wait a few IRQs (5 seconds) before doing the oops ... */ alert_counter[cpu]++;if (alert_counter[cpu] ==5 *nmi_hz) { + + CHK_DEBUGGER(2,SIGSEGV,0,regs,) + spin_lock(&nmi_print_lock);/* * We are in trouble anyway, lets at least try
arch/i386/kernel/signal.c +2 -1
@@ -578,7 +578,8 @@* have been cleared if the watchpoint triggered * inside the kernel. */ - __asm__("movl %0,%%db7" : :"r" (current->thread.debugreg[7 ])); +if (current->thread.debugreg[7 ]) + __asm__("movl %0,%%db7" : :"r" (current->thread.debugreg[7 ]));/* Whee! Actually deliver the signal. */ handle_signal (signr, &info, oldset, regs);
arch/i386/kernel/traps.c +14 -6
@@ -51,6 +51,7 @@#include <linux/irq.h> #include <linux/module.h> +#include <linux/debugger.h> #include "mach_traps.h"
@@ -258,6 +259,7 @@static int die_counter;int nl =0 ; + CHK_DEBUGGER(1,SIGTRAP,err,regs,) console_verbose(); spin_lock_irq(&die_lock); bust_spinlocks(1);
@@ -346,6 +348,7 @@#define DO_ERROR (trapnr, signr, str, name) \ asmlinkage void do_##name(struct pt_regs * regs, long error_code) \ { \ + CHK_DEBUGGER(trapnr,signr,error_code,regs,)\ do_trap(trapnr, signr, str, 0, regs, error_code, NULL); \ }
@@ -363,7 +366,9 @@#define DO_VM86_ERROR (trapnr, signr, str, name) \ asmlinkage void do_##name(struct pt_regs * regs, long error_code) \ { \ + CHK_DEBUGGER(trapnr,signr,error_code,regs,goto skip_trap)\ do_trap(trapnr, signr, str, 1, regs, error_code, NULL); \ +skip_trap: \ return; \ }
@@ -572,7 +577,7 @@ tsk->thread.debugreg[6 ] = condition;/* Mask out spurious TF errors due to lazy TF clearing */ -if (condition &DR_STEP ) { +if (condition &DR_STEP && !debugger_step) {/* * The TF error should be masked out only if the current * process is not traced and if the TRAP flag has been set
@@ -595,11 +600,13 @@ info.si_errno =0 ; info.si_code =TRAP_BRKPT ; -/* If this is a kernel mode trap, save the user PC on entry to -* the kernel, that's what the debugger can make sense of. -*/ - info.si_addr = ((regs->xcs &3 ) ==0 ) ? (void *)tsk->thread.eip : - (void *)regs->eip; + +/* If this is a kernel mode trap, we need to reset db7 to allow us +* to continue sanely */ +if ((regs->xcs &3 ) ==0 ) + goto clear_dr7; + + info.si_addr = (void *)regs->eip;force_sig_info (SIGTRAP , &info, tsk);/* Disable additional traps. They'll be re-enabled when
@@ -609,6 +616,7 @@ __asm__("movl %0,%%db7" :/* no output */ :"r" (0 )); + CHK_DEBUGGER(1,SIGTRAP,error_code,regs,) return; debug_vm86:
arch/i386/mm/fault.c +15 -0
@@ -2,6 +2,11 @@* linux/arch/i386/mm/fault.c * * Copyright (C) 1995 Linus Torvalds +* +* Change History +* +* Tigran Aivazian <[email protected]> Remote debugging support. +* */ #include <linux/signal.h>
@@ -21,6 +26,7 @@#include <linux/vt_kern.h> /* For unblank_screen() */ #include <linux/highmem.h> #include <linux/module.h> +#include <linux/debugger.h> #include <asm/system.h> #include <asm/uaccess.h>
@@ -289,6 +295,12 @@if (in_atomic () || !mm) goto bad_area_nosemaphore; +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);
@@ -426,12 +438,15 @@if (is_prefetch (regs, address))return ; + CHK_DEBUGGER(14, SIGSEGV,error_code, regs,) +/* * Oops. The kernel tried to access some bad page. We'll have to * terminate things with extreme prejudice. */ bust_spinlocks(1); +if (address <PAGE_SIZE )printk (KERN_ALERT "Unable to handle kernel NULL pointer dereference" );
include/asm-i386/kgdb.h new file +53 -0
53 lines not on this page · raw message
include/asm-i386/processor.h +1 -0
@@ -423,6 +423,7 @@unsigned int saved_fs, saved_gs;/* IO permissions */ unsigned long *io_bitmap_ptr; +void * debuggerinfo; };#define INIT_THREAD { \
Signature · 2 lines
Tom Rini http://gate.crashing.org/~trini/