[BACK]Return to kdbasupport.c CVS log [TXT][DIR] Up to [Development] / linux-2.6-xfs / arch / x86_64 / kdb

File: [Development] / linux-2.6-xfs / arch / x86_64 / kdb / Attic / kdbasupport.c (download)

Revision 1.1, Mon May 29 16:35:25 2006 UTC (11 years, 4 months ago) by nathans.longdrop.melbourne.sgi.com
Branch: MAIN

Merge up to 2.6.17-rc5.
Merge of 2.6.x-xfs-melb:linux:26065a by kenmcd.

/*
 * Kernel Debugger Architecture Independent Support Functions
 *
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file "COPYING" in the main directory of this archive
 * for more details.
 *
 * Copyright (c) 1999-2004 Silicon Graphics, Inc.  All Rights Reserved.
 */

#include <linux/config.h>
#include <linux/string.h>
#include <linux/stddef.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/ptrace.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/kdb.h>
#include <linux/kdbprivate.h>
#include <asm/kdebug.h>
#include <asm/processor.h>
#include <asm/msr.h>
#include <asm/uaccess.h>
#include <asm/mach_apic.h>
#include <asm/hw_irq.h>


#define SP_SANITY(ss, sp)	1
#define SS(sp)			((sp) & -THREAD_SIZE)	/* XXX */

/*
 * kdba_find_return
 *
 *	Given a starting point on the stack and symtab data for the
 *	current function, scan up the stack looking for a return
 *	address for this function.
 * Inputs:
 *	sp	Starting stack pointer for scan
 *	ss	Start of stack for current process
 *	symtab	kallsyms symbol data for the function
 * Outputs:
 *	None.
 * Returns:
 *	Position on stack of return address, 0 if not found.
 * Locking:
 *	None.
 * Remarks:
 *	This is sensitive to the calling sequence generated by gcc.
 */


static kdb_machreg_t
kdba_find_return(kdb_machreg_t sp, kdb_machreg_t ss, const kdb_symtab_t *symtab)
{
	kdb_machreg_t	ret;
	kdb_symtab_t	caller_symtab;
	unsigned long	disp8;
	unsigned long	disp32;
	unsigned char	code[7];
#define retaddr(off) code[sizeof(code)+(off)]

	if (KDB_DEBUG(ARA)) {
		kdb_printf("  kdba_find_return: start\n");
	}

	if (SP_SANITY(ss, sp) == 0) {
		kdb_printf("    sp is in wrong stack 0x%lx\n", sp);
		return(0);
	}

	if ((sp & (THREAD_SIZE - 1)) < sizeof(struct task_struct)) {
		kdb_printf("    sp is inside task_struct\n");
		return(0);
	}

	for (;ret = 0, sp & (THREAD_SIZE-1);sp += 8) {
		if (KDB_DEBUG(ARA)) {
			kdb_printf("    sp=0x%lx", sp);
		}
		if (kdb_getword(&ret, sp, 8))
			break;
		kdbnearsym(ret, &caller_symtab);
		if (KDB_DEBUG(ARA)) {
			kdb_printf(" ret=");
			kdb_symbol_print(ret, &caller_symtab, KDB_SP_DEFAULT|KDB_SP_SYMSIZE);
		}
		if (!caller_symtab.sym_name) {
			if (KDB_DEBUG(ARA)) {
				kdb_printf("\n");
			}
			continue;	/* not a valid kernel address */
		}
		KDB_STATE_SET(SUPPRESS);
		if (kdb_getarea(code, ret-sizeof(code)) ||
		    kdb_getword(&disp32, ret-4, 4) ||
		    kdb_getword(&disp8, ret-1, 1))
			continue;	/* not a valid return address */
		if (retaddr(-5) == 0xe8) {
			/* call disp32 */
			if (KDB_DEBUG(ARA)) {
				kdb_printf(" call disp32");
			}
			if (ret + (s32) disp32 == symtab->sym_start) {
				if (KDB_DEBUG(ARA)) {
					kdb_printf(" matched\n");
				}
				break;		/* call to this function */
			}
			if (KDB_DEBUG(ARA)) {
				kdb_printf(" failed");
			}
		} else if (retaddr(-7) == 0xff && retaddr(-6) == 0x14 && retaddr(-5) == 0x85) {
			/* call *disp32(,%rax,4), used by syscall.
			 * Cannot calculate address, assume it is valid
			 * if the current function name starts with
			 * 'sys_' or 'old_'.
			 */
			if (KDB_DEBUG(ARA)) {
				/* XXX FIXME */
				kdb_printf(" call *0xnnnn(,%%rax,4)");
			}
			if (strncmp(symtab->sym_name, "sys_", 4) == 0 ||
			    strncmp(symtab->sym_name, "old_", 4) == 0) {
				if (KDB_DEBUG(ARA)) {
					kdb_printf(" matched\n");
				}
				break;		/* probably call to this function */
			}
			if (KDB_DEBUG(ARA)) {
				kdb_printf(" failed");
			}
		} else if (retaddr(-2) == 0xff && (retaddr(-1) & 0xf8) == 0xd0) {
			/* call *%reg.  Cannot validate, have to assume
			 * it is valid.
			 */
			if (KDB_DEBUG(ARA)) {
				kdb_printf(" call *%%reg, assume valid\n");
			}
			break;		/* hope it is a call to this function */
		} else if (retaddr(-3) == 0xff && (retaddr(-2) & 0xf8) == 0x50) {
			/* call *disp8(%reg).  Cannot validate, have to assume
			 * it is valid.
			 */
			if (KDB_DEBUG(ARA)) {
				kdb_printf(" call *disp8(%%reg), assume valid\n");
			}
			break;		/* hope it is a call to this function */
		} else if (retaddr(-5) == 0xe9) {
			/* jmp disp32.  I have been told that gcc may
			 * do function tail optimization and replace
			 * call with jmp.
			 */
			if (KDB_DEBUG(ARA)) {
				kdb_printf(" jmp disp32\n");
			}
			if (ret + (s32) disp32 == symtab->sym_start) {
				if (KDB_DEBUG(ARA)) {
					kdb_printf(" matched\n");
				}
				break;		/* jmp to this function */
			}
			if (KDB_DEBUG(ARA)) {
				kdb_printf(" failed");
			}
		} else if (retaddr(-2) == 0xeb) {
			/* jmp disp8 */
			if (KDB_DEBUG(ARA)) {
				kdb_printf(" jmp disp8\n");
			}
			if (ret + (s8) disp8 == symtab->sym_start) {
				if (KDB_DEBUG(ARA)) {
					kdb_printf(" matched\n");
				}
				break;		/* jmp to this function */
			}
			if (KDB_DEBUG(ARA)) {
				kdb_printf(" failed");
			}
		} else if (strcmp(caller_symtab.sym_name, "ret_from_intr") == 0
		           && ret == caller_symtab.sym_start) {
			/* ret_from_intr is pushed on stack for interrupts */
			if (KDB_DEBUG(ARA)) {
				kdb_printf(" ret_from_intr matched\n");
			}
			break;		/* special case, hand crafted frame */
		}
		if (KDB_DEBUG(ARA)) {
			kdb_printf("\n");
		}
	}
	if (KDB_DEBUG(ARA)) {
		kdb_printf("  end ret=0x%lx sp=0x%lx\n", ret, sp);
	}
	if (ret)
		return(sp);
	return(0);
}

/*
 * kdba_prologue
 *
 *	This function analyzes a gcc-generated function prototype
 *	with or without frame pointers to determine the amount of
 *	automatic storage and register save storage is used on the
 *	stack of the target function.  It only counts instructions
 *	that have been executed up to but excluding the current rip.
 * Inputs:
 *	code	Start address of function code to analyze
 *	pc	Current program counter within function
 *	sp	Current stack pointer for function
 *	ss	Start of stack for current process
 *	fp	Current frame pointer for function, may not be valid
 *	caller	1 if looking for data on the caller frame, 0 for callee.
 * Outputs:
 *	ar	Activation record, all fields may be set.  fp and oldfp
 *		are 0 if they cannot be extracted.  return is 0 if the
 *		code cannot find a valid return address.  args and arg0
 *		are 0 if the number of arguments cannot be safely
 *		calculated.
 * Returns:
 *	1 if prologue is valid, 0 otherwise.  If pc is 0 treat it as a
 *	valid prologue to allow bt on wild branches.
 * Locking:
 *	None.
 * Remarks:
 *
 *	x86_64 prologues
 *
 *	kdba_prologue():
 *		push   %r15
 *		mov    %rdi,%r15
 *		push   %r14
 *		mov    %rsi,%r14
 *		push   %r13
 *		push   %r12
 *		push   %rbp
 *		mov    %rdx,%rbp
 *
 *	leaf fn w/ 1 arg:
 *		push   %rbp
 *		mov    %rsp,%rbp
 *		mov    %rdi,0xfffffffffffffff8(%rbp)
 *
 */

int
kdba_prologue(const kdb_symtab_t *symtab, kdb_machreg_t pc, kdb_machreg_t sp,
	      kdb_machreg_t fp, kdb_machreg_t ss, int caller, kdb_ar_t *ar)
{
	kdb_machreg_t	ret_p, code = symtab->sym_start;
	int		oldfp_present = 0, unwound = 0;
	unsigned char	instruction[6];

	if (KDB_DEBUG(ARA)) {
		kdb_printf("kdba_prologue: code=0x%lx %s pc=0x%lx sp=0x%lx fp=0x%lx\n",
		code, symtab->sym_name, pc, sp, fp);
	}

	/* Special case for wild branches.  Assumes top of stack is return address */
	if (pc == 0) {
		memset(ar, 0, sizeof(*ar));
		ar->setup = 8;
		ar->end = sp;
		ar->start = ar->end + 8;
		kdb_getword(&(ar->ret), sp, 8);
		if (KDB_DEBUG(ARA)) {
			kdb_printf("  pc==0: ret=0x%lx\n", ar->ret);
		}
		return(1);
	}

	if (code == 0 || sp & 3 || (SP_SANITY(ss, sp) == 0))
		return(0);

	ar->end = sp;				/* End of activation record +1 */

	/* Special cases galore when the caller pc is within entry.S.
	 * The return address for these routines is outside the kernel,
	 * so the normal algorithm to find the frame does not work.
	 * Hand craft the frame to no setup, regs, locals etc, assume 6
	 * parameters.
	 * This list was extracted from entry.S by looking for all call
	 * instructions that were eventually followed by RESTORE_ALL,
	 * take the label before each such instruction.
	 */
	if (caller &&
	    (strcmp(symtab->sym_name, "lcall7") == 0 ||
	     strcmp(symtab->sym_name, "lcall27") == 0 ||
	     strcmp(symtab->sym_name, "kdb_call") == 0 ||
	     strcmp(symtab->sym_name, "system_call") == 0 ||
	     strcmp(symtab->sym_name, "tracesys") == 0 ||
	     strcmp(symtab->sym_name, "signal_return") == 0 ||
	     strcmp(symtab->sym_name, "v86_signal_return") == 0 ||
	     strcmp(symtab->sym_name, "tracesys") == 0 ||
	     strcmp(symtab->sym_name, "tracesys_exit") == 0 ||
	     strcmp(symtab->sym_name, "handle_softirq") == 0 ||
	     strcmp(symtab->sym_name, "reschedule") == 0 ||
	     strcmp(symtab->sym_name, "error_code") == 0 ||
	     strcmp(symtab->sym_name, "device_not_available") == 0 ||
	     strcmp(symtab->sym_name, "nmi") == 0)) {
		ar->start = ar->end + 6*8;	/* 6 parameters */
		if (SP_SANITY(ss, ar->start) == 0)
			ar->start = 0;
		return(1);
	}

	ar->setup = 8;	/* Return address is always on stack */

	/* Kludge.  If we are sitting on 'ret' then the stack has been unwound,
	 * ignore all the startup code.
	 */
	if (kdb_getarea(instruction[0], pc))
		return(0);
	if (instruction[0] == 0xc3) {
		/* ret */
		unwound = 1;
	}

	if (kdb_getarea(instruction, code))
		return(0);
	if (!unwound && code < pc && instruction[0] == 0x55) {
		/* pushl %rbp */
		ar->setup += 8;	/* Frame pointer is on stack */
		oldfp_present = 1;
		++code;
		if (KDB_DEBUG(ARA)) {
			kdb_printf("  pushq %%rbp\n");
		}
		if (code < pc && instruction[0] == 0x89 && instruction[1] == 0xe5) {
			/* movl %esp,%ebp */
			if (fp >= sp && SP_SANITY(ss, fp))
				ar->fp = fp;	/* %rbp has been set */
			code += 2;
			if (KDB_DEBUG(ARA)) {
				kdb_printf("  movq %%rsp,%%rbp, fp=0x%lx\n", ar->fp);
			}
		}
	}

	if (!unwound && code < pc) {
		if (instruction[0] == 0x83 && instruction[1] == 0xec) {
			/* subl $xx,%rsp */
			kdb_getword(&(ar->locals), (unsigned long)(instruction+2), 1);
			code += 3;
			if (KDB_DEBUG(ARA)) {
				kdb_printf("  subl $xx,%%rsp, locals=%ld\n", ar->locals);
			}
		} else if (instruction[0] == 0x81 && instruction[1] == 0xec) {
			/* subl $xxxxxxxx,%rsp */
			kdb_getword(&(ar->locals), (unsigned long)(instruction+2), 8);
			code += 6;
			if (KDB_DEBUG(ARA)) {
				kdb_printf("  subl $xxxxxxxx,%%rsp, locals=%ld\n", ar->locals);
			}
		}
	}

	while (!unwound && code < pc &&
	       kdb_getarea(instruction, code) == 0 &&
	       (instruction[0] & 0xf8) == 0x50) {
		/* pushl %reg */
		ar->regs += 8;
		++code;
		if (KDB_DEBUG(ARA)) {
			kdb_printf("  pushq %%reg, regs=%ld\n", ar->regs);
		}
	}

	/* Check the return address.  It must point within the kernel
	 * and the code at that location must be a valid entry sequence.
	 */
	if (ar->fp) {
		ret_p = ar->fp + ar->setup;
	}
	else {
		ret_p = ar->end + ar->regs + ar->locals + ar->setup;
	}
	ret_p -= 8;
	if (KDB_DEBUG(ARA)) {
		kdb_printf("  ret_p(0)=0x%lx\n", ret_p);
	}
	ar->ret = 0;
	if ((SP_SANITY(ss, ret_p) != 0) &&
	    (ret_p = kdba_find_return(ret_p, ss, symtab))) {
		kdb_getword(&(ar->ret), ret_p, 8);
	}
	if (KDB_DEBUG(ARA)) {
		kdb_printf("  ret_p(1)=0x%lx ret=0x%lx\n", ret_p, ar->ret);
	}
	if (ar->ret) {
		ar->fp = ret_p - ar->setup + 8;	/* "accurate" fp */
		ar->start = ret_p + 8;
		if (KDB_DEBUG(ARA)) {
			kdb_printf("  fp=0x%lx start=0x%lx\n", ar->fp, ar->start);
		}
	}
	if (oldfp_present) {
		if (ar->fp)
			kdb_getword(&(ar->oldfp), ar->fp, 8);
		if (KDB_DEBUG(ARA)) {
			kdb_printf("  oldfp=0x%lx", ar->oldfp);
		}
		if (ar->oldfp <= ar->fp || (SP_SANITY(ss, ar->oldfp) == 0)) {
			ar->oldfp = 0;
			if (KDB_DEBUG(ARA)) {
				kdb_printf(" (out of range)");
			}
		}
		if (KDB_DEBUG(ARA)) {
			kdb_printf("\n");
		}
	}
	return(1);
}

kdb_machreg_t
kdba_getdr6(void)
{
	return kdba_getdr(6);
}

kdb_machreg_t
kdba_getdr7(void)
{
	return kdba_getdr(7);
}

void
kdba_putdr6(kdb_machreg_t contents)
{
	kdba_putdr(6, contents);
}

static void
kdba_putdr7(kdb_machreg_t contents)
{
	kdba_putdr(7, contents);
}

void
kdba_installdbreg(kdb_bp_t *bp)
{
	kdb_machreg_t	dr7;

	dr7 = kdba_getdr7();

	kdba_putdr(bp->bp_hard->bph_reg, bp->bp_addr);

	dr7 |= DR7_GE;
	if (cpu_has_de)
		set_in_cr4(X86_CR4_DE);

	switch (bp->bp_hard->bph_reg){
	case 0:
		DR7_RW0SET(dr7,bp->bp_hard->bph_mode);
		DR7_LEN0SET(dr7,bp->bp_hard->bph_length);
		DR7_G0SET(dr7);
		break;
	case 1:
		DR7_RW1SET(dr7,bp->bp_hard->bph_mode);
		DR7_LEN1SET(dr7,bp->bp_hard->bph_length);
		DR7_G1SET(dr7);
		break;
	case 2:
		DR7_RW2SET(dr7,bp->bp_hard->bph_mode);
		DR7_LEN2SET(dr7,bp->bp_hard->bph_length);
		DR7_G2SET(dr7);
		break;
	case 3:
		DR7_RW3SET(dr7,bp->bp_hard->bph_mode);
		DR7_LEN3SET(dr7,bp->bp_hard->bph_length);
		DR7_G3SET(dr7);
		break;
	default:
		kdb_printf("kdb: Bad debug register!! %ld\n",
			   bp->bp_hard->bph_reg);
		break;
	}

	kdba_putdr7(dr7);
	return;
}

void
kdba_removedbreg(kdb_bp_t *bp)
{
	int 		regnum;
	kdb_machreg_t	dr7;

	if (!bp->bp_hard)
		return;

	regnum = bp->bp_hard->bph_reg;

	dr7 = kdba_getdr7();

	kdba_putdr(regnum, 0);

	switch (regnum) {
	case 0:
		DR7_G0CLR(dr7);
		DR7_L0CLR(dr7);
		break;
	case 1:
		DR7_G1CLR(dr7);
		DR7_L1CLR(dr7);
		break;
	case 2:
		DR7_G2CLR(dr7);
		DR7_L2CLR(dr7);
		break;
	case 3:
		DR7_G3CLR(dr7);
		DR7_L3CLR(dr7);
		break;
	default:
		kdb_printf("kdb: Bad debug register!! %d\n", regnum);
		break;
	}

	kdba_putdr7(dr7);
}

kdb_machreg_t
kdba_getdr(int regnum)
{
	kdb_machreg_t contents = 0;
	switch(regnum) {
	case 0:
		__asm__ ("movq %%db0,%0\n\t":"=r"(contents));
		break;
	case 1:
		__asm__ ("movq %%db1,%0\n\t":"=r"(contents));
		break;
	case 2:
		__asm__ ("movq %%db2,%0\n\t":"=r"(contents));
		break;
	case 3:
		__asm__ ("movq %%db3,%0\n\t":"=r"(contents));
		break;
	case 4:
	case 5:
		break;
	case 6:
		__asm__ ("movq %%db6,%0\n\t":"=r"(contents));
		break;
	case 7:
		__asm__ ("movq %%db7,%0\n\t":"=r"(contents));
		break;
	default:
		break;
	}

	return contents;
}


kdb_machreg_t
kdb_getcr(int regnum)
{
	kdb_machreg_t contents = 0;
	switch(regnum) {
	case 0:
		__asm__ ("movq %%cr0,%0\n\t":"=r"(contents));
		break;
	case 1:
		break;
	case 2:
		__asm__ ("movq %%cr2,%0\n\t":"=r"(contents));
		break;
	case 3:
		__asm__ ("movq %%cr3,%0\n\t":"=r"(contents));
		break;
	case 4:
		__asm__ ("movq %%cr4,%0\n\t":"=r"(contents));
		break;
	default:
		break;
	}

	return contents;
}

void
kdba_putdr(int regnum, kdb_machreg_t contents)
{
	switch(regnum) {
	case 0:
		__asm__ ("movq %0,%%db0\n\t"::"r"(contents));
		break;
	case 1:
		__asm__ ("movq %0,%%db1\n\t"::"r"(contents));
		break;
	case 2:
		__asm__ ("movq %0,%%db2\n\t"::"r"(contents));
		break;
	case 3:
		__asm__ ("movq %0,%%db3\n\t"::"r"(contents));
		break;
	case 4:
	case 5:
		break;
	case 6:
		__asm__ ("movq %0,%%db6\n\t"::"r"(contents));
		break;
	case 7:
		__asm__ ("movq %0,%%db7\n\t"::"r"(contents));
		break;
	default:
		break;
	}
}

/*
 * kdba_getregcontents
 *
 *	Return the contents of the register specified by the
 *	input string argument.   Return an error if the string
 *	does not match a machine register.
 *
 *	The following pseudo register names are supported:
 *	   &regs	 - Prints address of exception frame
 *	   krsp		 - Prints kernel stack pointer at time of fault
 *	   crsp		 - Prints current kernel stack pointer, inside kdb
 *	   ceflags	 - Prints current flags, inside kdb
 *	   %<regname>	 - Uses the value of the registers at the
 *			   last time the user process entered kernel
 *			   mode, instead of the registers at the time
 *			   kdb was entered.
 *
 * Parameters:
 *	regname		Pointer to string naming register
 *	regs		Pointer to structure containing registers.
 * Outputs:
 *	*contents	Pointer to unsigned long to recieve register contents
 * Returns:
 *	0		Success
 *	KDB_BADREG	Invalid register name
 * Locking:
 * 	None.
 * Remarks:
 * 	If kdb was entered via an interrupt from the kernel itself then
 *	ss and rsp are *not* on the stack.
 */

static struct kdbregs {
	char   *reg_name;
	size_t	reg_offset;
} kdbreglist[] = {
	{ "r15",	offsetof(struct pt_regs, r15) },
	{ "r14",	offsetof(struct pt_regs, r14) },
	{ "r13",	offsetof(struct pt_regs, r13) },
	{ "r12",	offsetof(struct pt_regs, r12) },
	{ "rbp",	offsetof(struct pt_regs, rbp) },
	{ "rbx",	offsetof(struct pt_regs, rbx) },
	{ "r11",	offsetof(struct pt_regs, r11) },
	{ "r10",	offsetof(struct pt_regs, r10) },
	{ "r9",		offsetof(struct pt_regs, r9) },
	{ "r8",		offsetof(struct pt_regs, r8) },
	{ "rax",	offsetof(struct pt_regs, rax) },
	{ "rcx",	offsetof(struct pt_regs, rcx) },
	{ "rdx",	offsetof(struct pt_regs, rdx) },
	{ "rsi",	offsetof(struct pt_regs, rsi) },
	{ "rdi",	offsetof(struct pt_regs, rdi) },
	{ "orig_rax",	offsetof(struct pt_regs, orig_rax) },
	{ "rip",	offsetof(struct pt_regs, rip) },
	{ "cs",		offsetof(struct pt_regs, cs) },
	{ "eflags", 	offsetof(struct pt_regs, eflags) },
	{ "rsp",	offsetof(struct pt_regs, rsp) },
	{ "ss",		offsetof(struct pt_regs, ss) },
};

static const int nkdbreglist = sizeof(kdbreglist) / sizeof(struct kdbregs);

static struct kdbregs dbreglist[] = {
	{ "dr0", 	0 },
	{ "dr1", 	1 },
	{ "dr2",	2 },
	{ "dr3", 	3 },
	{ "dr6", 	6 },
	{ "dr7",	7 },
};

static const int ndbreglist = sizeof(dbreglist) / sizeof(struct kdbregs);

int
kdba_getregcontents(const char *regname,
		    struct pt_regs *regs,
		    kdb_machreg_t *contents)
{
	int i;

	if (strcmp(regname, "&regs") == 0) {
		*contents = (unsigned long)regs;
		return 0;
	}

	if (strcmp(regname, "krsp") == 0) {
		*contents = (unsigned long)regs + sizeof(struct pt_regs);
		if ((regs->cs & 0xffff) == __KERNEL_CS) {
			/* rsp and ss are not on stack */
			*contents -= 2*4;
		}
		return 0;
	}

	if (strcmp(regname, "crsp") == 0) {
		asm volatile("movq %%rsp,%0":"=m" (*contents));
		return 0;
	}

	if (strcmp(regname, "ceflags") == 0) {
		unsigned long flags;
		local_save_flags(flags);
		*contents = flags;
		return 0;
	}

	if (regname[0] == '%') {
		/* User registers:  %%r[a-c]x, etc */
		regname++;
		regs = (struct pt_regs *)
			(current->thread.rsp0 - sizeof(struct pt_regs));
	}

	for (i=0; i<nkdbreglist; i++) {
		if (strnicmp(kdbreglist[i].reg_name,
			     regname,
			     strlen(regname)) == 0)
			break;
	}

	if ((i < nkdbreglist)
	 && (strlen(kdbreglist[i].reg_name) == strlen(regname))) {
		if ((regs->cs & 0xffff) == __KERNEL_CS) {
			/* No cpl switch, rsp is not on stack */
			if (strcmp(kdbreglist[i].reg_name, "rsp") == 0) {
				*contents = (kdb_machreg_t)regs +
					sizeof(struct pt_regs) - 2*8;
				return(0);
			}
			if (strcmp(kdbreglist[i].reg_name, "ss") == 0) {
				kdb_machreg_t r;

				r = (kdb_machreg_t)regs +
					sizeof(struct pt_regs) - 2*8;
				*contents = (kdb_machreg_t)SS(r);	/* XXX */
				return(0);
			}
		}
		*contents = *(unsigned long *)((unsigned long)regs +
				kdbreglist[i].reg_offset);
		return(0);
	}

	for (i=0; i<ndbreglist; i++) {
		if (strnicmp(dbreglist[i].reg_name,
			     regname,
			     strlen(regname)) == 0)
			break;
	}

	if ((i < ndbreglist)
	 && (strlen(dbreglist[i].reg_name) == strlen(regname))) {
		*contents = kdba_getdr(dbreglist[i].reg_offset);
		return 0;
	}
	return KDB_BADREG;
}

/*
 * kdba_setregcontents
 *
 *	Set the contents of the register specified by the
 *	input string argument.   Return an error if the string
 *	does not match a machine register.
 *
 *	Supports modification of user-mode registers via
 *	%<register-name>
 *
 * Parameters:
 *	regname		Pointer to string naming register
 *	regs		Pointer to structure containing registers.
 *	contents	Unsigned long containing new register contents
 * Outputs:
 * Returns:
 *	0		Success
 *	KDB_BADREG	Invalid register name
 * Locking:
 * 	None.
 * Remarks:
 */

int
kdba_setregcontents(const char *regname,
		  struct pt_regs *regs,
		  unsigned long contents)
{
	int i;

	if (regname[0] == '%') {
		regname++;
		regs = (struct pt_regs *)
			(current->thread.rsp0 - sizeof(struct pt_regs));
	}

	for (i=0; i<nkdbreglist; i++) {
		if (strnicmp(kdbreglist[i].reg_name,
			     regname,
			     strlen(regname)) == 0)
			break;
	}

	if ((i < nkdbreglist)
	 && (strlen(kdbreglist[i].reg_name) == strlen(regname))) {
		*(unsigned long *)((unsigned long)regs
				   + kdbreglist[i].reg_offset) = contents;
		return 0;
	}

	for (i=0; i<ndbreglist; i++) {
		if (strnicmp(dbreglist[i].reg_name,
			     regname,
			     strlen(regname)) == 0)
			break;
	}

	if ((i < ndbreglist)
	 && (strlen(dbreglist[i].reg_name) == strlen(regname))) {
		kdba_putdr(dbreglist[i].reg_offset, contents);
		return 0;
	}

	return KDB_BADREG;
}

/*
 * kdba_dumpregs
 *
 *	Dump the specified register set to the display.
 *
 * Parameters:
 *	regs		Pointer to structure containing registers.
 *	type		Character string identifying register set to dump
 *	extra		string further identifying register (optional)
 * Outputs:
 * Returns:
 *	0		Success
 * Locking:
 * 	None.
 * Remarks:
 *	This function will dump the general register set if the type
 *	argument is NULL (struct pt_regs).   The alternate register
 *	set types supported by this function:
 *
 *	d 		Debug registers
 *	c		Control registers
 *	u		User registers at most recent entry to kernel
 * Following not yet implemented:
 *	m		Model Specific Registers (extra defines register #)
 *	r		Memory Type Range Registers (extra defines register)
 */

int
kdba_dumpregs(struct pt_regs *regs,
	    const char *type,
	    const char *extra)
{
	int i;
	int count = 0;

	if (type
	 && (type[0] == 'u')) {
		type = NULL;
		regs = (struct pt_regs *)
			(current->thread.rsp0 - sizeof(struct pt_regs));
	}

	if (type == NULL) {
		struct kdbregs *rlp;
		kdb_machreg_t contents;

		for (i=0, rlp=kdbreglist; i<nkdbreglist; i++,rlp++) {
			kdb_printf("%8s = ", rlp->reg_name);
			kdba_getregcontents(rlp->reg_name, regs, &contents);
			kdb_printf("0x%016lx ", contents);
			if ((++count % 2) == 0)
				kdb_printf("\n");
		}

		kdb_printf("&regs = 0x%p\n", regs);

		return 0;
	}

	switch (type[0]) {
	case 'd':
	{
		unsigned long dr[8];

		for(i=0; i<8; i++) {
			if ((i == 4) || (i == 5)) continue;
			dr[i] = kdba_getdr(i);
		}
		kdb_printf("dr0 = 0x%08lx  dr1 = 0x%08lx  dr2 = 0x%08lx  dr3 = 0x%08lx\n",
			   dr[0], dr[1], dr[2], dr[3]);
		kdb_printf("dr6 = 0x%08lx  dr7 = 0x%08lx\n",
			   dr[6], dr[7]);
		return 0;
	}
	case 'c':
	{
		unsigned long cr[5];

		for (i=0; i<5; i++) {
			cr[i] = kdb_getcr(i);
		}
		kdb_printf("cr0 = 0x%08lx  cr1 = 0x%08lx  cr2 = 0x%08lx  cr3 = 0x%08lx\ncr4 = 0x%08lx\n",
			   cr[0], cr[1], cr[2], cr[3], cr[4]);
		return 0;
	}
	case 'm':
		break;
	case 'r':
		break;
	default:
		return KDB_BADREG;
	}

	/* NOTREACHED */
	return 0;
}

kdb_machreg_t
kdba_getpc(struct pt_regs *regs)
{
	return regs->rip;
}

int
kdba_setpc(struct pt_regs *regs, kdb_machreg_t newpc)
{
	if (KDB_NULL_REGS(regs))
		return KDB_BADREG;
	regs->rip = newpc;
	KDB_STATE_SET(IP_ADJUSTED);
	return 0;
}

/*
 * kdba_main_loop
 *
 *	Do any architecture specific set up before entering the main kdb loop.
 *	The primary function of this routine is to make all processes look the
 *	same to kdb, kdb must be able to list a process without worrying if the
 *	process is running or blocked, so make all process look as though they
 *	are blocked.
 *
 * Inputs:
 *	reason		The reason KDB was invoked
 *	error		The hardware-defined error code
 *	error2		kdb's current reason code.  Initially error but can change
 *			acording to kdb state.
 *	db_result	Result from break or debug point.
 *	ef		The exception frame at time of fault/breakpoint.  If reason
 *			is KDB_REASON_SILENT then ef is NULL, otherwise it should
 *			always be valid.
 * Returns:
 *	0	KDB was invoked for an event which it wasn't responsible
 *	1	KDB handled the event for which it was invoked.
 * Outputs:
 *	Sets rip and rsp in current->thread.
 * Locking:
 *	None.
 * Remarks:
 *	none.
 */

int
kdba_main_loop(kdb_reason_t reason, kdb_reason_t reason2, int error,
	       kdb_dbtrap_t db_result, struct pt_regs *regs)
{
	int ret;

	if (regs)
		kdba_getregcontents("rsp", regs, &(current->thread.rsp));
	kdb_save_running(regs);
	ret = kdb_main_loop(reason, reason2, error, db_result, regs);
	kdb_unsave_running(regs);
	return ret;
}

void
kdba_disableint(kdb_intstate_t *state)
{
	unsigned long *fp = (unsigned long *)state;
	unsigned long flags;

	local_irq_save(flags);
	*fp = flags;
}

void
kdba_restoreint(kdb_intstate_t *state)
{
	unsigned long flags = *(unsigned long *)state;
	local_irq_restore(flags);
}

void
kdba_setsinglestep(struct pt_regs *regs)
{
	if (KDB_NULL_REGS(regs))
		return;
	if (regs->eflags & EF_IE)
		KDB_STATE_SET(A_IF);
	else
		KDB_STATE_CLEAR(A_IF);
	regs->eflags = (regs->eflags | EF_TF) & ~EF_IE;
}

void
kdba_clearsinglestep(struct pt_regs *regs)
{
	if (KDB_NULL_REGS(regs))
		return;
	if (KDB_STATE(A_IF))
		regs->eflags |= EF_IE;
	else
		regs->eflags &= ~EF_IE;
}

#ifdef KDB_HAVE_LONGJMP
int asmlinkage
kdba_setjmp(kdb_jmp_buf *jb)
{
#if defined(CONFIG_FRAME_POINTER)
	__asm__("movq %rbx, (0*8)(%rdi);"
		"movq %rbp, (1*8)(%rdi);"
		"movq %r12, (2*8)(%rdi);"
		"movq %r13, (3*8)(%rdi);"
		"movq %r14, (4*8)(%rdi);"
		"movq %r15, (5*8)(%rdi);"
		"leaq 16(%rsp), %rdx;"
		"movq %rdx, (6*8)(%rdi);"
		"movq (%rsp), %rax;"
		"movq %rax, (7*8)(%rdi)");
#else	 /* CONFIG_FRAME_POINTER */
	__asm__("movq %rbx, (0*8)(%rdi);"
		"movq %rbp, (1*8)(%rdi);"
		"movq %r12, (2*8)(%rdi);"
		"movq %r13, (3*8)(%rdi);"
		"movq %r14, (4*8)(%rdi);"
		"movq %r15, (5*8)(%rdi);"
		"leaq 8(%rsp), %rdx;"
		"movq %rdx, (6*8)(%rdi);"
		"movq (%rsp), %rax;"
		"movq %rax, (7*8)(%rdi)");
#endif   /* CONFIG_FRAME_POINTER */
	KDB_STATE_SET(LONGJMP);
	return 0;
}

void asmlinkage
kdba_longjmp(kdb_jmp_buf *jb, int reason)
{
#if defined(CONFIG_FRAME_POINTER)
	__asm__("movq (0*8)(%rdi),%rbx;"
		"movq (1*8)(%rdi),%rbp;"
		"movq (2*8)(%rdi),%r12;"
		"movq (3*8)(%rdi),%r13;"
		"movq (4*8)(%rdi),%r14;"
		"movq (5*8)(%rdi),%r15;"
		"test %esi,%esi;"
		"mov $01,%eax;"
		"cmove %eax,%esi;"
		"mov %esi, %eax;"
		"movq (7*8)(%rdi),%rdx;"
		"movq (6*8)(%rdi),%rsp;"
		"jmpq *%rdx");
#else    /* CONFIG_FRAME_POINTER */
	__asm__("movq (0*8)(%rdi),%rbx;"
		"movq (1*8)(%rdi),%rbp;"
		"movq (2*8)(%rdi),%r12;"
		"movq (3*8)(%rdi),%r13;"
		"movq (4*8)(%rdi),%r14;"
		"movq (5*8)(%rdi),%r15;"
		"test %esi,%esi;"
		"mov $01,%eax;"
		"cmove %eax,%esi;"
		"mov %esi, %eax;"
		"movq (7*8)(%rdi),%rdx;"
		"movq (6*8)(%rdi),%rsp;"
		"jmpq *%rdx");
#endif	 /* CONFIG_FRAME_POINTER */
}
#endif	/* KDB_HAVE_LONGJMP */

/*
 * kdba_enable_lbr
 *
 *	Enable last branch recording.
 *
 * Parameters:
 *	None.
 * Returns:
 *	None
 * Locking:
 *	None
 * Remarks:
 *	None.
 */

static unsigned char lbr_warned;

void
kdba_enable_lbr(void)
{
	u32  lv, hv;

	if (!test_bit(X86_FEATURE_MCA, &boot_cpu_data.x86_capability)) {
		if (lbr_warned) {
			kdb_printf("kdb: machine does not support last branch recording\n");
			lbr_warned = 1;
		}
		return;
	}
	rdmsr(MSR_IA32_DEBUGCTLMSR, lv, hv);
	lv |= 0x1;	/* Set LBR enable */
	wrmsr(MSR_IA32_DEBUGCTLMSR, lv, hv);
}

/*
 * kdba_disable_lbr
 *
 *	disable last branch recording.
 *
 * Parameters:
 *	None.
 * Returns:
 *	None
 * Locking:
 *	None
 * Remarks:
 *	None.
 */

void
kdba_disable_lbr(void)
{
	u32  lv, hv;

	if (!test_bit(X86_FEATURE_MCA, &boot_cpu_data.x86_capability)) {
		if (lbr_warned) {
			kdb_printf("kdb: machine does not support last branch recording\n");
			lbr_warned = 1;
		}
		return;
	}
	rdmsr(MSR_IA32_DEBUGCTLMSR, lv, hv);
	lv &= ~0x1;	/* Set LBR disable */
	wrmsr(MSR_IA32_DEBUGCTLMSR, lv, hv);
}

/*
 * kdba_print_lbr
 *
 *	Print last branch and last exception addresses
 *
 * Parameters:
 *	None.
 * Returns:
 *	None
 * Locking:
 *	None
 * Remarks:
 *	None.
 */

void
kdba_print_lbr(void)
{
	u32  from, to, dummy;

	if (!test_bit(X86_FEATURE_MCA, &boot_cpu_data.x86_capability))
		return;

	rdmsr(MSR_IA32_LASTBRANCHFROMIP, from, dummy);
	rdmsr(MSR_IA32_LASTBRANCHTOIP, to, dummy);
	kdb_printf("Last Branch IP, from: ");
	kdb_symbol_print(from, NULL, KDB_SP_DEFAULT);
	kdb_printf(" to: ");
	kdb_symbol_print(to, NULL, KDB_SP_DEFAULT);
	kdb_printf("\n");
	rdmsr(MSR_IA32_LASTINTFROMIP, from, dummy);
	rdmsr(MSR_IA32_LASTINTTOIP, to, dummy);
	kdb_printf("Last Int IP, from: ");
	kdb_symbol_print(from, NULL, KDB_SP_DEFAULT);
	kdb_printf(" to: ");
	kdb_symbol_print(to, NULL, KDB_SP_DEFAULT);
	kdb_printf("\n");
}

/*
 * kdba_entry
 *
 *	This is the interface routine between
 *	the notifier die_chain and kdb
 */
static int kdba_entry( struct notifier_block *b, unsigned long val, void *v)
{
	struct die_args *args = v;
	int err, trap, ret = 0;
	struct pt_regs *regs;

	regs = args->regs;
	err  = args->err;
	trap  = args->trapnr;
	switch (val){
#if defined(CONFIG_SMP)
		case DIE_NMI_IPI:
			ret = kdb_ipi(regs, NULL);
			break;
#endif
		case DIE_OOPS:
			ret = kdb(KDB_REASON_OOPS, err, regs);
			break;
		case DIE_CALL:
			ret = kdb(KDB_REASON_ENTER, err, regs);
			break;
		case DIE_DEBUG:
			ret = kdb(KDB_REASON_DEBUG, err, regs);
			break;
		case DIE_INT3:
			 ret = kdb(KDB_REASON_BREAK, err, regs);
			// falls thru
		default:
			break;
	}
	return (ret ? NOTIFY_STOP : NOTIFY_DONE);
}

/*
 * notifier block for kdb entry
 */
static struct notifier_block kdba_notifier = {
	.notifier_call = kdba_entry
};

/*
 * kdba_init
 *
 * 	Architecture specific initialization.
 *
 * Parameters:
 *	None.
 * Returns:
 *	None.
 * Locking:
 *	None.
 * Remarks:
 *	None.
 */

void __init
kdba_init(void)
{
	kdba_enable_lbr();
	atomic_notifier_chain_register(&die_chain, &kdba_notifier);
	return;
}

/*
 * kdba_adjust_ip
 *
 * 	Architecture specific adjustment of instruction pointer before leaving
 *	kdb.
 *
 * Parameters:
 *	reason		The reason KDB was invoked
 *	error		The hardware-defined error code
 *	ef		The exception frame at time of fault/breakpoint.  If reason
 *			is KDB_REASON_SILENT then ef is NULL, otherwise it should
 *			always be valid.
 * Returns:
 *	None.
 * Locking:
 *	None.
 * Remarks:
 *	noop on ix86.
 */

void
kdba_adjust_ip(kdb_reason_t reason, int error, struct pt_regs *ef)
{
	return;
}

/* dummy code to make common layer happy for now */
void
kdba_enable_mce(void)
{
}

void
kdba_set_current_task(const struct task_struct *p)
{
	kdb_current_task = p;
	if (kdb_task_has_cpu(p)) {
		struct kdb_running_process *krp = kdb_running_process + kdb_process_cpu(p);
		kdb_current_regs = krp->regs;
		return;
	}
	kdb_current_regs = NULL;
}

#ifdef CONFIG_SMP	// This is a hack, sigh...
void
smp_kdb_stop(void)
{
	send_IPI_allbutself(NMI_VECTOR);
}
#endif