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

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

Revision 1.16, Tue Dec 20 14:26:22 2005 UTC (11 years, 9 months ago) by nathans.longdrop.melbourne.sgi.com
Branch: MAIN
Changes since 1.15: +0 -0 lines

Merge up to 2.6.15-rc6
Merge of 2.6.x-xfs-melb:linux:24891a 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/module.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/ptrace.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/kdb.h>
#include <linux/kdbprivate.h>

#include <asm/processor.h>
#include <asm/msr.h>
#include <asm/uaccess.h>

/*
 * kdba_find_return_1
 *
 *	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
 *	assume	When false, do not apply tests that have to assume a branch is valid
 * 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_1(kdb_machreg_t sp, kdb_machreg_t ss, const kdb_symtab_t *symtab, int assume)
{
	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)]

	for (;ret = 0, sp & (THREAD_SIZE-1);sp += 4) {
		if (KDB_DEBUG(ARA)) {
			kdb_printf("    sp=0x%lx", sp);
		}
		if (kdb_getword(&ret, sp, 4))
			break;
		if (ret > PAGE_SIZE)
			kdbnearsym(ret, &caller_symtab);
		else
			memset(&caller_symtab, 0, sizeof(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");
				}
				break;		/* call to this function */
			}
			if (KDB_DEBUG(ARA)) {
				kdb_printf(" failed");
			}
		} 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");
			}
			if (ret + (s32) disp32 == symtab->sym_start) {
				if (KDB_DEBUG(ARA)) {
					kdb_printf(" matched");
				}
				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");
			}
			if (ret + (s8) disp8 == symtab->sym_start) {
				if (KDB_DEBUG(ARA)) {
					kdb_printf(" matched");
				}
				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");
			}
			break;		/* special case, hand crafted frame */
		} else if (!assume) {
			/* All following tests cannot validate the target address so they
			 * must assume that the return address is valid.
			 */
			if (KDB_DEBUG(ARA)) {
				kdb_printf("\n");
			}
			continue;
		} else if (retaddr(-7) == 0xff && retaddr(-6) == 0x14 && retaddr(-5) == 0x85) {
			/* call *disp32(,%eax,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)) {
				kdb_printf(" call *0xnnnn(,%%eax,4)");
			}
			if (strncmp(symtab->sym_name, "sys_", 4) == 0 ||
			    strncmp(symtab->sym_name, "old_", 4) == 0) {
				if (KDB_DEBUG(ARA)) {
					kdb_printf(" assume valid");
				}
				break;		/* probably call to this function */
			}
			if (KDB_DEBUG(ARA)) {
				kdb_printf(" failed");
			}
		} else if (retaddr(-2) == 0xff &&
			   ((retaddr(-1) & 0xf8) == 0xd0 || (retaddr(-1) & 0xf8) == 0x10)) {
			/* call *%reg.  Cannot validate, have to assume
			 * it is valid.
			 */
			if (KDB_DEBUG(ARA)) {
				kdb_printf(" call *%%reg, assume valid");
			}
			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");
			}
			break;		/* hope it is a call to this function */
		} else if (retaddr(-6) == 0xff && (retaddr(-5) & 0xf8) == 0x90) {
			/* call *disp32(%reg).  Cannot validate, have to assume
			 * it is valid.
			 */
			if (KDB_DEBUG(ARA)) {
				kdb_printf(" call *disp32(%%reg), assume valid");
			}
			break;		/* hope it is a call to this function */
		}
		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_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;

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

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

	if (KDB_DEBUG(ARA)) {
		kdb_printf(" kdba_find_return_1(assume==0)\n");
	}
	if ((ret = kdba_find_return_1(sp, ss, symtab, 0)))
		return ret;
	if (KDB_DEBUG(ARA)) {
		kdb_printf(" kdba_find_return_1(assume==1)\n");
	}
	ret = kdba_find_return_1(sp, ss, symtab, 1);
	return ret;
}

/*
 * 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 eip.
 * Inputs:
 *	code	Start address of function code to analyze
 *	pc	Current program counter within function
 *	sp	Current stack pointer for function
 *	fp	Current frame pointer for function, may not be valid
 *	ss	Start of stack for current process.
 *	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:
 *
 *	A prologue for ia32 generally looks like:
 *
 *		pushl  %ebp		[All functions, but only if
 *		movl   %esp, %ebp	 compiled with frame pointers]
 *		subl   $auto, %esp	[some functions]
 *		pushl  %reg		[some functions]
 *		pushl  %reg		[some functions]
 *
 *	FIXME: Mike Galbraith says that gcc 2.95 can generate a slightly
 *	       different prologue.  No support for gcc 2.95 yet.
 */

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 = 4;
		ar->end = sp;
		ar->start = ar->end + 4;
		kdb_getword(&(ar->ret), sp, 4);
		if (KDB_DEBUG(ARA)) {
			kdb_printf("  pc==0: ret=0x%lx\n", ar->ret);
		}
		return(1);
	}

	if (code == 0 || sp & 3 || ss != (sp & -THREAD_SIZE))
		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*4;	/* 6 parameters */
		if ((ar->start & -THREAD_SIZE) != ss)
			ar->start = 0;
		return(1);
	}

	ar->setup = 4;	/* 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 %ebp */
		ar->setup += 4;	/* Frame pointer is on stack */
		oldfp_present = 1;
		++code;
		if (KDB_DEBUG(ARA)) {
			kdb_printf("  pushl %%ebp\n");
		}
		if (code < pc && instruction[0] == 0x89 && instruction[1] == 0xe5) {
			/* movl %esp,%ebp */
			if (fp >= sp && (fp & -THREAD_SIZE) == ss)
				ar->fp = fp;	/* %ebp has been set */
			code += 2;
			if (KDB_DEBUG(ARA)) {
				kdb_printf("  movl %%esp,%%ebp, fp=0x%lx\n", ar->fp);
			}
		}
	}

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

	while (!unwound && code < pc &&
	       kdb_getarea(instruction, code) == 0 &&
	       (instruction[0] & 0xf8) == 0x50) {
		/* pushl %reg */
		ar->regs += 4;
		++code;
		if (KDB_DEBUG(ARA)) {
			kdb_printf("  pushl %%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 -= 4;
	if (KDB_DEBUG(ARA)) {
		kdb_printf("  ret_p(0)=0x%lx\n", ret_p);
	}
	ar->ret = 0;
	if ((ret_p & -THREAD_SIZE) == ss &&
	    (ret_p = kdba_find_return(ret_p, ss, symtab))) {
		kdb_getword(&(ar->ret), ret_p, 4);
	}
	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 + 4;	/* "accurate" fp */
		ar->start = ret_p + 4;
		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, 4);
		if (KDB_DEBUG(ARA)) {
			kdb_printf("  oldfp=0x%lx", ar->oldfp);
		}
		if (ar->oldfp <= ar->fp || (ar->oldfp & -THREAD_SIZE) != ss) {
			ar->oldfp = 0;
			if (KDB_DEBUG(ARA)) {
				kdb_printf(" (out of range)");
			}
		}
		if (KDB_DEBUG(ARA)) {
			kdb_printf("\n");
		}
	}
	return(1);
}

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

	return contents;
}

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

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

	return contents;
}

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);
}


/*
 * 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
 *	   kesp		 - Prints kernel stack pointer at time of fault
 *	   cesp		 - 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 esp are *not* on the stack.
 */

static struct kdbregs {
	char   *reg_name;
	size_t	reg_offset;
} kdbreglist[] = {
	{ "eax",	offsetof(struct pt_regs, eax) },
	{ "ebx",	offsetof(struct pt_regs, ebx) },
	{ "ecx",	offsetof(struct pt_regs, ecx) },
	{ "edx",	offsetof(struct pt_regs, edx) },

	{ "esi",	offsetof(struct pt_regs, esi) },
	{ "edi",	offsetof(struct pt_regs, edi) },
	{ "esp",	offsetof(struct pt_regs, esp) },
	{ "eip",	offsetof(struct pt_regs, eip) },

	{ "ebp",	offsetof(struct pt_regs, ebp) },
	{ "xss", 	offsetof(struct pt_regs, xss) },
	{ "xcs",	offsetof(struct pt_regs, xcs) },
	{ "eflags", 	offsetof(struct pt_regs, eflags) },

	{ "xds", 	offsetof(struct pt_regs, xds) },
	{ "xes", 	offsetof(struct pt_regs, xes) },
	{ "origeax",	offsetof(struct pt_regs, orig_eax) },

};

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, "cesp") == 0) {
		asm volatile("movl %%esp,%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:  %%e[a-c]x, etc */
		regname++;
		regs = (struct pt_regs *)
			(kdb_current_task->thread.esp0 - sizeof(struct pt_regs));
	}

	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;
	}

	if (!regs) {
		kdb_printf("%s: pt_regs not available, use bt* or pid to select a different task\n", __FUNCTION__);
		return KDB_BADREG;
	}

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

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

	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->xcs & 0xffff) == __KERNEL_CS) {
			/* No cpl switch, esp and ss are not on stack */
			if (strcmp(kdbreglist[i].reg_name, "esp") == 0) {
				*contents = (kdb_machreg_t)regs +
					sizeof(struct pt_regs) - 2*4;
				return(0);
			}
			if (strcmp(kdbreglist[i].reg_name, "xss") == 0) {
				asm volatile(
					"pushl %%ss\n"
					"popl %0\n"
					:"=m" (*contents));
				return(0);
			}
		}
		*contents = *(unsigned long *)((unsigned long)regs +
				kdbreglist[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 *)
			(kdb_current_task->thread.esp0 - sizeof(struct pt_regs));
	}

	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;
	}

	if (!regs) {
		kdb_printf("%s: pt_regs not available, use bt* or pid to select a different task\n", __FUNCTION__);
		return KDB_BADREG;
	}

	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;
	}

	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
 *			for the process currently selected with "pid" command.
 * 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 *)
			(kdb_current_task->thread.esp0 - sizeof(struct pt_regs));
	}

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

		if (!regs) {
			kdb_printf("%s: pt_regs not available, use bt* or pid to select a different task\n", __FUNCTION__);
			return KDB_BADREG;
		}

		for (i=0, rlp=kdbreglist; i<nkdbreglist; i++,rlp++) {
			kdb_printf("%s = ", rlp->reg_name);
			kdba_getregcontents(rlp->reg_name, regs, &contents);
			kdb_printf("0x%08lx ", contents);
			if ((++count % 4) == 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] = kdba_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;
}
EXPORT_SYMBOL(kdba_dumpregs);

kdb_machreg_t
kdba_getpc(struct pt_regs *regs)
{
	return regs ? regs->eip : 0;
}

int
kdba_setpc(struct pt_regs *regs, kdb_machreg_t newpc)
{
	if (KDB_NULL_REGS(regs))
		return KDB_BADREG;
	regs->eip = 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.
 *	regs		The exception frame at time of fault/breakpoint.  If reason
 *			is KDB_REASON_SILENT then regs 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 eip and esp 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;
	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 = *(int *)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__ ("movl 8(%esp), %eax\n\t"
		 "movl %ebx, 0(%eax)\n\t"
		 "movl %esi, 4(%eax)\n\t"
		 "movl %edi, 8(%eax)\n\t"
		 "movl (%esp), %ecx\n\t"
		 "movl %ecx, 12(%eax)\n\t"
		 "leal 8(%esp), %ecx\n\t"
		 "movl %ecx, 16(%eax)\n\t"
		 "movl 4(%esp), %ecx\n\t"
		 "movl %ecx, 20(%eax)\n\t");
#else	 /* CONFIG_FRAME_POINTER */
	__asm__ ("movl 4(%esp), %eax\n\t"
		 "movl %ebx, 0(%eax)\n\t"
		 "movl %esi, 4(%eax)\n\t"
		 "movl %edi, 8(%eax)\n\t"
		 "movl %ebp, 12(%eax)\n\t"
		 "leal 4(%esp), %ecx\n\t"
		 "movl %ecx, 16(%eax)\n\t"
		 "movl 0(%esp), %ecx\n\t"
		 "movl %ecx, 20(%eax)\n\t");
#endif   /* CONFIG_FRAME_POINTER */
	return 0;
}

void asmlinkage
kdba_longjmp(kdb_jmp_buf *jb, int reason)
{
#if defined(CONFIG_FRAME_POINTER)
	__asm__("movl 8(%esp), %ecx\n\t"
		"movl 12(%esp), %eax\n\t"
		"movl 20(%ecx), %edx\n\t"
		"movl 0(%ecx), %ebx\n\t"
		"movl 4(%ecx), %esi\n\t"
		"movl 8(%ecx), %edi\n\t"
		"movl 12(%ecx), %ebp\n\t"
		"movl 16(%ecx), %esp\n\t"
		"jmp *%edx\n");
#else    /* CONFIG_FRAME_POINTER */
	__asm__("movl 4(%esp), %ecx\n\t"
		"movl 8(%esp), %eax\n\t"
		"movl 20(%ecx), %edx\n\t"
		"movl 0(%ecx), %ebx\n\t"
		"movl 4(%ecx), %esi\n\t"
		"movl 8(%ecx), %edi\n\t"
		"movl 12(%ecx), %ebp\n\t"
		"movl 16(%ecx), %esp\n\t"
		"jmp *%edx\n");
#endif	 /* CONFIG_FRAME_POINTER */
}
#endif	/* KDB_HAVE_LONGJMP */


/*
 * kdba_enable_mce
 *
 *	This function is called once on each CPU to enable machine
 *	check exception handling.
 *
 * Inputs:
 *	None.
 * Outputs:
 *	None.
 * Returns:
 *	None.
 * Locking:
 *	None.
 * Remarks:
 *
 */

void
kdba_enable_mce(void)
{
	/* No longer required, arch/i386/kernel/bluesmoke.c does the job now */
}

/*
 * 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_pt_regs
 *
 *	Format a struct pt_regs
 *
 * Inputs:
 *	argc	argument count
 *	argv	argument vector
 *	envp	environment vector
 *	regs	registers at time kdb was entered.
 * Outputs:
 *	None.
 * Returns:
 *	zero for success, a kdb diagnostic if error
 * Locking:
 *	none.
 * Remarks:
 *	If no address is supplied, it uses regs.
 */

static int
kdba_pt_regs(int argc, const char **argv, const char **envp, struct pt_regs *regs)
{
	int diag;
	kdb_machreg_t addr;
	long offset = 0;
	int nextarg;
	struct pt_regs *p;
	static const char *fmt = "  %-11.11s 0x%lx\n";

	if (argc == 0) {
		addr = (kdb_machreg_t) regs;
	} else if (argc == 1) {
		nextarg = 1;
		diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs);
		if (diag)
			return diag;
	} else {
		return KDB_ARGCOUNT;
	}

	p = (struct pt_regs *) addr;
	kdb_printf("struct pt_regs %p-%p\n", p, (unsigned char *)p + sizeof(*p) - 1);
	kdb_print_nameval("ebx", p->ebx);
	kdb_print_nameval("ecx", p->ecx);
	kdb_print_nameval("edx", p->edx);
	kdb_print_nameval("esi", p->esi);
	kdb_print_nameval("edi", p->edi);
	kdb_print_nameval("ebp", p->ebp);
	kdb_print_nameval("eax", p->eax);
	kdb_printf(fmt, "xds", p->xds);
	kdb_printf(fmt, "xes", p->xes);
	kdb_print_nameval("orig_eax", p->orig_eax);
	kdb_print_nameval("eip", p->eip);
	kdb_printf(fmt, "xcs", p->xcs);
	kdb_printf(fmt, "eflags", p->eflags);
	kdb_printf(fmt, "esp", p->esp);
	kdb_printf(fmt, "xss", p->xss);
	return 0;
}

/*
 * kdba_stackdepth
 *
 *	Print processes that are using more than a specific percentage of their
 *	stack.
 *
 * Inputs:
 *	argc	argument count
 *	argv	argument vector
 *	envp	environment vector
 *	regs	registers at time kdb was entered.
 * Outputs:
 *	None.
 * Returns:
 *	zero for success, a kdb diagnostic if error
 * Locking:
 *	none.
 * Remarks:
 *	If no percentage is supplied, it uses 60.
 */

static void
kdba_stackdepth1(struct task_struct *p, unsigned long esp)
{
	struct thread_info *tinfo;
	int used;
	const char *type;
	kdb_ps1(p);
	do {
		tinfo = (struct thread_info *)(esp & -THREAD_SIZE);
		used = sizeof(*tinfo) + THREAD_SIZE - (esp & (THREAD_SIZE-1));
		type = NULL;
#ifdef CONFIG_4KSTACKS
		if (kdb_task_has_cpu(p))
			type = kdba_irq_ctx_type(kdb_process_cpu(p), tinfo);
#endif
		if (!type)
			type = "process";
		kdb_printf("  %s stack %p esp %lx used %d\n", type, tinfo, esp, used);
		esp = tinfo->previous_esp;
	} while (esp);
}

static int
kdba_stackdepth(int argc, const char **argv, const char **envp, struct pt_regs *regs)
{
	int diag, cpu, threshold, used, over;
	long percentage;
	unsigned long esp;
	long offset = 0;
	int nextarg;
	struct task_struct *p, *g;
	struct kdb_running_process *krp;
	struct thread_info *tinfo;

	if (argc == 0) {
		percentage = 60;
	} else if (argc == 1) {
		nextarg = 1;
		diag = kdbgetaddrarg(argc, argv, &nextarg, &percentage, &offset, NULL, regs);
		if (diag)
			return diag;
	} else {
		return KDB_ARGCOUNT;
	}
	percentage = max_t(int, percentage, 1);
	percentage = min_t(int, percentage, 100);
	threshold = ((2 * THREAD_SIZE * percentage) / 100 + 1) >> 1;
	kdb_printf("stackdepth: processes using more than %ld%% (%d bytes) of stack\n",
		percentage, threshold);

	/* Run the active tasks first, they can have multiple stacks */
	for (cpu = 0, krp = kdb_running_process; cpu < NR_CPUS; ++cpu, ++krp) {
		if (!cpu_online(cpu))
			continue;
		p = krp->p;
		esp = krp->arch.esp;
		over = 0;
		do {
			tinfo = (struct thread_info *)(esp & -THREAD_SIZE);
			used = sizeof(*tinfo) + THREAD_SIZE - (esp & (THREAD_SIZE-1));
			if (used >= threshold)
				over = 1;
			esp = tinfo->previous_esp;
		} while (esp);
		if (over)
			kdba_stackdepth1(p, krp->arch.esp);
	}
	/* Now the tasks that are not on cpus */
	kdb_do_each_thread(g, p) {
		if (kdb_task_has_cpu(p))
			continue;
		esp = p->thread.esp;
		used = sizeof(*tinfo) + THREAD_SIZE - (esp & (THREAD_SIZE-1));
		over = used >= threshold;
		if (over)
			kdba_stackdepth1(p, esp);
	} kdb_while_each_thread(g, p);

	return 0;
}

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

void __init
kdba_init(void)
{
	kdba_enable_lbr();
	kdb_register("pt_regs", kdba_pt_regs, "address", "Format struct pt_regs", 0);
	kdb_register("stackdepth", kdba_stackdepth, "[percentage]", "Print processes using >= stack percentage", 0);

	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
 *	regs		The exception frame at time of fault/breakpoint.  If reason
 *			is KDB_REASON_SILENT then regs 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 *regs)
{
	return;
}

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;
}