/* x86.c - core analysis suite
 *
 * Portions Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc.
 * Copyright (C) 2002-2014,2017 David Anderson
 * Copyright (C) 2002-2014,2017 Red Hat, Inc. All rights reserved.
 *
 * 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 of the License, 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.
 */

#ifdef X86
/*
 *                     NOTICE OF APPRECIATION
 *
 *  The stack-trace related code in this file is an extension of the stack 
 *  trace code from the Mach in-kernel debugger "ddb".  Sincere thanks to 
 *  the author(s).
 *
 */

/*
 * Mach Operating System
 * Copyright (c) 1991,1990 Carnegie Mellon University
 * All Rights Reserved.
 *
 * Permission to use, copy, modify and distribute this software and its
 * documentation is hereby granted, provided that both the copyright
 * notice and this permission notice appear in all copies of the
 * software, derivative works or modified versions, and any portions
 * thereof, and that both notices appear in supporting documentation.
 *
 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
 *
 * Carnegie Mellon requests users of this software to return to
 *
 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
 *  School of Computer Science
 *  Carnegie Mellon University
 *  Pittsburgh PA 15213-3890
 *
 * any improvements or extensions that they make and grant Carnegie the
 * rights to redistribute these changes.
 */
#include "defs.h"
#include "xen_hyper_defs.h"

#ifndef MCLX

#include <sys/param.h>
#include <sys/systm.h>

#include <machine/cpu.h>

#include <vm/vm.h>
#include <vm/vm_param.h>
#include <vm/pmap.h>
#include <ddb/ddb.h>

#include <ddb/db_access.h>
#include <ddb/db_sym.h>
#include <ddb/db_variables.h>

/*
 * Machine register set.
 */
struct db_variable db_regs[] = {
	"cs",	&ddb_regs.tf_cs,  FCN_NULL,
	"ds",	&ddb_regs.tf_ds,  FCN_NULL,
	"es",	&ddb_regs.tf_es,  FCN_NULL,
#if 0
	"fs",	&ddb_regs.tf_fs,  FCN_NULL,
	"gs",	&ddb_regs.tf_gs,  FCN_NULL,
#endif
	"ss",	&ddb_regs.tf_ss,  FCN_NULL,
	"eax",	&ddb_regs.tf_eax, FCN_NULL,
	"ecx",	&ddb_regs.tf_ecx, FCN_NULL,
	"edx",	&ddb_regs.tf_edx, FCN_NULL,
	"ebx",	&ddb_regs.tf_ebx, FCN_NULL,
	"esp",	&ddb_regs.tf_esp, FCN_NULL,
	"ebp",	&ddb_regs.tf_ebp, FCN_NULL,
	"esi",	&ddb_regs.tf_esi, FCN_NULL,
	"edi",	&ddb_regs.tf_edi, FCN_NULL,
	"eip",	&ddb_regs.tf_eip, FCN_NULL,
	"efl",	&ddb_regs.tf_eflags, FCN_NULL,
};
struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]);
#else

typedef int             db_strategy_t;  /* search strategy */

#define DB_STGY_ANY     0                       /* anything goes */
#define DB_STGY_XTRN    1                       /* only external symbols */
#define DB_STGY_PROC    2                       /* only procedures */

typedef ulong           db_addr_t;      /* address - unsigned */
typedef int             db_expr_t;      /* expression - signed */

/*
 * Symbol representation is specific to the symtab style:
 * BSD compilers use dbx' nlist, other compilers might use
 * a different one
 */
typedef char *          db_sym_t;       /* opaque handle on symbols */
#define DB_SYM_NULL     ((db_sym_t)0)

typedef uint            boolean_t;

#endif /* !MCLX */

/*
 * Stack trace.
 */
#ifdef MCLX
static db_expr_t db_get_value(db_addr_t, int, boolean_t, struct bt_info *);
#define INKERNEL(va) (machdep->kvtop(CURRENT_CONTEXT(), va, &phys, 0))
#else
#define	INKERNEL(va)	(((vm_offset_t)(va)) >= USRSTACK)
#endif

struct i386_frame {
	struct i386_frame	*f_frame;
	int			f_retaddr;
	int			f_arg0;
};

#ifdef MCLX
#define NORMAL              0
#define IDT_DIRECT_ENTRY    1
#define IDT_JMP_ERROR_CODE  2
#define RET_FROM_INTR       3
#define SIGNAL_RETURN       4
#else
#define NORMAL		0
#define	TRAP		1
#define	INTERRUPT	2
#define	SYSCALL		3
#endif

#ifndef MCLX
typedef vm_offset_t     db_addr_t;
#endif

#ifdef MCLX
struct eframe {
        int eframe_found;
	int eframe_type;
        ulong eframe_addr;
	ulong jmp_error_code_eip;
};

static void db_nextframe(struct i386_frame **, db_addr_t *, struct eframe *,
	struct bt_info *);
static int dump_eframe(struct eframe *, int, struct bt_info *);
static int eframe_numargs(ulong eip, struct bt_info *);
static int check_for_eframe(char *, struct bt_info *);
static void x86_user_eframe(struct bt_info *);
static ulong x86_next_eframe(ulong addr, struct bt_info *bt);
static void x86_cmd_mach(void);
static int x86_get_smp_cpus(void);
static void x86_display_machine_stats(void);
static void x86_display_cpu_data(unsigned int);
static void x86_display_memmap(void);
static int x86_omit_frame_pointer(void);
static void x86_back_trace_cmd(struct bt_info *);
static int is_rodata_text(ulong);
static int mach_CRASHDEBUG(ulong);
static db_sym_t db_search_symbol(db_addr_t, db_strategy_t,db_expr_t *);
static void db_symbol_values(db_sym_t, char **, db_expr_t *);
static int db_sym_numargs(db_sym_t, int *, char **);
static void x86_dump_line_number(ulong);
static void x86_clear_machdep_cache(void);
static void x86_parse_cmdline_args(void);

static ulong mach_debug = 0;

static int
mach_CRASHDEBUG(ulong dval)
{
        if (CRASHDEBUG(dval))
                return TRUE;

        return (mach_debug >= dval);
}


#else
static void db_nextframe(struct i386_frame **, db_addr_t *);
#endif
#ifdef MCLX
static int db_numargs(struct i386_frame *, struct bt_info *bt);
static void db_print_stack_entry(char *, int, char **, int *, 
	    db_addr_t, struct bt_info *, struct eframe *, int, 
	    struct i386_frame *);
#else
static void db_print_stack_entry (char *, int, char **, int *, db_addr_t);
#endif

/*
 * Figure out how many arguments were passed into the frame at "fp".
 */
static int
db_numargs(fp, bt)
	struct i386_frame *fp;
	struct bt_info *bt;
{
	int	*argp;
	int	inst;
	int	args;

	argp = (int *)db_get_value((int)&fp->f_retaddr, 4, FALSE, bt);
	/*
	 * etext is wrong for LKMs.  We should attempt to interpret
	 * the instruction at the return address in all cases.  This
	 * may require better fault handling.
	 */
#ifdef MCLX
	if (!is_kernel_text((ulong)argp)) {
#else
	if (argp < (int *)btext || argp >= (int *)etext) {
#endif
		args = 5;
	} else {
		inst = db_get_value((int)argp, 4, FALSE, bt);
		if ((inst & 0xff) == 0x59)	/* popl %ecx */
			args = 1;
		else if ((inst & 0xffff) == 0xc483)	/* addl $Ibs, %esp */
			args = ((inst >> 16) & 0xff) / 4;
		else
			args = 5;
	}
	return (args);
}

#ifdef MCLX
static int
eframe_numargs(ulong eip, struct bt_info *bt)
{
        int     inst;
        int     args;

	if (!is_kernel_text(eip)) 
		args = 5;
	else {
                inst = db_get_value((int)eip, 4, FALSE, bt);
                if ((inst & 0xff) == 0x59)      /* popl %ecx */
                        args = 1;
                else if ((inst & 0xffff) == 0xc483)     /* addl $Ibs, %esp */
                        args = ((inst >> 16) & 0xff) / 4;
                else
                        args = 5;
        }

	return args;
}
#endif

static void
#ifdef MCLX
db_print_stack_entry(name, narg, argnp, argp, callpc, bt, ep, fnum, frame)
#else
db_print_stack_entry(name, narg, argnp, argp, callpc)
#endif
	char *name;
	int narg;
	char **argnp;
	int *argp;
	db_addr_t callpc;
#ifdef MCLX
	struct bt_info *bt;
	struct eframe *ep;
	int fnum;
	struct i386_frame *frame;
#endif
{
#ifdef MCLX
	int i;
	db_expr_t arg;
	char buf1[BUFSIZE];
	char buf2[BUFSIZE];
	char buf3[BUFSIZE];
	char *sp;

	if (!name) {
		if (IS_MODULE_VADDR(callpc) &&
		    module_symbol(callpc, NULL, NULL, buf1, *gdb_output_radix)) {
			sprintf(buf2, "(%s)", buf1);
			name = buf2;
		}
		else
			name = "(unknown module)";
	}

	if (strstr(name, "_MODULE_START_")) {
		sprintf(buf3, "(%s module)", name + strlen("_MODULE_START_"));
		name = buf3;
	}

	if (BT_REFERENCE_CHECK(bt)) {
		switch (bt->ref->cmdflags & (BT_REF_SYMBOL|BT_REF_HEXVAL))
		{
		case BT_REF_SYMBOL: 
			if (ep->eframe_found && ep->jmp_error_code_eip) {
			       if (STREQ(closest_symbol(ep->jmp_error_code_eip),
			    	   bt->ref->str) || 
				   STREQ(closest_symbol(callpc), bt->ref->str))
					bt->ref->cmdflags |= BT_REF_FOUND;
			} else if (STREQ(name, bt->ref->str))
				bt->ref->cmdflags |= BT_REF_FOUND;
			break;

		case BT_REF_HEXVAL: 
			if (ep->eframe_found && ep->jmp_error_code_eip &&
			    (bt->ref->hexval == ep->jmp_error_code_eip))
				bt->ref->cmdflags |= BT_REF_FOUND;   
			else if (bt->ref->hexval == callpc)
				bt->ref->cmdflags |= BT_REF_FOUND;
			break;
		}

		return;

	} else {
		fprintf(fp, "%s#%d [%08lx] ", 
			fnum < 10 ? " " : "", fnum, (ulong)frame);

		if (ep->eframe_found && ep->jmp_error_code_eip)
        		fprintf(fp, "%s (via %s)",
				closest_symbol(callpc),
                		closest_symbol(ep->jmp_error_code_eip));
		else
		fprintf(fp, "%s", name);

        	fprintf(fp, " at %lx\n", callpc);
	}

	if (ep->eframe_found) 
		goto done_entry;

	if (STREQ(name, "L6"))
		goto done_entry;

        fprintf(fp, "    (");

	if ((i = get_function_numargs(callpc)) >= 0)
		narg = i;

        while (narg) {
                if (argnp)
                        fprintf(fp, "%s=", *argnp++);

		arg = db_get_value((int)argp, 4, FALSE, bt);

		if ((sp = value_symbol(arg)))
			fprintf(fp, "%s", sp);
		else if ((bt->flags & BT_SYMBOLIC_ARGS) &&
		    strlen(value_to_symstr(arg, buf1, 0)))
			fprintf(fp, "%s", buf1);
		else
			fprintf(fp, "%x", arg);
		
                argp++;
                if (--narg != 0)
                        fprintf(fp, ", ");
        }

	if (i == 0)
		fprintf(fp, "void");

        fprintf(fp, ")\n");
done_entry:
	if (bt->flags & BT_LINE_NUMBERS) 
		x86_dump_line_number(callpc);

	return;

#else
	db_printf("%s(", name);
	while (narg) {
		if (argnp)
			db_printf("%s=", *argnp++);
		db_printf("%r", db_get_value((int)argp, 4, FALSE, bt));
		argp++;
		if (--narg != 0)
			db_printf(",");
  	}
	db_printf(") at ");
	db_printsym(callpc, DB_STGY_PROC);
	db_printf("\n");
	return;
#endif
}

#ifdef MCLX
static db_sym_t
db_search_symbol(db_addr_t val, db_strategy_t strategy, db_expr_t *offp) 
{
	struct syment *sp;
	ulong offset;

	if ((sp = value_search(val, &offset))) {
		*offp = (db_expr_t)offset;
		return(sp->name);
	} else
		return DB_SYM_NULL;
}

/*
 * Return name and value of a symbol
 */
static void
db_symbol_values(db_sym_t sym, char **namep, db_expr_t *valuep)
{
	struct syment   *sp;

        if (sym == DB_SYM_NULL) {
                *namep = 0;
                return;
        }

        if ((sp = symbol_search(sym)) == NULL) {
		error(INFO, "db_symbol_values: cannot find symbol: %s\n", sym);
                *namep = 0;
		return;
	}

	*namep = sp->name;
	if (valuep)
		*valuep = sp->value;

#ifndef MCLX
        X_db_symbol_values(db_last_symtab, sym, namep, &value);

        if (db_symbol_is_ambiguous(sym))
                *namep = db_qualify(sym, db_last_symtab->name);
        if (valuep)
                *valuep = value;
#endif
}

static unsigned db_extend[] = { /* table for sign-extending */
        0,
        0xFFFFFF80U,
        0xFFFF8000U,
        0xFF800000U
};

static db_expr_t
db_get_value(addr, size, is_signed, bt)
        db_addr_t        addr;
        int     	 size;
        boolean_t        is_signed;
	struct bt_info * bt;
{
        char            data[sizeof(int)];
        db_expr_t 	value;
        int    		i;

#ifndef MCLX
        db_read_bytes(addr, size, data);
#else
	BZERO(data, sizeof(int));
	if (INSTACK(addr, bt)) {
		if (size == sizeof(ulong)) 
			return (db_expr_t)GET_STACK_ULONG(addr); 
		else
			GET_STACK_DATA(addr, data, size);
	} else {
		if ((size == sizeof(int)) && 
		    text_value_cache(addr, 0, (uint32_t *)&value))
			return value;

		if (!readmem(addr, KVADDR, &value, size, "db_get_value", 
	    	     RETURN_ON_ERROR))
			error(FATAL, "db_get_value: read error: address: %lx\n",
				 addr);

		if (size == sizeof(int)) 
			text_value_cache(addr, value, NULL);
	}
#endif

        value = 0;
#if     BYTE_MSF
        for (i = 0; i < size; i++)
#else   /* BYTE_LSF */
        for (i = size - 1; i >= 0; i--)
#endif
        {
            value = (value << 8) + (data[i] & 0xFF);
        }

        if (size < 4) {
            if (is_signed && (value & db_extend[size]) != 0)
                value |= db_extend[size];
        }
        return (value);
}

static int
db_sym_numargs(db_sym_t sym, int *nargp, char **argnames)
{
        return FALSE;
}

#endif

/*
 * Figure out the next frame up in the call stack.
 */
#ifdef MCLX
static void
db_nextframe(fp, ip, ep, bt)
        struct i386_frame **fp;            /* in/out */
        db_addr_t          *ip;            /* out */
	struct eframe      *ep;
	struct bt_info     *bt;
#else
static void
db_nextframe(fp, ip)
	struct i386_frame **fp;		/* in/out */
	db_addr_t	*ip;		/* out */
#endif
{
	int eip, ebp;
	db_expr_t offset;
	char *sym, *name;
#ifdef MCLX
	static int last_ebp;
	static int last_eip;
	struct syment *sp;
#endif

	eip = db_get_value((int) &(*fp)->f_retaddr, 4, FALSE, bt);
	ebp = db_get_value((int) &(*fp)->f_frame, 4, FALSE, bt);

	/*
	 * Figure out frame type, presuming normal.
	 */
	BZERO(ep, sizeof(struct eframe));
	ep->eframe_type = NORMAL;

	sym = db_search_symbol(eip, DB_STGY_ANY, &offset);
	db_symbol_values(sym, &name, NULL);
	if (name != NULL) {
		ep->eframe_type = check_for_eframe(name, bt);
#ifndef MCLX
		if (!strcmp(name, "calltrap")) {
			frame_type = TRAP;
		} else if (!strncmp(name, "Xresume", 7)) {
			frame_type = INTERRUPT;
		} else if (!strcmp(name, "_Xsyscall")) {
			frame_type = SYSCALL;
		}
#endif
	}

	switch (ep->eframe_type)
	{
	case NORMAL:
                ep->eframe_found = FALSE;
                break;

	case IDT_DIRECT_ENTRY:
	case RET_FROM_INTR:
	case SIGNAL_RETURN:
                ep->eframe_found = TRUE;
                ep->eframe_addr = x86_next_eframe(last_ebp + sizeof(ulong)*2,
                    bt);
		break;

	case IDT_JMP_ERROR_CODE:
                ep->eframe_found = TRUE;
                ep->eframe_addr = x86_next_eframe(last_ebp + sizeof(ulong) * 4,
                    bt);
		if ((sp = x86_jmp_error_code(last_eip))) 
			ep->jmp_error_code_eip = sp->value;
                break;

	default:
		error(FATAL, "unknown exception frame type?\n");

	}

        *ip = (db_addr_t) eip;
        *fp = (struct i386_frame *) ebp;
        last_ebp = ebp;
	last_eip = eip;

	return;

#ifndef MCLX
	db_print_stack_entry(name, 0, 0, 0, eip);

	/*
	 * Point to base of trapframe which is just above the
	 * current frame.
	 */
	tf = (struct trapframe *) ((int)*fp + 8);

	esp = (ISPL(tf->tf_cs) == SEL_UPL) ?  tf->tf_esp : (int)&tf->tf_esp;
	switch (frame_type) {
	case TRAP:
		if (INKERNEL((int) tf)) {
			eip = tf->tf_eip;
			ebp = tf->tf_ebp;
			db_printf(
		    "--- trap %#r, eip = %#r, esp = %#r, ebp = %#r ---\n",
			    tf->tf_trapno, eip, esp, ebp);
		}
		break;
	case SYSCALL:
		if (INKERNEL((int) tf)) {
			eip = tf->tf_eip;
			ebp = tf->tf_ebp;
			db_printf(
		    "--- syscall %#r, eip = %#r, esp = %#r, ebp = %#r ---\n",
			    tf->tf_eax, eip, esp, ebp);
		}
		break;
	case INTERRUPT:
		tf = (struct trapframe *)((int)*fp + 16);
		if (INKERNEL((int) tf)) {
			eip = tf->tf_eip;
			ebp = tf->tf_ebp;
			db_printf(
		    "--- interrupt, eip = %#r, esp = %#r, ebp = %#r ---\n",
			    eip, esp, ebp);
		}
		break;
	default:
		break;
	}

	*ip = (db_addr_t) eip;
	*fp = (struct i386_frame *) ebp;
#endif
}

#ifdef MCLX
void
x86_back_trace_cmd(struct bt_info *bt)
#else
ulong
db_stack_trace_cmd(addr, have_addr, count, modif, task, flags)
	db_expr_t addr;
	boolean_t have_addr;
	db_expr_t count;
	char *modif;
	ulong task;
	ulong flags;
#endif  /* MCLX */
{
	struct i386_frame *frame;
	int *argp;
	db_addr_t callpc;
	boolean_t first;
#ifdef MCLX
	db_expr_t addr;
        boolean_t have_addr;
        db_expr_t count;
        char *modif;
	db_addr_t last_callpc;
	ulong lastframe;
	physaddr_t phys;
	int frame_number;
	int forced;
	struct eframe eframe, *ep;
	char dbuf[BUFSIZE];

	if (!(bt->flags & BT_USER_SPACE) && 
	    (!bt->stkptr || !accessible(bt->stkptr))) {
		error(INFO, "cannot determine starting stack pointer\n");
		if (KVMDUMP_DUMPFILE())
			kvmdump_display_regs(bt->tc->processor, fp);
		else if (ELF_NOTES_VALID() && DISKDUMP_DUMPFILE())
			diskdump_display_regs(bt->tc->processor, fp);
		else if (SADUMP_DUMPFILE())
			sadump_display_regs(bt->tc->processor, fp);
		return;
	}

	if (bt->flags & BT_USER_SPACE) {
		if (KVMDUMP_DUMPFILE())
			kvmdump_display_regs(bt->tc->processor, fp);
		else if (ELF_NOTES_VALID() && DISKDUMP_DUMPFILE())
			diskdump_display_regs(bt->tc->processor, fp);
		else if (SADUMP_DUMPFILE())
			sadump_display_regs(bt->tc->processor, fp);
		fprintf(fp, " #0 [user space]\n");
		return;
	} else if ((bt->flags & BT_KERNEL_SPACE)) {
		if (KVMDUMP_DUMPFILE())
			kvmdump_display_regs(bt->tc->processor, fp);
		else if (ELF_NOTES_VALID() && DISKDUMP_DUMPFILE())
			diskdump_display_regs(bt->tc->processor, fp);
		else if (SADUMP_DUMPFILE())
			sadump_display_regs(bt->tc->processor, fp);
	}

	addr = bt->stkptr;
	have_addr = TRUE;
	count = 50;
	modif = (char *)bt->instptr;
        mach_debug = bt->debug;

        if ((machdep->flags & OMIT_FRAME_PTR) || 
	    bt->debug || 
	    (bt->flags & BT_FRAMESIZE_DEBUG) ||
	    !(bt->flags & BT_OLD_BACK_TRACE)) {
		bt->flags &= ~BT_OLD_BACK_TRACE;
                lkcd_x86_back_trace(bt, 0, fp);
                return;
        }

        if (mach_CRASHDEBUG(2)) {
        	fprintf(fp, "--> stkptr: %lx instptr: %lx (%s)\n",
			bt->stkptr, bt->instptr, closest_symbol(bt->instptr));
	}
#endif

	if (count == -1)
		count = 65535;

	if (!have_addr) {
#ifndef MCLX
		frame = (struct i386_frame *)ddb_regs.tf_ebp;
		if (frame == NULL)
			frame = (struct i386_frame *)(ddb_regs.tf_esp - 4);
		callpc = (db_addr_t)ddb_regs.tf_eip;
#endif
	} else {
		frame = (struct i386_frame *)addr;
		lastframe = (ulong)frame;
		ep = &eframe;
		BZERO(ep, sizeof(struct eframe));
		ep->eframe_found = FALSE;

		callpc = (db_addr_t)db_get_value((int)&frame->f_retaddr, 4, 
			FALSE, bt);
		if (modif) {
			frame_number = 0;
			forced = TRUE;
			callpc = (db_addr_t)modif;
		}
		else {
			frame_number = 1;
			forced = FALSE;
			if (!is_kernel_text(callpc))
				error(INFO, 
				   "callpc from stack is not a text address\n");
		}
	}

	first = TRUE;
	while (count--) {
		struct i386_frame *actframe;
		int		narg;
		char *	name;
		db_expr_t	offset;
		db_sym_t	sym;
#define MAXNARG	16
		char	*argnames[MAXNARG], **argnp = NULL;

		sym = db_search_symbol(callpc, DB_STGY_ANY, &offset);
		db_symbol_values(sym, &name, NULL);

		/*
		 * Attempt to determine a (possibly fake) frame that gives
		 * the caller's pc.  It may differ from `frame' if the
		 * current function never sets up a standard frame or hasn't
		 * set one up yet or has just discarded one.  The last two
		 * cases can be guessed fairly reliably for code generated
		 * by gcc.  The first case is too much trouble to handle in
		 * general because the amount of junk on the stack depends
		 * on the pc (the special handling of "calltrap", etc. in
		 * db_nextframe() works because the `next' pc is special).
		 */
		actframe = frame;
		if (first && !have_addr) {
#ifdef MCLX
			error(FATAL, "cannot handle \"!have_addr\" path #2\n");
#else
			int instr;

			instr = db_get_value(callpc, 4, FALSE);
			if ((instr & 0x00ffffff) == 0x00e58955) {
				/* pushl %ebp; movl %esp, %ebp */
				actframe = (struct i386_frame *)
					   (ddb_regs.tf_esp - 4);
			} else if ((instr & 0x0000ffff) == 0x0000e589) {
				/* movl %esp, %ebp */
				actframe = (struct i386_frame *)
					   ddb_regs.tf_esp;
				if (ddb_regs.tf_ebp == 0) {
					/* Fake the caller's frame better. */
					frame = actframe;
				}
			} else if ((instr & 0x000000ff) == 0x000000c3) {
				/* ret */
				actframe = (struct i386_frame *)
					   (ddb_regs.tf_esp - 4);
			} else if (offset == 0) {
				/* Probably a symbol in assembler code. */
				actframe = (struct i386_frame *)
					   (ddb_regs.tf_esp - 4);
			}
#endif
		}
		first = FALSE;

		argp = &actframe->f_arg0;
		narg = MAXNARG;
		if (sym != NULL && db_sym_numargs(sym, &narg, argnames)) {
			argnp = argnames;
		} else {
			narg = db_numargs(frame, bt);
		}

#ifdef MCLX
		if (is_kernel_text(callpc) || IS_MODULE_VADDR(callpc)) {
                        if (mach_CRASHDEBUG(2))
                                fprintf(fp, 
				    "--> (1) lastframe: %lx => frame: %lx\n",
                                        lastframe, (ulong)frame);

			db_print_stack_entry(name, narg, argnp, argp, callpc, 
				bt, ep, frame_number++, frame);

			if (STREQ(closest_symbol(callpc), "start_secondary"))
				break;

			if (BT_REFERENCE_FOUND(bt))
				return;

			if ((ulong)frame < lastframe) {
				break;
			}
			if (INSTACK(frame, bt) && 
			    ((ulong)frame > lastframe))
				lastframe = (ulong)frame;

		} else {
			if (!(forced && frame_number == 1)) {
				if (is_kernel_data(callpc)) {
                        		if (mach_CRASHDEBUG(2))
                                		fprintf(fp, 
					 "--> break(1): callpc %lx is data?\n",
                                        		callpc);
					if (!is_rodata_text(callpc))
						break;
				}

                                if (mach_CRASHDEBUG(2))
                                        fprintf(fp,
                                       "--> (2) lastframe: %lx => frame: %lx\n",
                                                lastframe, (ulong)frame);

				db_print_stack_entry(name, narg, argnp, 
					argp, callpc, bt, ep,
					frame_number++, frame); 

				if (BT_REFERENCE_FOUND(bt))
					return;

                        	if ((ulong)frame < lastframe) {
                                	break;
				}
                        	if (INSTACK(frame, bt) &&
				    ((ulong)frame > lastframe))
                                	lastframe = (ulong)frame;
			}
		}
		if (!INSTACK(frame, bt)) {
			if (mach_CRASHDEBUG(2))
				fprintf(fp, 
			    "--> break: !INSTACK(frame: %lx, task: %lx)\n",
					(ulong)frame, bt->task);
			break;
		}
#else
		db_print_stack_entry(name, narg, argnp, argp, callpc);
#endif

		if (actframe != frame) {
			/* `frame' belongs to caller. */
			callpc = (db_addr_t)
			    db_get_value((int)&actframe->f_retaddr, 4, 
				FALSE, bt);
			continue;
		}

                if (ep->eframe_found) 
			frame_number = dump_eframe(ep, frame_number, bt);

		last_callpc = callpc;

skip_frame:
		db_nextframe(&frame, &callpc, ep, bt);

		if (mach_CRASHDEBUG(2)) {
			fprintf(fp, 
			    "--> db_nextframe: frame: %lx  callpc: %lx [%s]\n", 
				(ulong)frame, callpc, 
				value_to_symstr(callpc, dbuf,0));
			if (callpc == last_callpc)
				fprintf(fp, "last callpc == callpc!\n");
		}

		if ((callpc == last_callpc) &&
		     STREQ(closest_symbol(callpc), "smp_stop_cpu_interrupt"))
			goto skip_frame;

		if (INSTACK(frame, bt) && 
		    ((ulong)frame < lastframe))
			if (mach_CRASHDEBUG(2))
				fprintf(fp, 
				     "--> frame pointer reversion?\n");

		if (INKERNEL((int) callpc) && !INKERNEL((int) frame)) {
			sym = db_search_symbol(callpc, DB_STGY_ANY, &offset);
			db_symbol_values(sym, &name, NULL);

                	if (is_kernel_data(callpc)) {
                        	if (mach_CRASHDEBUG(2))
                                	fprintf(fp,
				          "--> break(2): callpc %lx is data?\n",
                                        	callpc);
				if (!is_rodata_text(callpc))
					break;
                	}

                        if (mach_CRASHDEBUG(2))
                               fprintf(fp, 
				    "--> (3) lastframe: %lx => frame: %lx\n",
                                        lastframe, (ulong)frame);

			db_print_stack_entry(name, 0, 0, 0, callpc, bt, ep,
				frame_number++, frame);

			if (BT_REFERENCE_FOUND(bt))
				return;

			if ((ulong)frame < lastframe) {
				if (STREQ(closest_symbol(callpc), "reschedule"))
					x86_user_eframe(bt);
				break;
			}

                        if (INSTACK(frame, bt) &&
			    ((ulong)frame > lastframe))
                        	lastframe = (ulong)frame;
	
			if (mach_CRASHDEBUG(2)) 
				fprintf(fp, 
         "--> break: INKERNEL(callpc: %lx [%s]) && !INKERNEL(frame: %lx)\n",
				    callpc, value_to_symstr(callpc, dbuf, 0), 
				    (ulong)frame);
			break;
		}
		if (!INKERNEL((int) frame)) {
			if (mach_CRASHDEBUG(2))
				fprintf(fp, 
				    "--> break: !INKERNEL(frame: %lx)\n", 
					(ulong)frame);
			break;
		}
	}

	if (mach_CRASHDEBUG(2)) {
		fprintf(fp, "--> returning lastframe: %lx\n", lastframe);
	}

        if (ep->eframe_found) 
       		frame_number = dump_eframe(ep, frame_number, bt);

#ifndef MCLX
	return(lastframe);
#endif
}

/*
 *  The remainder of this file was generated at MCL to segregate 
 *  x86-specific needs.
 */
static int x86_uvtop(struct task_context *, ulong, physaddr_t *, int);
static int x86_kvtop(struct task_context *, ulong, physaddr_t *, int);
static int x86_uvtop_PAE(struct task_context *, ulong, physaddr_t *, int);
static int x86_kvtop_PAE(struct task_context *, ulong, physaddr_t *, int);
static int x86_uvtop_xen_wpt(struct task_context *, ulong, physaddr_t *, int);
static int x86_kvtop_xen_wpt(struct task_context *, ulong, physaddr_t *, int);
static int x86_uvtop_xen_wpt_PAE(struct task_context *, ulong, physaddr_t *, int);
static int x86_kvtop_xen_wpt_PAE(struct task_context *, ulong, physaddr_t *, int);
static int x86_kvtop_remap(ulong, physaddr_t *);
static ulong x86_get_task_pgd(ulong);
static ulong x86_processor_speed(void);
static ulong x86_get_pc(struct bt_info *);
static ulong x86_get_sp(struct bt_info *);
static void x86_get_stack_frame(struct bt_info *, ulong *, ulong *);
static int x86_translate_pte(ulong, void *, ulonglong);
static uint64_t x86_memory_size(void);
static ulong x86_vmalloc_start(void);
static ulong *read_idt_table(int);
static void eframe_init(void);
static int remap_init(void);
#define READ_IDT_INIT     1
#define READ_IDT_RUNTIME  2
static char *extract_idt_function(ulong *, char *, ulong *);
static int x86_is_task_addr(ulong);
static int x86_verify_symbol(const char *, ulong, char);
static int x86_eframe_search(struct bt_info *);
static ulong x86_in_irqstack(ulong);
static int x86_dis_filter(ulong, char *, unsigned int);
static struct line_number_hook x86_line_number_hooks[];
static int x86_is_uvaddr(ulong, struct task_context *);
static void x86_init_kernel_pgd(void);
static ulong xen_m2p_nonPAE(ulong);
static int x86_xendump_p2m_create(struct xendump_data *);
static int x86_pvops_xendump_p2m_create(struct xendump_data *);
static int x86_pvops_xendump_p2m_l2_create(struct xendump_data *);
static int x86_pvops_xendump_p2m_l3_create(struct xendump_data *);
static void x86_debug_dump_page(FILE *, char *, char *);
static int x86_xen_kdump_p2m_create(struct xen_kdump_data *);
static char *x86_xen_kdump_load_page(ulong, char *);
static char *x86_xen_kdump_load_page_PAE(ulong, char *);
static ulong x86_xen_kdump_page_mfn(ulong);
static ulong x86_xen_kdump_page_mfn_PAE(ulong);
static ulong x86_xendump_panic_task(struct xendump_data *);
static void x86_get_xendump_regs(struct xendump_data *, struct bt_info *, ulong *, ulong *);
static char *x86_xendump_load_page(ulong, char *);
static char *x86_xendump_load_page_PAE(ulong, char *);
static int x86_xendump_page_index(ulong);
static int x86_xendump_page_index_PAE(ulong);
static void x86_init_hyper(int);
static ulong x86_get_stackbase_hyper(ulong);
static ulong x86_get_stacktop_hyper(ulong);

int INT_EFRAME_SS = 14;
int INT_EFRAME_ESP = 13;
int INT_EFRAME_EFLAGS = 12;   /* CS lcall7 */
int INT_EFRAME_CS = 11;       /* EIP lcall7 */
int INT_EFRAME_EIP = 10;      /* EFLAGS lcall7 */
int INT_EFRAME_ERR = 9;
int INT_EFRAME_ES = 8;
int INT_EFRAME_DS = 7;
int INT_EFRAME_EAX = 6;
int INT_EFRAME_EBP = 5;
int INT_EFRAME_EDI = 4;
int INT_EFRAME_ESI = 3;
int INT_EFRAME_EDX = 2;
int INT_EFRAME_ECX = 1;
int INT_EFRAME_EBX = 0;
int INT_EFRAME_GS = -1;

#define MAX_USER_EFRAME_SIZE   (17)
#define KERNEL_EFRAME_SIZE (INT_EFRAME_EFLAGS+1)

#define EFRAME_USER   (1)
#define EFRAME_KERNEL (2)

#define DPL_BITS   (0x3)

static int
dump_eframe(struct eframe *ep, int frame_number, struct bt_info *bt)
{
	int i;
	char buf[BUFSIZE], *sp;
	ulong int_eframe[MAX_USER_EFRAME_SIZE];
	int eframe_type, args;
	ulong value, *argp;

	eframe_type = 0;

	if (STACK_OFFSET_TYPE(ep->eframe_addr) > STACKSIZE()) 
		return(frame_number);

	GET_STACK_DATA(ep->eframe_addr, (char *)int_eframe,
		SIZE(pt_regs));	

	if (int_eframe[INT_EFRAME_CS] & DPL_BITS) {
		if (!INSTACK(ep->eframe_addr + 
		    SIZE(pt_regs) - 1, bt))
			return(frame_number);
	/* error(FATAL, "read of exception frame would go beyond stack\n"); */
		eframe_type = EFRAME_USER;
	} else {
                if (!INSTACK(ep->eframe_addr + 
		    (KERNEL_EFRAME_SIZE*sizeof(ulong)) - 1, bt))
			return(frame_number);
        /* error(FATAL, "read of exception frame would go beyond stack\n"); */
                eframe_type = EFRAME_KERNEL;
	}

	x86_dump_eframe_common(bt, int_eframe, (eframe_type == EFRAME_KERNEL));

	if (bt->flags & BT_EFRAME_SEARCH)
		return 0;

	if (eframe_type == EFRAME_USER)
		return(frame_number);

	if (BT_REFERENCE_CHECK(bt)) 
		return(++frame_number);

	/*
	 *  The exception occurred while executing in kernel mode.
	 *  Pull out the EIP from the exception frame and display 
         *  the frame line.  Then figure out whether it's possible to 
	 *  show any arguments.
	 */
	fprintf(fp, "%s#%d [%08lx] %s at %08lx\n",
		frame_number < 10 ?  " " : "",
		frame_number,
		int_eframe[INT_EFRAME_EBP],
		value_to_symstr(int_eframe[INT_EFRAME_EIP], buf, 0),
		int_eframe[INT_EFRAME_EIP]);

	frame_number++;

	if ((sp = closest_symbol(int_eframe[INT_EFRAME_EIP])) == NULL)
		return(frame_number);

	value = symbol_value(sp);
        argp = (ulong *)(int_eframe[INT_EFRAME_EBP] + (sizeof(long)*2));
	args = is_system_call(NULL, value) ? 
		4 : eframe_numargs(int_eframe[INT_EFRAME_EIP], bt);
	
	fprintf(fp, "    (");
	for (i = 0; i < args; i++, argp++) {
		if (INSTACK(argp, bt)) 
			value = GET_STACK_ULONG((ulong)argp);
	        else /* impossible! */ 
        		readmem((ulong)argp, KVADDR, &value,
                		sizeof(ulong), "syscall arg", FAULT_ON_ERROR);
					
		if (i)
			fprintf(fp, ", ");

		if ((sp = value_symbol(value)))
		        fprintf(fp, "%s", sp);
		else if ((bt->flags & BT_SYMBOLIC_ARGS) &&
		        strlen(value_to_symstr(value, buf, 0)))
		       	fprintf(fp, "%s", buf);
		else
		        fprintf(fp, "%lx", value);
	}
	fprintf(fp, ")\n");

	if (bt->flags & BT_LINE_NUMBERS) 
		x86_dump_line_number(int_eframe[INT_EFRAME_EIP]);

	return(frame_number);
}

/*
 *  Dump an exception frame, coming from either source of stack trace code.
 *  (i.e., -fomit-frame-pointer or not)
 */
void
x86_dump_eframe_common(struct bt_info *bt, ulong *int_eframe, int kernel)
{
	struct syment *sp;
	ulong offset;

	if (bt && BT_REFERENCE_CHECK(bt)) {  
		if (!(bt->ref->cmdflags & BT_REF_HEXVAL)) 
			return;

		if ((int_eframe[INT_EFRAME_EAX] == bt->ref->hexval) ||
		    (int_eframe[INT_EFRAME_EBX] == bt->ref->hexval) || 
		    (int_eframe[INT_EFRAME_ECX] == bt->ref->hexval) || 
		    (int_eframe[INT_EFRAME_EDX] == bt->ref->hexval) || 
		    (int_eframe[INT_EFRAME_EBP] == bt->ref->hexval) || 
		    (int_eframe[INT_EFRAME_ESI] == bt->ref->hexval) || 
		    (int_eframe[INT_EFRAME_EDI] == bt->ref->hexval) || 
		    ((short)int_eframe[INT_EFRAME_ES] == 
				(short)bt->ref->hexval) || 
		    ((short)int_eframe[INT_EFRAME_DS] == 
				(short)bt->ref->hexval) || 
		    ((short)int_eframe[INT_EFRAME_CS] ==
                                (short)bt->ref->hexval) ||
		    (int_eframe[INT_EFRAME_EIP] == bt->ref->hexval) || 
		    (int_eframe[INT_EFRAME_ERR] == bt->ref->hexval) || 
		    (int_eframe[INT_EFRAME_EFLAGS] == bt->ref->hexval))
			bt->ref->cmdflags |= BT_REF_FOUND;

		if (!kernel) {
			if ((int_eframe[INT_EFRAME_ESP] == bt->ref->hexval) ||
		            ((short)int_eframe[INT_EFRAME_SS] == 
			    (short)bt->ref->hexval))
				bt->ref->cmdflags |= BT_REF_FOUND;
		}

		return;
	}

	if (kernel) {
		if (bt && (bt->flags & BT_EFRAME_SEARCH)) {
			fprintf(fp, "    [exception EIP: ");
			if ((sp = value_search(int_eframe[INT_EFRAME_EIP], 
			    &offset))) {
				fprintf(fp, "%s", sp->name);
				if (offset)
					fprintf(fp, 
					    (*gdb_output_radix == 16) ? 
					    "+0x%lx" : "+%ld", 
					    offset);
			} else 
				fprintf(fp, 
					"unknown or invalid address");
			fprintf(fp, "]\n");
		}
	    	fprintf(fp, 
  	    "    EAX: %08lx  EBX: %08lx  ECX: %08lx  EDX: %08lx  EBP: %08lx \n",
			int_eframe[INT_EFRAME_EAX],
			int_eframe[INT_EFRAME_EBX],
			int_eframe[INT_EFRAME_ECX],
			int_eframe[INT_EFRAME_EDX],
			int_eframe[INT_EFRAME_EBP]);
	} else
                fprintf(fp, 
		    "    EAX: %08lx  EBX: %08lx  ECX: %08lx  EDX: %08lx \n",
                        int_eframe[INT_EFRAME_EAX],
                        int_eframe[INT_EFRAME_EBX],
                        int_eframe[INT_EFRAME_ECX],
                        int_eframe[INT_EFRAME_EDX]);

        fprintf(fp, 
		"    DS:  %04x      ESI: %08lx  ES:  %04x      EDI: %08lx",
                (short)int_eframe[INT_EFRAME_DS],
                int_eframe[INT_EFRAME_ESI],
                (short)int_eframe[INT_EFRAME_ES],
                int_eframe[INT_EFRAME_EDI]);
	if (kernel && (INT_EFRAME_GS != -1))
		fprintf(fp, "  GS:  %04x", (short)int_eframe[INT_EFRAME_GS]);
	fprintf(fp, "\n");

	if (!kernel) {
		fprintf(fp, "    SS:  %04x      ESP: %08lx  EBP: %08lx",
			(short)int_eframe[INT_EFRAME_SS],
			int_eframe[INT_EFRAME_ESP],
                        int_eframe[INT_EFRAME_EBP]);
		if (INT_EFRAME_GS != -1)
			fprintf(fp, "  GS:  %04x", (short)int_eframe[INT_EFRAME_GS]);
		fprintf(fp, "\n");
	}

	fprintf(fp, 
	    "    CS:  %04x      EIP: %08lx  ERR: %08lx  EFLAGS: %08lx \n",
                (short)int_eframe[INT_EFRAME_CS],
                int_eframe[INT_EFRAME_EIP],
                int_eframe[INT_EFRAME_ERR],
                int_eframe[INT_EFRAME_EFLAGS]);
}

/*
 *  Catch a few functions that show up as rodata but really are
 *  functions.
 */
int
is_rodata_text(ulong callpc)
{
	struct syment *sp;

	if (!is_rodata(callpc, &sp))
		return FALSE;

	if (strstr(sp->name, "interrupt") || strstr(sp->name, "call_"))
		return TRUE;

	return FALSE;
}


static int 
check_for_eframe(char *name, struct bt_info *bt)
{
        int i;
        ulong *ip;
        char buf[BUFSIZE];

        ip = read_idt_table(READ_IDT_RUNTIME);

        for (i = 0; i < 256; i++, ip += 2) {
		if (STREQ(name, extract_idt_function(ip, buf, NULL))) 
			return IDT_DIRECT_ENTRY;
	}

	if (STREQ(name, "ret_from_intr") || 
	    STREQ(name, "call_call_function_interrupt") ||
	    STREQ(name, "call_reschedule_interrupt") ||
	    STREQ(name, "call_invalidate_interrupt"))
		return RET_FROM_INTR;

        if (STREQ(name, "error_code"))
        	return IDT_JMP_ERROR_CODE;

	if (STREQ(name, "signal_return"))
		return SIGNAL_RETURN;

	return FALSE;
}

/*
 *  Return the syment of the function that did the "jmp error_code".
 */
struct syment * 
x86_jmp_error_code(ulong callpc)
{
	struct syment *sp;

	if (!(sp = value_search(callpc, NULL)) || !STRNEQ(sp->name, "do_"))
		return NULL;

	return (symbol_search(sp->name + strlen("do_")));
}

static const char *hook_files[] = {
	"arch/i386/kernel/entry.S",
	"arch/i386/kernel/head.S",
	"arch/i386/kernel/semaphore.c"
};

#define ENTRY_S      ((char **)&hook_files[0])
#define HEAD_S       ((char **)&hook_files[1])
#define SEMAPHORE_C  ((char **)&hook_files[2])

static struct line_number_hook x86_line_number_hooks[] = {
	{"lcall7", ENTRY_S},                   
	{"lcall27", ENTRY_S},                       
	{"ret_from_fork", ENTRY_S},                       
	{"system_call", ENTRY_S},                       
	{"ret_from_sys_call", ENTRY_S},                       
	{"ret_from_intr", ENTRY_S},                       
	{"divide_error", ENTRY_S},                       
	{"coprocessor_error", ENTRY_S},                       
	{"simd_coprocessor_error", ENTRY_S},                       
	{"device_not_available", ENTRY_S},                       
	{"debug", ENTRY_S},                       
	{"nmi", ENTRY_S},                       
	{"int3", ENTRY_S},                       
	{"overflow", ENTRY_S},                       
	{"bounds", ENTRY_S},                       
	{"invalid_op", ENTRY_S},                       
	{"coprocessor_segment_overrun", ENTRY_S},                       
	{"double_fault", ENTRY_S},                       
	{"invalid_TSS", ENTRY_S},                       
	{"segment_not_present", ENTRY_S},                       
	{"stack_segment", ENTRY_S},                       
	{"general_protection", ENTRY_S},                       
	{"alignment_check", ENTRY_S},                       
	{"page_fault", ENTRY_S},                       
	{"machine_check", ENTRY_S},                       
	{"spurious_interrupt_bug", ENTRY_S},                       
	{"v86_signal_return", ENTRY_S},                       
	{"tracesys", ENTRY_S},                       
	{"tracesys_exit", ENTRY_S},                       
	{"badsys", ENTRY_S},                       
	{"ret_from_exception", ENTRY_S},                       
	{"reschedule", ENTRY_S},                       
	{"error_code", ENTRY_S},                       
	{"device_not_available_emulate", ENTRY_S},                       
	{"restore_all", ENTRY_S},                       
	{"signal_return", ENTRY_S},                       

        {"L6", HEAD_S},                       
	{"_text", HEAD_S},                       
        {"startup_32", HEAD_S},                       
        {"checkCPUtype", HEAD_S},                       
        {"is486", HEAD_S},                       
        {"is386", HEAD_S},                       
        {"ready", HEAD_S},                       
        {"check_x87", HEAD_S},                       
        {"setup_idt", HEAD_S},                       
        {"rp_sidt", HEAD_S},                       
        {"stack_start", HEAD_S},                       
        {"int_msg", HEAD_S},                       
        {"ignore_int", HEAD_S},                       
        {"idt_descr", HEAD_S},                       
        {"idt", HEAD_S},                       
        {"gdt_descr", HEAD_S},                       
        {"gdt", HEAD_S},                       
        {"swapper_pg_dir", HEAD_S},                       
        {"pg0", HEAD_S},                       
        {"pg1", HEAD_S},                       
        {"empty_zero_page", HEAD_S},                       

	{"__down_failed", SEMAPHORE_C},                 
	{"__down_failed_interruptible", SEMAPHORE_C},                 
	{"__down_failed_trylock", SEMAPHORE_C},                 
	{"__up_wakeup", SEMAPHORE_C},                 
	{"__write_lock_failed", SEMAPHORE_C},                 
	{"__read_lock_failed", SEMAPHORE_C},                 

	{NULL, NULL}    /* list must be NULL-terminated */
};


static void
x86_dump_line_number(ulong callpc)
{
	int retries;
	char buf[BUFSIZE], *p;

        retries = 0;
try_closest:
	get_line_number(callpc, buf, FALSE);

        if (strlen(buf)) {
                if (retries) {
                        p = strstr(buf, ": ");
			if (p)
				*p = NULLCHAR;
                }
                fprintf(fp, "    %s\n", buf);
        } else {
                if (retries) {
                        fprintf(fp, GDB_PATCHED() ? 
			  "" : "    (cannot determine file and line number)\n");
                } else {
                        retries++;
                        callpc = closest_symbol_value(callpc);
                        goto try_closest;
                }
        }
}

/*
 *   Look for likely exception frames in a stack.
 */

struct x86_pt_regs {
	ulong reg_value[MAX_USER_EFRAME_SIZE];
};

/*
 * Searches from addr within the stackframe defined by bt
 * for the next set of bytes that matches an exception frame pattern.
 * Returns either the address of the frame or 0.
 */
static ulong
x86_next_eframe(ulong addr, struct bt_info *bt)
{
	ulong *first, *last;
	struct x86_pt_regs *pt;
	ulong *stack;
        ulong rv;

	stack = (ulong *)bt->stackbuf;

        if (!INSTACK(addr, bt)) {
                return(0);
        }

        rv = 0;
	first = stack + ((addr - bt->stackbase) / sizeof(ulong));
	last = stack +
	   (((bt->stacktop - bt->stackbase) - SIZE(pt_regs)) / sizeof(ulong));

        for ( ; first <= last; first++) {
                pt = (struct x86_pt_regs *)first;

		/* check for kernel exception frame */

		if (((short)pt->reg_value[INT_EFRAME_CS] == 0x10) &&
		    ((short)pt->reg_value[INT_EFRAME_DS] == 0x18) &&
                    ((short)pt->reg_value[INT_EFRAME_ES] == 0x18) &&
		    IS_KVADDR(pt->reg_value[INT_EFRAME_EIP])) {
			if (!(machdep->flags & OMIT_FRAME_PTR) && 
			    !INSTACK(pt->reg_value[INT_EFRAME_EBP], bt)) 
				continue;
                        rv = bt->stackbase + sizeof(ulong) * (first - stack);
                        break;
		}

                if (((short)pt->reg_value[INT_EFRAME_CS] == 0x60) &&
                    ((short)pt->reg_value[INT_EFRAME_DS] == 0x68) &&
                    ((short)pt->reg_value[INT_EFRAME_ES] == 0x68) &&
                    IS_KVADDR(pt->reg_value[INT_EFRAME_EIP])) {
			if (!(machdep->flags & OMIT_FRAME_PTR) && 
			    !INSTACK(pt->reg_value[INT_EFRAME_EBP], bt)) 
				continue;
                        rv = bt->stackbase + sizeof(ulong) * (first - stack);
                        break;
                }

                if (((short)pt->reg_value[INT_EFRAME_CS] == 0x60) &&
                    ((short)pt->reg_value[INT_EFRAME_DS] == 0x7b) &&
                    ((short)pt->reg_value[INT_EFRAME_ES] == 0x7b) &&
                    IS_KVADDR(pt->reg_value[INT_EFRAME_EIP])) {
                        if (!(machdep->flags & OMIT_FRAME_PTR) &&
                            !INSTACK(pt->reg_value[INT_EFRAME_EBP], bt))
                                continue;
                        rv = bt->stackbase + sizeof(ulong) * (first - stack);
                        break;
                }

                if (XEN() && ((short)pt->reg_value[INT_EFRAME_CS] == 0x61) &&
                    ((short)pt->reg_value[INT_EFRAME_DS] == 0x7b) &&
                    ((short)pt->reg_value[INT_EFRAME_ES] == 0x7b) &&
                    IS_KVADDR(pt->reg_value[INT_EFRAME_EIP])) {
                        if (!(machdep->flags & OMIT_FRAME_PTR) &&
                            !INSTACK(pt->reg_value[INT_EFRAME_EBP], bt))
                                continue;
                        rv = bt->stackbase + sizeof(ulong) * (first - stack);
                        break;
                }

		/* check for user exception frame */

		if (((short)pt->reg_value[INT_EFRAME_CS] == 0x23) &&
		    ((short)pt->reg_value[INT_EFRAME_DS] == 0x2b) &&
		    ((short)pt->reg_value[INT_EFRAME_ES] == 0x2b) &&
		    ((short)pt->reg_value[INT_EFRAME_SS] == 0x2b) &&
		    IS_UVADDR(pt->reg_value[INT_EFRAME_EIP], bt->tc) &&
		    IS_UVADDR(pt->reg_value[INT_EFRAME_ESP], bt->tc)) {
                        rv = bt->stackbase + sizeof(ulong) * (first - stack);
                        break;
		}

                if (((short)pt->reg_value[INT_EFRAME_CS] == 0x73) &&
                    ((short)pt->reg_value[INT_EFRAME_DS] == 0x7b) &&
                    ((short)pt->reg_value[INT_EFRAME_ES] == 0x7b) &&
                    ((short)pt->reg_value[INT_EFRAME_SS] == 0x7b) &&
                    IS_UVADDR(pt->reg_value[INT_EFRAME_EIP], bt->tc) &&
                    IS_UVADDR(pt->reg_value[INT_EFRAME_ESP], bt->tc)) {
                        rv = bt->stackbase + sizeof(ulong) * (first - stack);
                        break;
                }

		/*
		 *  2.6 kernels using sysenter_entry instead of system_call
		 *  have a funky trampoline EIP address.
		 */
                if (((short)pt->reg_value[INT_EFRAME_CS] == 0x73) &&
                    ((short)pt->reg_value[INT_EFRAME_DS] == 0x7b) &&
                    ((short)pt->reg_value[INT_EFRAME_ES] == 0x7b) &&
                    ((short)pt->reg_value[INT_EFRAME_SS] == 0x7b) &&
                    (pt->reg_value[INT_EFRAME_EFLAGS] == 0x246) &&
                    IS_UVADDR(pt->reg_value[INT_EFRAME_ESP], bt->tc)) {
                        rv = bt->stackbase + sizeof(ulong) * (first - stack);
                        break;
                }
        }
        return(rv);
}

static int 
x86_eframe_search(struct bt_info *bt_in)
{
	ulong addr;
	struct x86_pt_regs *pt;
	struct eframe eframe, *ep;
	struct bt_info bt_local, *bt;
	ulong flagsave;
	ulong irqstack;
        short cs;
        char *mode, *ibuf;
	int c, cnt;

	bt = bt_in;
	ibuf = NULL;
	cnt = 0;

	if (bt->flags & BT_EFRAME_SEARCH2) {
		if (!(tt->flags & IRQSTACKS)) {
			error(FATAL, "this kernel does not have IRQ stacks\n");
			return 0;
		}

		BCOPY(bt_in, &bt_local, sizeof(struct bt_info));
		bt = &bt_local;
		bt->flags &= ~(ulonglong)BT_EFRAME_SEARCH2;

        	for (c = 0; c < NR_CPUS; c++) {
                	if (tt->hardirq_ctx[c]) {
				if ((bt->flags & BT_CPUMASK) && 
				    !(NUM_IN_BITMAP(bt->cpumask, c)))
					continue;
				bt->hp->esp = tt->hardirq_ctx[c];
				fprintf(fp, "CPU %d HARD IRQ STACK:\n", c);
				if ((cnt = x86_eframe_search(bt)))
					fprintf(fp, "\n");
				else
					fprintf(fp, "(none found)\n\n");
			}
		}
        	for (c = 0; c < NR_CPUS; c++) {
			if (tt->softirq_ctx[c]) {
				if ((bt->flags & BT_CPUMASK) && 
				    !(NUM_IN_BITMAP(bt->cpumask, c)))
					continue;
				bt->hp->esp = tt->softirq_ctx[c];
				fprintf(fp, "CPU %d SOFT IRQ STACK:\n", c);
				if ((cnt = x86_eframe_search(bt)))
					fprintf(fp, "\n");
				else
					fprintf(fp, "(none found)\n\n");
			}
		}

		return 0;
	}

	if (bt->hp && bt->hp->esp) {
		BCOPY(bt_in, &bt_local, sizeof(struct bt_info));
		bt = &bt_local;
		addr = bt->hp->esp;
		if ((irqstack = x86_in_irqstack(addr))) {
                	bt->stackbase = irqstack;
                	bt->stacktop = irqstack + SIZE(irq_ctx);
			if (SIZE(irq_ctx) > STACKSIZE()) {
				ibuf = (char *)GETBUF(SIZE(irq_ctx));
				bt->stackbuf = ibuf;
			}
			alter_stackbuf(bt);
		} else if (!INSTACK(addr, bt))
                        error(FATAL,
                            "unrecognized stack address for this task: %lx\n",
                                bt->hp->esp);
	} else if (tt->flags & THREAD_INFO)
        	addr = bt->stackbase + 
			roundup(SIZE(thread_info), sizeof(ulong));
	else
        	addr = bt->stackbase + 
			roundup(SIZE(task_struct), sizeof(ulong));

	ep = &eframe;
	BZERO(ep, sizeof(struct eframe));

        while ((addr = x86_next_eframe(addr, bt)) != 0) {
		cnt++;
		if (bt->flags & BT_EFRAME_COUNT) {
			addr += 4;
			continue;
		}
                pt = (struct x86_pt_regs *) (bt->stackbuf
                    + (addr - bt->stackbase));
                ep->eframe_addr = addr;
                cs = pt->reg_value[INT_EFRAME_CS];
                if ((cs == 0x23) || (cs == 0x73)) {
                        mode = "USER-MODE";
                } else if ((cs == 0x10) || (cs == 0x60)) {
                        mode = "KERNEL-MODE";
		} else if (XEN() && (cs == 0x61)) {
                        mode = "KERNEL-MODE";
                } else {
                        mode = "UNKNOWN-MODE";
                }
                fprintf(fp, "%s  %s EXCEPTION FRAME AT %lx:\n",
	            bt->flags & BT_EFRAME_SEARCH ? "\n" : "",
		    mode, ep->eframe_addr);
		flagsave = bt->flags;
		bt->flags |= BT_EFRAME_SEARCH;
                dump_eframe(ep, 0, bt);
		bt->flags = flagsave;
                addr += 4;
        }

	if (ibuf)
		FREEBUF(ibuf);

	return cnt;
}

static ulong 
x86_in_irqstack(ulong addr)
{
	int c;

	if (!(tt->flags & IRQSTACKS))
		return 0;
	
	for (c = 0; c < NR_CPUS; c++) {
                if (tt->hardirq_ctx[c]) {
			if ((addr >= tt->hardirq_ctx[c]) &&
			    (addr < (tt->hardirq_ctx[c] + SIZE(irq_ctx))))
				return(tt->hardirq_ctx[c]);
	
                }
                if (tt->softirq_ctx[c]) {
                       if ((addr >= tt->softirq_ctx[c]) &&
                           (addr < (tt->softirq_ctx[c] + SIZE(irq_ctx))))
                                return(tt->softirq_ctx[c]);
		}
	}

	return 0;
}

/*
 *  Dump the kernel-entry user-mode exception frame.
 */
static void
x86_user_eframe(struct bt_info *bt)
{
        struct eframe eframe, *ep;
	struct x86_pt_regs x86_pt_regs, *pt;
	ulong pt_regs_addr;

	pt_regs_addr = USER_EFRAME_ADDR(bt->task);
	readmem(pt_regs_addr, KVADDR, &x86_pt_regs, sizeof(struct x86_pt_regs),
		"x86 pt_regs", FAULT_ON_ERROR);

        pt = &x86_pt_regs;
        if (((short)pt->reg_value[INT_EFRAME_CS] == 0x23) &&
            ((short)pt->reg_value[INT_EFRAME_DS] == 0x2b) &&
            ((short)pt->reg_value[INT_EFRAME_ES] == 0x2b) &&
            ((short)pt->reg_value[INT_EFRAME_SS] == 0x2b) &&
            IS_UVADDR(pt->reg_value[INT_EFRAME_EIP], bt->tc) &&
            IS_UVADDR(pt->reg_value[INT_EFRAME_ESP], bt->tc) &&
            IS_UVADDR(pt->reg_value[INT_EFRAME_EBP], bt->tc)) {
                ep = &eframe;
                BZERO(ep, sizeof(struct eframe));
                ep->eframe_addr = pt_regs_addr;
		bt->flags |= BT_EFRAME_SEARCH;
                dump_eframe(ep, 0, bt);
		bt->flags &= ~(ulonglong)BT_EFRAME_SEARCH;
	}

}

/*
 *  Do all necessary machine-specific setup here.  This is called three times,
 *  during symbol table initialization, and before and after GDB has been 
 *  initialized.
 */

struct machine_specific x86_machine_specific = { 0 };

static int PGDIR_SHIFT;
static int PTRS_PER_PTE;
static int PTRS_PER_PGD;

void
x86_init(int when)
{
	struct syment *sp, *spn;

	if (XEN_HYPER_MODE()) {
		x86_init_hyper(when);
		return;
	}

	switch (when)
	{
	case SETUP_ENV:
		machdep->process_elf_notes = x86_process_elf_notes;
		break;
	case PRE_SYMTAB:
		machdep->verify_symbol = x86_verify_symbol;
                if (pc->flags & KERNEL_DEBUG_QUERY)
                        return;
                machdep->pagesize = memory_page_size();
                machdep->pageshift = ffs(machdep->pagesize) - 1;
                machdep->pageoffset = machdep->pagesize - 1;
                machdep->pagemask = ~((ulonglong)machdep->pageoffset);
		machdep->stacksize = machdep->pagesize * 2;
        	if ((machdep->pgd = (char *)malloc(PAGESIZE())) == NULL)
                	error(FATAL, "cannot malloc pgd space.");
                if ((machdep->pmd = (char *)malloc(PAGESIZE())) == NULL)
                        error(FATAL, "cannot malloc pmd space.");
        	if ((machdep->ptbl = (char *)malloc(PAGESIZE())) == NULL)
                	error(FATAL, "cannot malloc ptbl space.");
		machdep->last_pgd_read = 0;
		machdep->last_pmd_read = 0;
		machdep->last_ptbl_read = 0;
		machdep->machspec = &x86_machine_specific;
		machdep->verify_paddr = generic_verify_paddr;
		x86_parse_cmdline_args();
		break;

	case PRE_GDB:
		if (symbol_exists("pae_pgd_cachep") ||
		    ((sp = symbol_search("pkmap_count")) && 
		    (spn = next_symbol(NULL, sp)) &&
		    (((spn->value - sp->value)/sizeof(int)) == 512))) {
                	machdep->flags |= PAE;
			PGDIR_SHIFT = PGDIR_SHIFT_3LEVEL;
			PTRS_PER_PTE = PTRS_PER_PTE_3LEVEL;
			PTRS_PER_PGD = PTRS_PER_PGD_3LEVEL;
                        machdep->uvtop = x86_uvtop_PAE;
                        machdep->kvtop = x86_kvtop_PAE;
		} else {
			PGDIR_SHIFT = PGDIR_SHIFT_2LEVEL;
                        PTRS_PER_PTE = PTRS_PER_PTE_2LEVEL;
                        PTRS_PER_PGD = PTRS_PER_PGD_2LEVEL;
                	machdep->uvtop = x86_uvtop;
                	machdep->kvtop = x86_kvtop;
			free(machdep->pmd);
			machdep->pmd = machdep->pgd;   
		}
		machdep->ptrs_per_pgd = PTRS_PER_PGD;
		if (!machdep->kvbase) {
			if (kernel_symbol_exists("module_kaslr_mutex"))
				machdep->kvbase = 0xc0000000;
			else
				machdep->kvbase = symbol_value("_stext") & ~KVBASE_MASK;  
		}
		if (machdep->kvbase & 0x80000000) 
                	machdep->is_uvaddr = generic_is_uvaddr;
		else {
			vt->flags |= COMMON_VADDR;
                	machdep->is_uvaddr = x86_is_uvaddr;
		}
		machdep->identity_map_base = machdep->kvbase;
                machdep->is_kvaddr = generic_is_kvaddr;
	        machdep->eframe_search = x86_eframe_search;
	        machdep->back_trace = x86_back_trace_cmd;
	        machdep->processor_speed = x86_processor_speed;
	        machdep->get_task_pgd = x86_get_task_pgd;
		machdep->dump_irq = generic_dump_irq;
		machdep->get_irq_affinity = generic_get_irq_affinity;
		machdep->show_interrupts = generic_show_interrupts;
		machdep->get_stack_frame = x86_get_stack_frame;
		machdep->get_stackbase = generic_get_stackbase;
		machdep->get_stacktop = generic_get_stacktop;
		machdep->translate_pte = x86_translate_pte;
		machdep->memory_size = x86_memory_size;
		machdep->vmalloc_start = x86_vmalloc_start;
		machdep->is_task_addr = x86_is_task_addr;
		machdep->dis_filter = x86_dis_filter;
		machdep->cmd_mach = x86_cmd_mach;
		machdep->get_smp_cpus = x86_get_smp_cpus;
		machdep->flags |= FRAMESIZE_DEBUG;
		machdep->value_to_symbol = generic_machdep_value_to_symbol;
		machdep->init_kernel_pgd = x86_init_kernel_pgd;
		machdep->xendump_p2m_create = x86_xendump_p2m_create;
		machdep->xen_kdump_p2m_create = x86_xen_kdump_p2m_create;
		machdep->xendump_panic_task = x86_xendump_panic_task;
		machdep->get_xendump_regs = x86_get_xendump_regs;
		machdep->clear_machdep_cache = x86_clear_machdep_cache;
		break;

	case POST_GDB:
		if (x86_omit_frame_pointer())
			machdep->flags |= OMIT_FRAME_PTR;
		STRUCT_SIZE_INIT(user_regs_struct, "user_regs_struct");
		if (MEMBER_EXISTS("user_regs_struct", "ebp"))
			MEMBER_OFFSET_INIT(user_regs_struct_ebp,
				"user_regs_struct", "ebp");
		else
			MEMBER_OFFSET_INIT(user_regs_struct_ebp,
				"user_regs_struct", "bp");
		if (MEMBER_EXISTS("user_regs_struct", "esp"))
			MEMBER_OFFSET_INIT(user_regs_struct_esp,
				"user_regs_struct", "esp");
		else
			MEMBER_OFFSET_INIT(user_regs_struct_esp,
				"user_regs_struct", "sp");
		if (MEMBER_EXISTS("user_regs_struct", "eip"))
			MEMBER_OFFSET_INIT(user_regs_struct_eip,
				"user_regs_struct", "eip");
		else
			MEMBER_OFFSET_INIT(user_regs_struct_eip,
				"user_regs_struct", "ip");
		if (MEMBER_EXISTS("user_regs_struct", "eax"))
			MEMBER_OFFSET_INIT(user_regs_struct_eax,
				"user_regs_struct", "eax");
		else
			MEMBER_OFFSET_INIT(user_regs_struct_eax,
				"user_regs_struct", "ax");
		if (MEMBER_EXISTS("user_regs_struct", "ebx"))
			MEMBER_OFFSET_INIT(user_regs_struct_ebx,
				"user_regs_struct", "ebx");
		else
			MEMBER_OFFSET_INIT(user_regs_struct_ebx,
				"user_regs_struct", "bx");
		if (MEMBER_EXISTS("user_regs_struct", "ecx"))
			MEMBER_OFFSET_INIT(user_regs_struct_ecx,
				"user_regs_struct", "ecx");
		else
			MEMBER_OFFSET_INIT(user_regs_struct_ecx,
				"user_regs_struct", "cx");
		if (MEMBER_EXISTS("user_regs_struct", "edx"))
			MEMBER_OFFSET_INIT(user_regs_struct_edx,
				"user_regs_struct", "edx");
		else
			MEMBER_OFFSET_INIT(user_regs_struct_edx,
				"user_regs_struct", "dx");
		if (MEMBER_EXISTS("user_regs_struct", "esi"))
			MEMBER_OFFSET_INIT(user_regs_struct_esi,
				"user_regs_struct", "esi");
		else
			MEMBER_OFFSET_INIT(user_regs_struct_esi,
				"user_regs_struct", "si");
		if (MEMBER_EXISTS("user_regs_struct", "edi"))
			MEMBER_OFFSET_INIT(user_regs_struct_edi,
				"user_regs_struct", "edi");
		else
			MEMBER_OFFSET_INIT(user_regs_struct_edi,
				"user_regs_struct", "di");
		if (MEMBER_EXISTS("user_regs_struct", "eflags"))
			MEMBER_OFFSET_INIT(user_regs_struct_eflags,
				"user_regs_struct", "eflags");
		else
			MEMBER_OFFSET_INIT(user_regs_struct_eflags,
				"user_regs_struct", "flags");
		MEMBER_OFFSET_INIT(user_regs_struct_cs,
			"user_regs_struct", "cs");
		MEMBER_OFFSET_INIT(user_regs_struct_ds,
			"user_regs_struct", "ds");
		MEMBER_OFFSET_INIT(user_regs_struct_es,
			"user_regs_struct", "es");
		MEMBER_OFFSET_INIT(user_regs_struct_fs,
			"user_regs_struct", "fs");
		MEMBER_OFFSET_INIT(user_regs_struct_gs,
			"user_regs_struct", "gs");
		MEMBER_OFFSET_INIT(user_regs_struct_ss,
			"user_regs_struct", "ss");
		if (!VALID_STRUCT(user_regs_struct)) {
			/*  Use this hardwired version -- sometimes the 
			 *  debuginfo doesn't pick this up even though
			 *  it exists in the kernel; it shouldn't change.
			 */
			struct x86_user_regs_struct {
			        long ebx, ecx, edx, esi, edi, ebp, eax;
			        unsigned short ds, __ds, es, __es;
			        unsigned short fs, __fs, gs, __gs;
			        long orig_eax, eip;
			        unsigned short cs, __cs;
			        long eflags, esp;
			        unsigned short ss, __ss;
			};
			ASSIGN_SIZE(user_regs_struct) = 
				sizeof(struct x86_user_regs_struct);
			ASSIGN_OFFSET(user_regs_struct_ebp) =
				offsetof(struct x86_user_regs_struct, ebp);
			ASSIGN_OFFSET(user_regs_struct_esp) =
				offsetof(struct x86_user_regs_struct, esp);
			ASSIGN_OFFSET(user_regs_struct_eip) =
				offsetof(struct x86_user_regs_struct, eip);
			ASSIGN_OFFSET(user_regs_struct_eax) =
				offsetof(struct x86_user_regs_struct, eax);
			ASSIGN_OFFSET(user_regs_struct_ebx) =
				offsetof(struct x86_user_regs_struct, ebx);
			ASSIGN_OFFSET(user_regs_struct_ecx) =
				offsetof(struct x86_user_regs_struct, ecx);
			ASSIGN_OFFSET(user_regs_struct_edx) =
				offsetof(struct x86_user_regs_struct, edx);
			ASSIGN_OFFSET(user_regs_struct_esi) =
				offsetof(struct x86_user_regs_struct, esi);
			ASSIGN_OFFSET(user_regs_struct_edi) =
				offsetof(struct x86_user_regs_struct, edi);
			ASSIGN_OFFSET(user_regs_struct_eflags) =
				offsetof(struct x86_user_regs_struct, eflags);
			ASSIGN_OFFSET(user_regs_struct_cs) =
				offsetof(struct x86_user_regs_struct, cs);
			ASSIGN_OFFSET(user_regs_struct_ds) =
				offsetof(struct x86_user_regs_struct, ds);
			ASSIGN_OFFSET(user_regs_struct_es) =
				offsetof(struct x86_user_regs_struct, es);
			ASSIGN_OFFSET(user_regs_struct_fs) =
				offsetof(struct x86_user_regs_struct, fs);
			ASSIGN_OFFSET(user_regs_struct_gs) =
				offsetof(struct x86_user_regs_struct, gs);
			ASSIGN_OFFSET(user_regs_struct_ss) =
				offsetof(struct x86_user_regs_struct, ss);
		}
		MEMBER_OFFSET_INIT(thread_struct_cr3, "thread_struct", "cr3");
		STRUCT_SIZE_INIT(cpuinfo_x86, "cpuinfo_x86");
		STRUCT_SIZE_INIT(e820map, "e820map");
		STRUCT_SIZE_INIT(e820entry, "e820entry");
		STRUCT_SIZE_INIT(irq_ctx, "irq_ctx");
		if (!VALID_STRUCT(irq_ctx))
			STRUCT_SIZE_INIT(irq_ctx, "irq_stack");
		MEMBER_OFFSET_INIT(e820map_nr_map, "e820map", "nr_map");
		MEMBER_OFFSET_INIT(e820entry_addr, "e820entry", "addr");
		MEMBER_OFFSET_INIT(e820entry_size, "e820entry", "size");
		MEMBER_OFFSET_INIT(e820entry_type, "e820entry", "type");
		if (KVMDUMP_DUMPFILE())
			set_kvm_iohole(NULL);
		if (symbol_exists("irq_desc"))
			ARRAY_LENGTH_INIT(machdep->nr_irqs, irq_desc,
				"irq_desc", NULL, 0);
		else if (kernel_symbol_exists("nr_irqs"))
			get_symbol_data("nr_irqs", sizeof(unsigned int),
				&machdep->nr_irqs);
		else
			machdep->nr_irqs = 224;  /* NR_IRQS */
		if (!machdep->hz) {
			machdep->hz = HZ;
			if (THIS_KERNEL_VERSION >= LINUX(2,6,0))
				machdep->hz = 1000;
		}

		if (machdep->flags & PAE) {
			if (THIS_KERNEL_VERSION < LINUX(2,6,26))
				machdep->section_size_bits =
					_SECTION_SIZE_BITS_PAE_ORIG;
			else
				machdep->section_size_bits =
					_SECTION_SIZE_BITS_PAE_2_6_26;
			machdep->max_physmem_bits = _MAX_PHYSMEM_BITS_PAE;
		} else {
			machdep->section_size_bits = _SECTION_SIZE_BITS;
			machdep->max_physmem_bits = _MAX_PHYSMEM_BITS;
		}

		if (XEN() && (kt->xen_flags & WRITABLE_PAGE_TABLES)) {
			if (machdep->flags & PAE) 
                        	machdep->uvtop = x86_uvtop_xen_wpt_PAE;
			else
                        	machdep->uvtop = x86_uvtop_xen_wpt;
		} 

		if (XEN()) {
			MEMBER_OFFSET_INIT(vcpu_guest_context_user_regs,
				"vcpu_guest_context", "user_regs");
			MEMBER_OFFSET_INIT(cpu_user_regs_esp,
				"cpu_user_regs", "esp");
			MEMBER_OFFSET_INIT(cpu_user_regs_eip,
				"cpu_user_regs", "eip");
		}

		if (THIS_KERNEL_VERSION < LINUX(2,6,24))
			machdep->line_number_hooks = x86_line_number_hooks;

		eframe_init();

		if (THIS_KERNEL_VERSION >= LINUX(2,6,28))
			machdep->machspec->page_protnone = _PAGE_GLOBAL;
		else
			machdep->machspec->page_protnone = _PAGE_PSE;

		STRUCT_SIZE_INIT(note_buf, "note_buf_t");
		STRUCT_SIZE_INIT(elf_prstatus, "elf_prstatus");
		MEMBER_OFFSET_INIT(elf_prstatus_pr_reg, "elf_prstatus",
				   "pr_reg");
		STRUCT_SIZE_INIT(percpu_data, "percpu_data");

		if (!remap_init())
			machdep->machspec->max_numnodes = -1;

		MEMBER_OFFSET_INIT(inactive_task_frame_ret_addr, 
			"inactive_task_frame", "ret_addr");
		break;

	case POST_INIT:
		read_idt_table(READ_IDT_INIT); 
		break;

	case LOG_ONLY:
		machdep->kvbase = kt->vmcoreinfo._stext_SYMBOL & ~KVBASE_MASK;
		break;
	}
}

/*
 *  Handle non-default (c0000000) values of CONFIG_PAGE_OFFSET 
 *  with "--machdep page_offset=<address>"
 */
static void
x86_parse_cmdline_args(void)
{
	int index, i, c, err;
	char *arglist[MAXARGS];
	char buf[BUFSIZE];
	char *p;
	ulong value = 0;

	for (index = 0; index < MAX_MACHDEP_ARGS; index++) {
		if (!machdep->cmdline_args[index])
			break;

		if (!strstr(machdep->cmdline_args[index], "=")) {
			error(WARNING, "ignoring --machdep option: %x\n",
				machdep->cmdline_args[index]);
			continue;
		}

		strcpy(buf, machdep->cmdline_args[index]);

		for (p = buf; *p; p++) {
			if (*p == ',')
				*p = ' ';
		}

		c = parse_line(buf, arglist);

		for (i = 0; i < c; i++) {
			err = 0;

			if (STRNEQ(arglist[i], "page_offset=")) {
				int flags = RETURN_ON_ERROR | QUIET;

				p = arglist[i] + strlen("page_offset=");
				if (strlen(p))
					value = htol(p, flags, &err);

				if (!err) {
					machdep->kvbase = value;

					error(NOTE, "setting PAGE_OFFSET to: 0x%lx\n\n",
						machdep->kvbase);
					continue;
				}
			}

			error(WARNING, "ignoring --machdep option: %s\n",
				arglist[i]);
		}
	}
}

/*
 *  Account for addition of pt_regs.xgs field in 2.6.20+ kernels.
 */
static void
eframe_init(void)
{
	if (INVALID_SIZE(pt_regs)) {
		if (THIS_KERNEL_VERSION < LINUX(2,6,20))
			ASSIGN_SIZE(pt_regs) = (MAX_USER_EFRAME_SIZE-2)*sizeof(ulong);
		else {
			ASSIGN_SIZE(pt_regs) = MAX_USER_EFRAME_SIZE*sizeof(ulong);
			INT_EFRAME_SS = 15;
			INT_EFRAME_ESP = 14;
			INT_EFRAME_EFLAGS = 13;
			INT_EFRAME_CS = 12;
			INT_EFRAME_EIP = 11;
			INT_EFRAME_ERR = 10;
			INT_EFRAME_GS = 9;
		}
		return;
	}

	if (MEMBER_EXISTS("pt_regs", "esp")) {
		INT_EFRAME_SS = MEMBER_OFFSET("pt_regs", "xss") / 4; 
		INT_EFRAME_ESP = MEMBER_OFFSET("pt_regs", "esp") / 4;
		INT_EFRAME_EFLAGS = MEMBER_OFFSET("pt_regs", "eflags") / 4;
		INT_EFRAME_CS = MEMBER_OFFSET("pt_regs", "xcs") / 4;
		INT_EFRAME_EIP = MEMBER_OFFSET("pt_regs", "eip") / 4;
		INT_EFRAME_ERR = MEMBER_OFFSET("pt_regs", "orig_eax") / 4;
		if ((INT_EFRAME_GS = MEMBER_OFFSET("pt_regs", "xgs")) != -1)
			INT_EFRAME_GS /= 4;
		INT_EFRAME_ES = MEMBER_OFFSET("pt_regs", "xes") / 4;
		INT_EFRAME_DS = MEMBER_OFFSET("pt_regs", "xds") / 4;
		INT_EFRAME_EAX = MEMBER_OFFSET("pt_regs", "eax") / 4;
		INT_EFRAME_EBP = MEMBER_OFFSET("pt_regs", "ebp") / 4;
		INT_EFRAME_EDI = MEMBER_OFFSET("pt_regs", "edi") / 4;
		INT_EFRAME_ESI = MEMBER_OFFSET("pt_regs", "esi") / 4;
		INT_EFRAME_EDX = MEMBER_OFFSET("pt_regs", "edx") / 4;
		INT_EFRAME_ECX = MEMBER_OFFSET("pt_regs", "ecx") / 4;
		INT_EFRAME_EBX = MEMBER_OFFSET("pt_regs", "ebx") / 4;
	} else {
		INT_EFRAME_SS = MEMBER_OFFSET("pt_regs", "ss") / 4; 
		INT_EFRAME_ESP = MEMBER_OFFSET("pt_regs", "sp") / 4;
		INT_EFRAME_EFLAGS = MEMBER_OFFSET("pt_regs", "flags") / 4;
		INT_EFRAME_CS = MEMBER_OFFSET("pt_regs", "cs") / 4;
		INT_EFRAME_EIP = MEMBER_OFFSET("pt_regs", "ip") / 4;
		INT_EFRAME_ERR = MEMBER_OFFSET("pt_regs", "orig_ax") / 4;
		if ((INT_EFRAME_GS = MEMBER_OFFSET("pt_regs", "gs")) != -1)
			INT_EFRAME_GS /= 4;
		INT_EFRAME_ES = MEMBER_OFFSET("pt_regs", "es") / 4;
		INT_EFRAME_DS = MEMBER_OFFSET("pt_regs", "ds") / 4;
		INT_EFRAME_EAX = MEMBER_OFFSET("pt_regs", "ax") / 4;
		INT_EFRAME_EBP = MEMBER_OFFSET("pt_regs", "bp") / 4;
		INT_EFRAME_EDI = MEMBER_OFFSET("pt_regs", "di") / 4;
		INT_EFRAME_ESI = MEMBER_OFFSET("pt_regs", "si") / 4;
		INT_EFRAME_EDX = MEMBER_OFFSET("pt_regs", "dx") / 4;
		INT_EFRAME_ECX = MEMBER_OFFSET("pt_regs", "cx") / 4;
		INT_EFRAME_EBX = MEMBER_OFFSET("pt_regs", "bx") / 4;
	}
}

/*
 *  Locate regions remapped by the remap allocator
 */
static int
remap_init(void)
{
	ulong start_vaddr, end_vaddr, start_pfn;
	int max_numnodes;
	struct machine_specific *ms;
	struct syment *sp;

	if (! (sp = symbol_search("node_remap_start_vaddr")) )
		return FALSE;
	start_vaddr = sp->value;

	if (! (sp = symbol_search("node_remap_end_vaddr")) )
		return FALSE;
	end_vaddr = sp->value;

	if (! (sp = symbol_search("node_remap_start_pfn")) )
		return FALSE;
	start_pfn = sp->value;

	max_numnodes = get_array_length("node_remap_start_pfn", NULL,
					sizeof(ulong));
	if (max_numnodes < 1)
		max_numnodes = 1;

	ms = machdep->machspec;
	ms->remap_start_vaddr = calloc(3 * max_numnodes, sizeof(ulong));
	if (!ms->remap_start_vaddr)
		error(FATAL, "cannot malloc remap array");
	ms->remap_end_vaddr = ms->remap_start_vaddr + max_numnodes;
	ms->remap_start_pfn = ms->remap_end_vaddr + max_numnodes;

	readmem(start_vaddr, KVADDR, ms->remap_start_vaddr,
		max_numnodes * sizeof(ulong), "node_remap_start_vaddr",
		FAULT_ON_ERROR);
	readmem(end_vaddr, KVADDR, ms->remap_end_vaddr,
		max_numnodes * sizeof(ulong), "node_remap_end_vaddr",
		FAULT_ON_ERROR);
	readmem(start_pfn, KVADDR, ms->remap_start_pfn,
		max_numnodes * sizeof(ulong), "node_remap_end_vaddr",
		FAULT_ON_ERROR);
	ms->max_numnodes = max_numnodes;

	return TRUE;
}

static int
x86_kvtop_remap(ulong kvaddr, physaddr_t *paddr)
{
	struct machine_specific *ms;
	int i;

	ms = machdep->machspec;

	/* ms->max_numnodes is -1 when unused. */
	
	for (i = 0; i < ms->max_numnodes; ++i) {
		if (kvaddr >= ms->remap_start_vaddr[i] &&
		    kvaddr < ms->remap_end_vaddr[i]) {
			*paddr = PTOB(ms->remap_start_pfn[i]) +
				kvaddr - ms->remap_start_vaddr[i];
			return TRUE;
		}
	}
	return FALSE;
}

/*
 *  Needs to be done this way because of potential 4G/4G split.
 */
static int 
x86_is_uvaddr(ulong vaddr, struct task_context *tc)
{
	return IN_TASK_VMA(tc->task, vaddr);
}

/*
 *  Translates a user virtual address to its physical address.  cmd_vtop()
 *  sets the verbose flag so that the pte translation gets displayed; all
 *  other callers quietly accept the translation.
 *
 *  This routine can also take mapped kernel virtual addresses if the -u flag
 *  was passed to cmd_vtop().  If so, it makes the translation using the
 *  kernel-memory PGD entry instead of swapper_pg_dir.
 */

#define _4MB_PAGE_MASK       (~((MEGABYTES(4))-1))
#define _2MB_PAGE_MASK       (~((MEGABYTES(2))-1))

static int
x86_uvtop(struct task_context *tc, ulong vaddr, physaddr_t *paddr, int verbose)
{
	ulong mm, active_mm;
	ulong *pgd;
	ulong *page_dir;
	ulong *page_middle;
	ulong *page_table;
	ulong pgd_pte;
	ulong pmd_pte;
	ulong pte;
	char buf[BUFSIZE];

	if (!tc)
		error(FATAL, "current context invalid\n");

	*paddr = 0;

        if (is_kernel_thread(tc->task) && IS_KVADDR(vaddr)) { 
	    	if (VALID_MEMBER(thread_struct_cr3)) 
                	pgd = (ulong *)machdep->get_task_pgd(tc->task);
		else {
			if (INVALID_MEMBER(task_struct_active_mm))
				error(FATAL, "no cr3 or active_mm?\n");

                	readmem(tc->task + OFFSET(task_struct_active_mm), 
				KVADDR, &active_mm, sizeof(void *),
                        	"task active_mm contents", FAULT_ON_ERROR);

			if (!active_mm)
				error(FATAL, 
				     "no active_mm for this kernel thread\n");

			readmem(active_mm + OFFSET(mm_struct_pgd), 
				KVADDR, &pgd, sizeof(long), 
				"mm_struct pgd", FAULT_ON_ERROR);
		}
        } else {
		if ((mm = task_mm(tc->task, TRUE)))
			pgd = ULONG_PTR(tt->mm_struct + 
				OFFSET(mm_struct_pgd));
		else
			readmem(tc->mm_struct + OFFSET(mm_struct_pgd), 
				KVADDR, &pgd, sizeof(long), "mm_struct pgd", 
				FAULT_ON_ERROR);
	}

	if (verbose) 
		fprintf(fp, "PAGE DIRECTORY: %lx\n", (ulong)pgd);

	page_dir = pgd + (vaddr >> PGDIR_SHIFT);

	FILL_PGD(NONPAE_PAGEBASE(pgd), KVADDR, PAGESIZE());
	pgd_pte = ULONG(machdep->pgd + PAGEOFFSET(page_dir));

	if (verbose)
		fprintf(fp, "  PGD: %s => %lx\n", 
			mkstring(buf, VADDR_PRLEN, RJUST|LONG_HEX, 
			MKSTR((ulong)page_dir)),
			pgd_pte);

	if (!(pgd_pte & (_PAGE_PRESENT | _PAGE_PROTNONE)))
		goto no_upage;

        if (pgd_pte & _PAGE_4M) {
                if (verbose) {
                        fprintf(fp, " PAGE: %s  (4MB)\n\n", 
				mkstring(buf, VADDR_PRLEN, RJUST|LONG_HEX, 
				MKSTR(NONPAE_PAGEBASE(pgd_pte))));
			x86_translate_pte(pgd_pte, 0, 0);
		}

		*paddr = NONPAE_PAGEBASE(pgd_pte) + (vaddr & ~_4MB_PAGE_MASK);
                return TRUE;
        }

	page_middle = page_dir;

	FILL_PMD(NONPAE_PAGEBASE(page_middle), KVADDR, PAGESIZE());
	pmd_pte = ULONG(machdep->pmd + PAGEOFFSET(page_middle));

	if (verbose)
		fprintf(fp, "  PMD: %s => %lx\n", 
		        mkstring(buf, VADDR_PRLEN, RJUST|LONG_HEX,
                        MKSTR((ulong)page_middle)),
			pmd_pte);

	if (!pmd_pte)
		goto no_upage;

#ifdef PTES_IN_LOWMEM
	page_table = (ulong *)(PTOV(NONPAE_PAGEBASE(pmd_pte)) + 
		((vaddr>>10) & ((PTRS_PER_PTE-1)<<2)));

	FILL_PTBL(NONPAE_PAGEBASE(page_table), KVADDR, PAGESIZE());
	pte = ULONG(machdep->ptbl + PAGEOFFSET(page_table));
#else
        page_table = (ulong *)((NONPAE_PAGEBASE(pmd_pte)) +
                ((vaddr>>10) & ((PTRS_PER_PTE-1)<<2)));

        FILL_PTBL(NONPAE_PAGEBASE(page_table), PHYSADDR, PAGESIZE());
        pte = ULONG(machdep->ptbl + PAGEOFFSET(page_table));
#endif

        if (verbose) 
                fprintf(fp, "  PTE: %s => %lx\n", 
			mkstring(buf, VADDR_PRLEN, RJUST|LONG_HEX,
                        MKSTR((ulong)page_table)), pte);

	if (!(pte & (_PAGE_PRESENT | _PAGE_PROTNONE))) {
		*paddr = pte;

		if (pte && verbose) {
			fprintf(fp, "\n");
			x86_translate_pte(pte, 0, 0);
		}
		
		goto no_upage;
	}

	*paddr = NONPAE_PAGEBASE(pte) + PAGEOFFSET(vaddr);

        if (verbose) {
                fprintf(fp, " PAGE: %s\n\n", 
			mkstring(buf, VADDR_PRLEN, RJUST|LONG_HEX, 
			MKSTR(NONPAE_PAGEBASE(pte))));
		x86_translate_pte(pte, 0, 0);
	}

	return TRUE;

no_upage:
	return FALSE;
}

static int
x86_uvtop_xen_wpt(struct task_context *tc, ulong vaddr, physaddr_t *paddr, int verbose)
{
	ulong mm, active_mm;
	ulong *pgd;
	ulong *page_dir;
	ulong *page_middle;
	ulong *machine_page_table, *pseudo_page_table;
	ulong pgd_pte, pseudo_pgd_pte;
	ulong pmd_pte;
	ulong machine_pte, pseudo_pte;
	char buf[BUFSIZE];

	if (!tc)
		error(FATAL, "current context invalid\n");

	*paddr = 0;

        if (is_kernel_thread(tc->task) && IS_KVADDR(vaddr)) { 
	    	if (VALID_MEMBER(thread_struct_cr3)) 
                	pgd = (ulong *)machdep->get_task_pgd(tc->task);
		else {
			if (INVALID_MEMBER(task_struct_active_mm))
				error(FATAL, "no cr3 or active_mm?\n");

                	readmem(tc->task + OFFSET(task_struct_active_mm), 
				KVADDR, &active_mm, sizeof(void *),
                        	"task active_mm contents", FAULT_ON_ERROR);

			if (!active_mm)
				error(FATAL, 
				     "no active_mm for this kernel thread\n");

			readmem(active_mm + OFFSET(mm_struct_pgd), 
				KVADDR, &pgd, sizeof(long), 
				"mm_struct pgd", FAULT_ON_ERROR);
		}
        } else {
		if ((mm = task_mm(tc->task, TRUE)))
			pgd = ULONG_PTR(tt->mm_struct + 
				OFFSET(mm_struct_pgd));
		else
			readmem(tc->mm_struct + OFFSET(mm_struct_pgd), 
				KVADDR, &pgd, sizeof(long), "mm_struct pgd", 
				FAULT_ON_ERROR);
	}

	if (verbose) 
		fprintf(fp, "PAGE DIRECTORY: %lx\n", (ulong)pgd);

	page_dir = pgd + (vaddr >> PGDIR_SHIFT);

	FILL_PGD(NONPAE_PAGEBASE(pgd), KVADDR, PAGESIZE());
	pgd_pte = ULONG(machdep->pgd + PAGEOFFSET(page_dir));

	if (verbose)
		fprintf(fp, "  PGD: %s => %lx\n", 
			mkstring(buf, VADDR_PRLEN, RJUST|LONG_HEX, 
			MKSTR((ulong)page_dir)),
			pgd_pte);

	if (!pgd_pte)
		goto no_upage;

        if (pgd_pte & _PAGE_4M) {
                if (verbose) 
                        fprintf(fp, " PAGE: %s  (4MB) [machine]\n", 
				mkstring(buf, VADDR_PRLEN, RJUST|LONG_HEX, 
				MKSTR(NONPAE_PAGEBASE(pgd_pte))));

		pseudo_pgd_pte = xen_m2p_nonPAE(NONPAE_PAGEBASE(pgd_pte));

                if (pseudo_pgd_pte == XEN_MFN_NOT_FOUND) {
                        if (verbose)
                                fprintf(fp, " PAGE: page not available\n");
                        *paddr = PADDR_NOT_AVAILABLE;
                        return FALSE;
                }

		pseudo_pgd_pte |= PAGEOFFSET(pgd_pte);

		if (verbose) {
			fprintf(fp, " PAGE: %s  (4MB)\n\n", 
				mkstring(buf, VADDR_PRLEN, RJUST|LONG_HEX,
                        	MKSTR(NONPAE_PAGEBASE(pseudo_pgd_pte))));

			x86_translate_pte(pseudo_pgd_pte, 0, 0);
		}

		*paddr = NONPAE_PAGEBASE(pseudo_pgd_pte) + 
			(vaddr & ~_4MB_PAGE_MASK);

		return TRUE;
        }

	page_middle = page_dir;

	FILL_PMD(NONPAE_PAGEBASE(page_middle), KVADDR, PAGESIZE());
	pmd_pte = ULONG(machdep->pmd + PAGEOFFSET(page_middle));

	if (verbose)
		fprintf(fp, "  PMD: %s => %lx\n", 
		        mkstring(buf, VADDR_PRLEN, RJUST|LONG_HEX,
                        MKSTR((ulong)page_middle)),
			pmd_pte);

	if (!pmd_pte)
		goto no_upage;

        machine_page_table = (ulong *)((NONPAE_PAGEBASE(pmd_pte)) +
                ((vaddr>>10) & ((PTRS_PER_PTE-1)<<2)));

        pseudo_page_table = (ulong *)
                xen_m2p_nonPAE(NONPAE_PAGEBASE(machine_page_table));

        FILL_PTBL(NONPAE_PAGEBASE(pseudo_page_table), PHYSADDR, PAGESIZE());
        machine_pte = ULONG(machdep->ptbl + PAGEOFFSET(machine_page_table));

        if (verbose) {
                fprintf(fp, "  PTE: %s [machine]\n", 
			mkstring(buf, VADDR_PRLEN, RJUST|LONG_HEX,
                        MKSTR((ulong)machine_page_table)));

                fprintf(fp, "  PTE: %s => %lx\n",
                        mkstring(buf, VADDR_PRLEN, RJUST|LONG_HEX,
                        MKSTR((ulong)pseudo_page_table +
                        PAGEOFFSET(machine_page_table))), machine_pte);
	}

	if (!(machine_pte & (_PAGE_PRESENT | _PAGE_PROTNONE))) {
		*paddr = machine_pte;

		if (machine_pte && verbose) {
			fprintf(fp, "\n");
			x86_translate_pte(machine_pte, 0, 0);
		}
		
		goto no_upage;
	}

        pseudo_pte = xen_m2p_nonPAE(NONPAE_PAGEBASE(machine_pte));
        pseudo_pte |= PAGEOFFSET(machine_pte);

	*paddr = NONPAE_PAGEBASE(pseudo_pte) + PAGEOFFSET(vaddr);

        if (verbose) {
                fprintf(fp, " PAGE: %s [machine]\n", 
			mkstring(buf, VADDR_PRLEN, RJUST|LONG_HEX, 
			MKSTR(NONPAE_PAGEBASE(machine_pte))));

                fprintf(fp, " PAGE: %s\n\n",
                        mkstring(buf, VADDR_PRLEN, RJUST|LONG_HEX,
                        MKSTR(NONPAE_PAGEBASE(pseudo_pte))));

                x86_translate_pte(pseudo_pte, 0, 0);
	}

	return TRUE;

no_upage:
	return FALSE;
}

static int
x86_uvtop_PAE(struct task_context *tc, ulong vaddr, physaddr_t *paddr, int verbose)
{
	ulong mm, active_mm;
	ulonglong *pgd;
	ulonglong page_dir_entry;
	ulonglong page_middle;
	ulonglong page_middle_entry;
	ulonglong page_table;
	ulonglong page_table_entry;
	ulonglong physpage;
	ulonglong ull;
	ulong offset;
	char buf[BUFSIZE];

	if (!tc)
		error(FATAL, "current context invalid\n");

	*paddr = 0;

        if (is_kernel_thread(tc->task) && IS_KVADDR(vaddr)) { 
	    	if (VALID_MEMBER(thread_struct_cr3)) 
                	pgd = (ulonglong *)machdep->get_task_pgd(tc->task);
		else {
			if (INVALID_MEMBER(task_struct_active_mm))
				error(FATAL, "no cr3 or active_mm?\n");

                	readmem(tc->task + OFFSET(task_struct_active_mm), 
				KVADDR, &active_mm, sizeof(void *),
                        	"task active_mm contents", FAULT_ON_ERROR);

			if (!active_mm)
				error(FATAL, 
				     "no active_mm for this kernel thread\n");

			readmem(active_mm + OFFSET(mm_struct_pgd), 
				KVADDR, &pgd, sizeof(long), 
				"mm_struct pgd", FAULT_ON_ERROR);
		}
        } else {
		if ((mm = task_mm(tc->task, TRUE)))
			pgd = (ulonglong *)(ULONG_PTR(tt->mm_struct + 
				OFFSET(mm_struct_pgd)));
		else
			readmem(tc->mm_struct + OFFSET(mm_struct_pgd), 
				KVADDR, &pgd, sizeof(long), "mm_struct pgd", 
				FAULT_ON_ERROR);
	}

	if (verbose) 
		fprintf(fp, "PAGE DIRECTORY: %lx\n", (ulong)pgd);

	FILL_PGD(pgd, KVADDR, PTRS_PER_PGD * sizeof(ulonglong));

	offset = ((vaddr >> PGDIR_SHIFT) & (PTRS_PER_PGD-1)) * 
		sizeof(ulonglong);

	page_dir_entry = *((ulonglong *)&machdep->pgd[offset]);

	if (verbose)
		fprintf(fp, "  PGD: %s => %llx\n", 
			mkstring(buf, VADDR_PRLEN, RJUST|LONG_HEX, 
			MKSTR((ulong)pgd + offset)), 
			page_dir_entry);

	if (!(page_dir_entry & _PAGE_PRESENT)) {
		goto no_upage;
	}

	page_middle = PAE_PAGEBASE(page_dir_entry);

	FILL_PMD_PAE(page_middle, PHYSADDR, PAGESIZE());

	offset = ((vaddr >> PMD_SHIFT) & (PTRS_PER_PMD-1)) * sizeof(ulonglong);

        page_middle_entry = *((ulonglong *)&machdep->pmd[offset]);

        if (verbose) {
		ull = page_middle + offset;
                fprintf(fp, "  PMD: %s => %llx\n", 
			mkstring(buf, VADDR_PRLEN, RJUST|LONGLONG_HEX, 
			MKSTR(&ull)), 
			page_middle_entry);
	}

        if (!(page_middle_entry & (_PAGE_PRESENT | _PAGE_PROTNONE))) {
                goto no_upage;
        }

        if (page_middle_entry & _PAGE_PSE) {
                if (verbose) {
			ull = PAE_PAGEBASE(page_middle_entry);
                        fprintf(fp, " PAGE: %s  (2MB)\n\n",
				mkstring(buf, VADDR_PRLEN, RJUST|LONGLONG_HEX,
                        	MKSTR(&ull)));
                        x86_translate_pte(0, 0, page_middle_entry);
                }

                physpage = PAE_PAGEBASE(page_middle_entry) +
                        (vaddr & ~_2MB_PAGE_MASK);
                *paddr = physpage;

                return TRUE;
        }

        page_table = PAE_PAGEBASE(page_middle_entry);

        FILL_PTBL_PAE(page_table, PHYSADDR, PAGESIZE());

	offset = ((vaddr >> PAGESHIFT()) & (PTRS_PER_PTE-1)) * 
		sizeof(ulonglong);

        page_table_entry = *((ulonglong *)&machdep->ptbl[offset]);

        if (verbose) {
		ull = page_table + offset;
                fprintf(fp, "  PTE: %s => %llx\n", 
			mkstring(buf, VADDR_PRLEN, RJUST|LONGLONG_HEX, 
			MKSTR(&ull)), page_table_entry);
	}

        if (!(page_table_entry & (_PAGE_PRESENT | _PAGE_PROTNONE))) {
                *paddr = page_table_entry;

                if (page_table_entry && verbose) {
                        fprintf(fp, "\n");
                        x86_translate_pte(0, 0, page_table_entry);
                }

                goto no_upage;
        }

	physpage = PAE_PAGEBASE(page_table_entry) + PAGEOFFSET(vaddr);

        *paddr = physpage;

        if (verbose) {
                ull = PAE_PAGEBASE(page_table_entry);
                fprintf(fp, " PAGE: %s\n\n",
                        mkstring(buf, VADDR_PRLEN, RJUST|LONGLONG_HEX,
                        MKSTR(&ull)));
                x86_translate_pte(0, 0, page_table_entry);
        }

        return TRUE;

no_upage:
	return FALSE;
}

static int
x86_uvtop_xen_wpt_PAE(struct task_context *tc, ulong vaddr, physaddr_t *paddr, int verbose)
{
	ulong mm, active_mm;
	ulonglong *pgd;
	ulonglong page_dir_entry;
	ulonglong page_middle, pseudo_page_middle;
	ulonglong page_middle_entry;
	ulonglong page_table, pseudo_page_table;
	ulonglong page_table_entry, pte;
	ulonglong physpage, pseudo_physpage;
	ulonglong ull;
	ulong offset;
	char buf[BUFSIZE];

	if (!tc)
		error(FATAL, "current context invalid\n");

	*paddr = 0;

        if (is_kernel_thread(tc->task) && IS_KVADDR(vaddr)) { 
	    	if (VALID_MEMBER(thread_struct_cr3)) 
                	pgd = (ulonglong *)machdep->get_task_pgd(tc->task);
		else {
			if (INVALID_MEMBER(task_struct_active_mm))
				error(FATAL, "no cr3 or active_mm?\n");

                	readmem(tc->task + OFFSET(task_struct_active_mm), 
				KVADDR, &active_mm, sizeof(void *),
                        	"task active_mm contents", FAULT_ON_ERROR);

			if (!active_mm)
				error(FATAL, 
				     "no active_mm for this kernel thread\n");

			readmem(active_mm + OFFSET(mm_struct_pgd), 
				KVADDR, &pgd, sizeof(long), 
				"mm_struct pgd", FAULT_ON_ERROR);
		}
        } else {
		if ((mm = task_mm(tc->task, TRUE)))
			pgd = (ulonglong *)(ULONG_PTR(tt->mm_struct + 
				OFFSET(mm_struct_pgd)));
		else
			readmem(tc->mm_struct + OFFSET(mm_struct_pgd), 
				KVADDR, &pgd, sizeof(long), "mm_struct pgd", 
				FAULT_ON_ERROR);
	}

	if (verbose) 
		fprintf(fp, "PAGE DIRECTORY: %lx\n", (ulong)pgd);

	FILL_PGD(pgd, KVADDR, PTRS_PER_PGD * sizeof(ulonglong));

	offset = ((vaddr >> PGDIR_SHIFT) & (PTRS_PER_PGD-1)) * 
		sizeof(ulonglong);

	page_dir_entry = *((ulonglong *)&machdep->pgd[offset]);

	if (verbose)
		fprintf(fp, "  PGD: %s => %llx [machine]\n", 
			mkstring(buf, VADDR_PRLEN, RJUST|LONG_HEX, 
			MKSTR((ulong)pgd + offset)), 
			page_dir_entry);

	if (!(page_dir_entry & _PAGE_PRESENT)) {
		goto no_upage;
	}

	page_middle = PAE_PAGEBASE(page_dir_entry);
	pseudo_page_middle = xen_m2p(page_middle); 

        if (verbose)
                fprintf(fp, "  PGD: %s => %llx\n",
                        mkstring(buf, VADDR_PRLEN, RJUST|LONG_HEX,
                        MKSTR((ulong)pgd + offset)),
                        pseudo_page_middle | PAGEOFFSET(page_dir_entry) |
                        (page_dir_entry & _PAGE_NX));

	FILL_PMD_PAE(pseudo_page_middle, PHYSADDR, PAGESIZE());

	offset = ((vaddr >> PMD_SHIFT) & (PTRS_PER_PMD-1)) * sizeof(ulonglong);

        page_middle_entry = *((ulonglong *)&machdep->pmd[offset]);

        if (verbose) {
		ull = page_middle + offset;
                fprintf(fp, "  PMD: %s => %llx [machine]\n", 
			mkstring(buf, VADDR_PRLEN, RJUST|LONGLONG_HEX, 
			MKSTR(&ull)), 
			page_middle_entry);
	}

        if (!(page_middle_entry & _PAGE_PRESENT)) {
                goto no_upage;
        }

        if (page_middle_entry & _PAGE_PSE) {
		error(FATAL, "_PAGE_PSE in an mfn not supported\n");  /* XXX */
                if (verbose) {
			ull = PAE_PAGEBASE(page_middle_entry);
                        fprintf(fp, " PAGE: %s  (2MB)\n\n",
				mkstring(buf, VADDR_PRLEN, RJUST|LONGLONG_HEX,
                        	MKSTR(&ull)));
                        x86_translate_pte(0, 0, page_middle_entry);
                }

                physpage = PAE_PAGEBASE(page_middle_entry) +
                        (vaddr & ~_2MB_PAGE_MASK);
                *paddr = physpage;

                return TRUE;
        }

        page_table = PAE_PAGEBASE(page_middle_entry);
	pseudo_page_table = xen_m2p(page_table); 

        if (verbose) {
                ull = page_middle + offset;
                fprintf(fp, "  PMD: %s => %llx\n",
                        mkstring(buf, VADDR_PRLEN, RJUST|LONGLONG_HEX,
                        MKSTR(&ull)),
                        pseudo_page_table | PAGEOFFSET(page_middle_entry) |
                        (page_middle_entry & _PAGE_NX));
        }

        FILL_PTBL_PAE(pseudo_page_table, PHYSADDR, PAGESIZE());

	offset = ((vaddr >> PAGESHIFT()) & (PTRS_PER_PTE-1)) * 
		sizeof(ulonglong);

        page_table_entry = *((ulonglong *)&machdep->ptbl[offset]);

        if (verbose) {
		ull = page_table + offset;
                fprintf(fp, "  PTE: %s => %llx [machine]\n", 
			mkstring(buf, VADDR_PRLEN, RJUST|LONGLONG_HEX, 
			MKSTR(&ull)), page_table_entry);
	}

        if (!(page_table_entry & (_PAGE_PRESENT | _PAGE_PROTNONE))) {
                *paddr = page_table_entry;

                if (page_table_entry && verbose) {
                        fprintf(fp, "\n");
                        x86_translate_pte(0, 0, page_table_entry);
                }

                goto no_upage;
        }

	physpage = PAE_PAGEBASE(page_table_entry) + PAGEOFFSET(vaddr);
	pseudo_physpage = xen_m2p(physpage); 

        if (verbose) {
                ull = page_table + offset;
                fprintf(fp, "  PTE: %s => %llx\n",
                        mkstring(buf, VADDR_PRLEN, RJUST|LONGLONG_HEX,
                        MKSTR(&ull)),
                        pseudo_physpage | PAGEOFFSET(page_table_entry) |
                        (page_table_entry & _PAGE_NX));
        }

        *paddr = pseudo_physpage + PAGEOFFSET(vaddr);

        if (verbose) {
		physpage = PAE_PAGEBASE(physpage);
                fprintf(fp, " PAGE: %s [machine]\n", 
			mkstring(buf, VADDR_PRLEN, RJUST|LONGLONG_HEX, 
			MKSTR(&physpage)));
		
                fprintf(fp, " PAGE: %s\n\n",
                        mkstring(buf, VADDR_PRLEN, RJUST|LONGLONG_HEX,
                        MKSTR(&pseudo_physpage)));

		pte = pseudo_physpage | PAGEOFFSET(page_table_entry) |
			(page_table_entry & _PAGE_NX);

                x86_translate_pte(0, 0, pte);
        }

        return TRUE;

no_upage:
	return FALSE;
}

/*
 *  Translates a kernel virtual address to its physical address.  cmd_vtop()
 *  sets the verbose flag so that the pte translation gets displayed; all
 *  other callers quietly accept the translation.
 */

static int
x86_kvtop(struct task_context *tc, ulong kvaddr, physaddr_t *paddr, int verbose)
{
	ulong *pgd;
	ulong *page_dir;
	ulong *page_middle;
	ulong *page_table;
        ulong pgd_pte;
        ulong pmd_pte;
        ulong pte;
	char buf[BUFSIZE];

	if (!IS_KVADDR(kvaddr))
		return FALSE;

	if (XEN_HYPER_MODE()) {
		if (DIRECTMAP_VIRT_ADDR(kvaddr)) {
			*paddr = kvaddr - DIRECTMAP_VIRT_START;
			return TRUE;
		}
		pgd = (ulong *)symbol_value("idle_pg_table_l2");
	} else {
		if (x86_kvtop_remap(kvaddr, paddr)) {
			if (!verbose)
				return TRUE;
		} else if (!vt->vmalloc_start) {
			*paddr = VTOP(kvaddr);
			return TRUE;
		} else if (!IS_VMALLOC_ADDR(kvaddr)) { 
			*paddr = VTOP(kvaddr);
			if (!verbose)
				return TRUE;
		}

		if (XEN() && (kt->xen_flags & WRITABLE_PAGE_TABLES))
			return (x86_kvtop_xen_wpt(tc, kvaddr, paddr, verbose));

		pgd = (ulong *)vt->kernel_pgd[0];
	}

	if (verbose) 
		fprintf(fp, "PAGE DIRECTORY: %lx\n", (ulong)pgd);

	page_dir = pgd + (kvaddr >> PGDIR_SHIFT);

        FILL_PGD(NONPAE_PAGEBASE(pgd), KVADDR, PAGESIZE());
        pgd_pte = ULONG(machdep->pgd + PAGEOFFSET(page_dir));

	if (verbose)
		fprintf(fp, "  PGD: %s => %lx\n", 
			mkstring(buf, VADDR_PRLEN, RJUST|LONG_HEX, 
			MKSTR((ulong)page_dir)), pgd_pte);

	if (!pgd_pte)
		goto no_kpage;

	if (pgd_pte & _PAGE_4M) {
		if (verbose) {
			fprintf(fp, " PAGE: %s  (4MB)\n\n", 
				mkstring(buf, VADDR_PRLEN, RJUST|LONG_HEX,
                        	MKSTR(NONPAE_PAGEBASE(pgd_pte))));
			x86_translate_pte(pgd_pte, 0, 0);
		}

		*paddr = NONPAE_PAGEBASE(pgd_pte) + (kvaddr & ~_4MB_PAGE_MASK);

		return TRUE;
	} 

	page_middle = page_dir;

        FILL_PMD(NONPAE_PAGEBASE(page_middle), KVADDR, PAGESIZE());
        pmd_pte = ULONG(machdep->pmd + PAGEOFFSET(page_middle));

	if (verbose)
		fprintf(fp, "  PMD: %s => %lx\n", 
			mkstring(buf, VADDR_PRLEN, RJUST|LONG_HEX, 
			MKSTR((ulong)page_middle)), pmd_pte);

	if (!pmd_pte)
		goto no_kpage;

#ifdef PTES_IN_LOWMEM
	page_table = (ulong *)(PTOV(NONPAE_PAGEBASE(pmd_pte)) + 
		((kvaddr>>10) & ((PTRS_PER_PTE-1)<<2)));
	
        FILL_PTBL(NONPAE_PAGEBASE(page_table), KVADDR, PAGESIZE());
        pte = ULONG(machdep->ptbl + PAGEOFFSET(page_table));
#else
        page_table = (ulong *)((NONPAE_PAGEBASE(pmd_pte)) +
                ((kvaddr>>10) & ((PTRS_PER_PTE-1)<<2)));

        FILL_PTBL(NONPAE_PAGEBASE(page_table), PHYSADDR, PAGESIZE());
        pte = ULONG(machdep->ptbl + PAGEOFFSET(page_table));
#endif

        if (verbose) 
                fprintf(fp, "  PTE: %s => %lx\n", 
			mkstring(buf, VADDR_PRLEN, RJUST|LONG_HEX, 
			MKSTR((ulong)page_table)), pte);

	if (!(pte & (_PAGE_PRESENT | _PAGE_PROTNONE))) {
		if (pte && verbose) {
			fprintf(fp, "\n");
			x86_translate_pte(pte, 0, 0);
		}
		goto no_kpage;
	}

	if (verbose) {
		fprintf(fp, " PAGE: %s\n\n", 
			mkstring(buf, VADDR_PRLEN, RJUST|LONG_HEX, 
			MKSTR(NONPAE_PAGEBASE(pte))));
		x86_translate_pte(pte, 0, 0);
	}

	*paddr = NONPAE_PAGEBASE(pte) + PAGEOFFSET(kvaddr);

	return TRUE;

no_kpage:
	return FALSE;
}

static int
x86_kvtop_xen_wpt(struct task_context *tc, ulong kvaddr, physaddr_t *paddr, int verbose)
{
	ulong *pgd;
	ulong *page_dir;
	ulong *page_middle;
	ulong *machine_page_table, *pseudo_page_table;
        ulong pgd_pte, pseudo_pgd_pte;
        ulong pmd_pte;
        ulong machine_pte, pseudo_pte;
	char buf[BUFSIZE];

	pgd = (ulong *)vt->kernel_pgd[0];

	if (verbose) 
		fprintf(fp, "PAGE DIRECTORY: %lx\n", (ulong)pgd);

	page_dir = pgd + (kvaddr >> PGDIR_SHIFT);

        FILL_PGD(NONPAE_PAGEBASE(pgd), KVADDR, PAGESIZE());
        pgd_pte = ULONG(machdep->pgd + PAGEOFFSET(page_dir));

	if (verbose)
		fprintf(fp, "  PGD: %s => %lx\n", 
			mkstring(buf, VADDR_PRLEN, RJUST|LONG_HEX, 
			MKSTR((ulong)page_dir)), pgd_pte);

	if (!pgd_pte)
		goto no_kpage;

	if (pgd_pte & _PAGE_4M) {
		if (verbose)
			fprintf(fp, " PAGE: %s  (4MB) [machine]\n", 
				mkstring(buf, VADDR_PRLEN, RJUST|LONG_HEX,
                        	MKSTR(NONPAE_PAGEBASE(pgd_pte))));

		pseudo_pgd_pte = xen_m2p_nonPAE(NONPAE_PAGEBASE(pgd_pte));

		if (pseudo_pgd_pte == XEN_MFN_NOT_FOUND) {
			if (verbose)
				fprintf(fp, " PAGE: page not available\n");
			*paddr = PADDR_NOT_AVAILABLE;
			return FALSE;
		}

		pseudo_pgd_pte |= PAGEOFFSET(pgd_pte);

		if (verbose) {
			fprintf(fp, " PAGE: %s  (4MB)\n\n", 
				mkstring(buf, VADDR_PRLEN, RJUST|LONG_HEX,
                        	MKSTR(NONPAE_PAGEBASE(pseudo_pgd_pte))));

			x86_translate_pte(pseudo_pgd_pte, 0, 0);
		}

		*paddr = NONPAE_PAGEBASE(pseudo_pgd_pte) + 
			(kvaddr & ~_4MB_PAGE_MASK);

		return TRUE;
	} 

	page_middle = page_dir;

        FILL_PMD(NONPAE_PAGEBASE(page_middle), KVADDR, PAGESIZE());
        pmd_pte = ULONG(machdep->pmd + PAGEOFFSET(page_middle));

	if (verbose)
		fprintf(fp, "  PMD: %s => %lx\n", 
			mkstring(buf, VADDR_PRLEN, RJUST|LONG_HEX, 
			MKSTR((ulong)page_middle)), pmd_pte);

	if (!pmd_pte)
		goto no_kpage;

        machine_page_table = (ulong *)((NONPAE_PAGEBASE(pmd_pte)) +
                ((kvaddr>>10) & ((PTRS_PER_PTE-1)<<2)));

	pseudo_page_table = (ulong *)
		xen_m2p_nonPAE(NONPAE_PAGEBASE(machine_page_table));

        FILL_PTBL(NONPAE_PAGEBASE(pseudo_page_table), PHYSADDR, PAGESIZE());
        machine_pte = ULONG(machdep->ptbl + PAGEOFFSET(machine_page_table));

        if (verbose) {
                fprintf(fp, "  PTE: %s [machine]\n", 
			mkstring(buf, VADDR_PRLEN, RJUST|LONG_HEX, 
			MKSTR((ulong)machine_page_table)));

                fprintf(fp, "  PTE: %s => %lx\n", 
			mkstring(buf, VADDR_PRLEN, RJUST|LONG_HEX,
                        MKSTR((ulong)pseudo_page_table + 
			PAGEOFFSET(machine_page_table))), machine_pte);
	}

	if (!(machine_pte & (_PAGE_PRESENT | _PAGE_PROTNONE))) {
		if (machine_pte && verbose) {
			fprintf(fp, "\n");
			x86_translate_pte(machine_pte, 0, 0);
		}
		goto no_kpage;
	}

	pseudo_pte = xen_m2p_nonPAE(NONPAE_PAGEBASE(machine_pte));
	pseudo_pte |= PAGEOFFSET(machine_pte);

	if (verbose) {
		fprintf(fp, " PAGE: %s [machine]\n", 
			mkstring(buf, VADDR_PRLEN, RJUST|LONG_HEX, 
			MKSTR(NONPAE_PAGEBASE(machine_pte))));

		fprintf(fp, " PAGE: %s\n\n", 
			mkstring(buf, VADDR_PRLEN, RJUST|LONG_HEX, 
			MKSTR(NONPAE_PAGEBASE(pseudo_pte))));

		x86_translate_pte(pseudo_pte, 0, 0);
	}

	*paddr = NONPAE_PAGEBASE(pseudo_pte) + PAGEOFFSET(kvaddr);

	return TRUE;

no_kpage:
	return FALSE;
}


static int
x86_kvtop_PAE(struct task_context *tc, ulong kvaddr, physaddr_t *paddr, int verbose)
{
	ulonglong *pgd;
        ulonglong page_dir_entry;
        ulonglong page_middle;
        ulonglong page_middle_entry;
        ulonglong page_table;
        ulonglong page_table_entry;
        ulonglong physpage;
	ulonglong ull;
	char buf[BUFSIZE];
        ulong offset;
	

	if (!IS_KVADDR(kvaddr))
		return FALSE;

	if (XEN_HYPER_MODE()) {
		if (DIRECTMAP_VIRT_ADDR(kvaddr)) {
			*paddr = kvaddr - DIRECTMAP_VIRT_START;
			return TRUE;
		}
		if (symbol_exists("idle_pg_table_l3"))
			pgd = (ulonglong *)symbol_value("idle_pg_table_l3");
		else
			pgd = (ulonglong *)symbol_value("idle_pg_table");
	} else {
		if (x86_kvtop_remap(kvaddr, paddr)) {
			if (!verbose)
				return TRUE;
		} else if (!vt->vmalloc_start) {
			*paddr = VTOP(kvaddr);
			return TRUE;
		} else if (!IS_VMALLOC_ADDR(kvaddr)) { 
			*paddr = VTOP(kvaddr);
			if (!verbose)
				return TRUE;
		}

	        if (XEN() && (kt->xen_flags & WRITABLE_PAGE_TABLES))
	       	        return (x86_kvtop_xen_wpt_PAE(tc, kvaddr, paddr, verbose));

		pgd = (ulonglong *)vt->kernel_pgd[0];
	}

	if (verbose) 
		fprintf(fp, "PAGE DIRECTORY: %lx\n", (ulong)pgd);

	FILL_PGD(pgd, KVADDR, PTRS_PER_PGD * sizeof(ulonglong));

	offset = ((kvaddr >> PGDIR_SHIFT) & (PTRS_PER_PGD-1)) * 
		sizeof(ulonglong);

	page_dir_entry = *((ulonglong *)&machdep->pgd[offset]);

	if (verbose)
		fprintf(fp, "  PGD: %s => %llx\n", 
                        mkstring(buf, VADDR_PRLEN, RJUST|LONG_HEX,
                        MKSTR((ulong)pgd + offset)),
                        page_dir_entry);

	if (!(page_dir_entry & _PAGE_PRESENT)) {
		goto no_kpage;
	}

	page_middle = PAE_PAGEBASE(page_dir_entry);

	FILL_PMD_PAE(page_middle, PHYSADDR, PAGESIZE());

	offset = ((kvaddr >> PMD_SHIFT) & (PTRS_PER_PMD-1)) * sizeof(ulonglong);

        page_middle_entry = *((ulonglong *)&machdep->pmd[offset]);

        if (verbose) {
                ull = page_middle + offset;
                fprintf(fp, "  PMD: %s => %llx\n",
                        mkstring(buf, VADDR_PRLEN, RJUST|LONGLONG_HEX,
                        MKSTR(&ull)),
                        page_middle_entry);
	}

        if (!(page_middle_entry & _PAGE_PRESENT)) {
                goto no_kpage;
        }

        if (page_middle_entry & _PAGE_PSE) {
                if (verbose) {
                        ull = PAE_PAGEBASE(page_middle_entry);
                        fprintf(fp, " PAGE: %s  (2MB)\n\n",
                                mkstring(buf, VADDR_PRLEN, RJUST|LONGLONG_HEX,
                                MKSTR(&ull)));
                        x86_translate_pte(0, 0, page_middle_entry);
                }

		physpage = PAE_PAGEBASE(page_middle_entry) +
			(kvaddr & ~_2MB_PAGE_MASK);
                *paddr = physpage;


                return TRUE;
        }

        page_table = PAE_PAGEBASE(page_middle_entry);

        FILL_PTBL_PAE(page_table, PHYSADDR, PAGESIZE());

	offset = ((kvaddr >> PAGESHIFT()) & (PTRS_PER_PTE-1)) * 
		sizeof(ulonglong);

        page_table_entry = *((ulonglong *)&machdep->ptbl[offset]);

        if (verbose) {
                ull = page_table + offset;
                fprintf(fp, "  PTE: %s => %llx\n",
                        mkstring(buf, VADDR_PRLEN, RJUST|LONGLONG_HEX,
                        MKSTR(&ull)), page_table_entry);
	}

        if (!(page_table_entry & (_PAGE_PRESENT | _PAGE_PROTNONE))) {
                if (page_table_entry && verbose) {
                        fprintf(fp, "\n");
                        x86_translate_pte(0, 0, page_table_entry);
                }

                goto no_kpage;
        }

	physpage = PAE_PAGEBASE(page_table_entry) + PAGEOFFSET(kvaddr);

        *paddr = physpage;

        if (verbose) {
		ull = PAE_PAGEBASE(page_table_entry);
                fprintf(fp, " PAGE: %s\n\n",
                        mkstring(buf, VADDR_PRLEN, RJUST|LONGLONG_HEX,
                        MKSTR(&ull)));
                x86_translate_pte(0, 0, page_table_entry);
        }

        return TRUE;

no_kpage:
	return FALSE;
}

static int
x86_kvtop_xen_wpt_PAE(struct task_context *tc, ulong kvaddr, physaddr_t *paddr, int verbose)
{
	ulonglong *pgd;
        ulonglong page_dir_entry;
        ulonglong page_middle, pseudo_page_middle;
        ulonglong page_middle_entry;
        ulonglong page_table, pseudo_page_table;
        ulonglong page_table_entry, pte;
        ulonglong physpage, pseudo_physpage;
        ulonglong ull;
        ulong offset;
	char buf[BUFSIZE];

        pgd = (ulonglong *)vt->kernel_pgd[0];

        if (verbose)
                fprintf(fp, "PAGE DIRECTORY: %lx\n", (ulong)pgd);

        FILL_PGD(pgd, KVADDR, PTRS_PER_PGD * sizeof(ulonglong));

        offset = ((kvaddr >> PGDIR_SHIFT) & (PTRS_PER_PGD-1)) *
                sizeof(ulonglong);

        page_dir_entry = *((ulonglong *)&machdep->pgd[offset]);

        if (verbose)
                fprintf(fp, "  PGD: %s => %llx [machine]\n",
                        mkstring(buf, VADDR_PRLEN, RJUST|LONG_HEX,
                        MKSTR((ulong)pgd + offset)),
                        page_dir_entry);

        if (!(page_dir_entry & _PAGE_PRESENT)) {
                goto no_kpage;
        }

        page_middle = PAE_PAGEBASE(page_dir_entry);
	pseudo_page_middle = xen_m2p(page_middle); 

        if (verbose)
                fprintf(fp, "  PGD: %s => %llx\n",
                        mkstring(buf, VADDR_PRLEN, RJUST|LONG_HEX,
                        MKSTR((ulong)pgd + offset)),
			pseudo_page_middle | PAGEOFFSET(page_dir_entry) |
			(page_dir_entry & _PAGE_NX));

	FILL_PMD_PAE(pseudo_page_middle, PHYSADDR, PAGESIZE());

	offset = ((kvaddr >> PMD_SHIFT) & (PTRS_PER_PMD-1)) * sizeof(ulonglong);

        page_middle_entry = *((ulonglong *)&machdep->pmd[offset]);

        if (verbose) {
                ull = page_middle + offset;
                fprintf(fp, "  PMD: %s => %llx [machine]\n",
                        mkstring(buf, VADDR_PRLEN, RJUST|LONGLONG_HEX,
                        MKSTR(&ull)),
                        page_middle_entry);
	}

        if (!(page_middle_entry & _PAGE_PRESENT)) {
                goto no_kpage;
        }

        if (page_middle_entry & _PAGE_PSE) {
		error(FATAL, "_PAGE_PSE in an mfn not supported\n");  /* XXX */
                if (verbose) {
                        ull = PAE_PAGEBASE(page_middle_entry);
                        fprintf(fp, " PAGE: %s  (2MB)\n\n",
                                mkstring(buf, VADDR_PRLEN, RJUST|LONGLONG_HEX,
                                MKSTR(&ull)));
                        x86_translate_pte(0, 0, page_middle_entry);
                }

		physpage = PAE_PAGEBASE(page_middle_entry) +
			(kvaddr & ~_2MB_PAGE_MASK);
                *paddr = physpage;


                return TRUE;
        }

        page_table = PAE_PAGEBASE(page_middle_entry);
	pseudo_page_table = xen_m2p(page_table); 

        if (verbose) {
                ull = page_middle + offset;
                fprintf(fp, "  PMD: %s => %llx\n",
                        mkstring(buf, VADDR_PRLEN, RJUST|LONGLONG_HEX,
                        MKSTR(&ull)),
                        pseudo_page_table | PAGEOFFSET(page_middle_entry) | 
			(page_middle_entry & _PAGE_NX));
        }

        FILL_PTBL_PAE(pseudo_page_table, PHYSADDR, PAGESIZE());

	offset = ((kvaddr >> PAGESHIFT()) & (PTRS_PER_PTE-1)) * 
		sizeof(ulonglong);

        page_table_entry = *((ulonglong *)&machdep->ptbl[offset]);

        if (verbose) {
                ull = page_table + offset;
                fprintf(fp, "  PTE: %s => %llx [machine]\n",
                        mkstring(buf, VADDR_PRLEN, RJUST|LONGLONG_HEX,
                        MKSTR(&ull)), page_table_entry);
	}

        if (!(page_table_entry & (_PAGE_PRESENT | _PAGE_PROTNONE))) {
                if (page_table_entry && verbose) {
                        fprintf(fp, "\n");
                        x86_translate_pte(0, 0, page_table_entry);
                }

                goto no_kpage;
        }

	physpage = PAE_PAGEBASE(page_table_entry) + PAGEOFFSET(kvaddr);
	pseudo_physpage = xen_m2p(physpage); 

        if (verbose) {
                ull = page_table + offset;
                fprintf(fp, "  PTE: %s => %llx\n",
                        mkstring(buf, VADDR_PRLEN, RJUST|LONGLONG_HEX,
                        MKSTR(&ull)), 
			pseudo_physpage | PAGEOFFSET(page_table_entry) |
			(page_table_entry & _PAGE_NX));
        }

        *paddr = pseudo_physpage + PAGEOFFSET(kvaddr);

        if (verbose) {
		physpage = PAE_PAGEBASE(physpage);
                fprintf(fp, " PAGE: %s [machine]\n",
                        mkstring(buf, VADDR_PRLEN, RJUST|LONGLONG_HEX,
                        MKSTR(&physpage)));

                fprintf(fp, " PAGE: %s\n\n",
                        mkstring(buf, VADDR_PRLEN, RJUST|LONGLONG_HEX,
                        MKSTR(&pseudo_physpage)));

		pte = pseudo_physpage | PAGEOFFSET(page_table_entry) |
			(page_table_entry & _PAGE_NX);

		x86_translate_pte(0, 0, pte);
        }

        return TRUE;

no_kpage:
	return FALSE;
}

void
x86_clear_machdep_cache(void)
{
        machdep->machspec->last_pmd_read_PAE = 0;
        machdep->machspec->last_ptbl_read_PAE = 0;
}

/*
 *  Get the relevant page directory pointer from a task structure.
 */
static ulong
x86_get_task_pgd(ulong task)
{
	long offset;
	ulong cr3;

	offset = OFFSET_OPTION(task_struct_thread, task_struct_tss);

	if (INVALID_MEMBER(thread_struct_cr3))
		error(FATAL, 
		    "cr3 does not exist in this kernel's thread_struct\n"); 

	offset += OFFSET(thread_struct_cr3);

        readmem(task + offset, KVADDR, &cr3,
                sizeof(ulong), "task thread cr3", FAULT_ON_ERROR);

	return(PTOV(cr3));
}

/*
 *  Calculate and return the speed of the processor.
 */
ulong
x86_processor_speed(void)
{
	unsigned long cpu_hz, cpu_khz;

	if (machdep->mhz)
		return (machdep->mhz);

	if (symbol_exists("cpu_hz")) {
		get_symbol_data("cpu_hz", sizeof(long), &cpu_hz);
		if (cpu_hz)
			return (machdep->mhz = cpu_hz/1000000);
	}
	if (symbol_exists("cpu_khz")) {
		get_symbol_data("cpu_khz", sizeof(long), &cpu_khz);
		if (cpu_khz)
			return(machdep->mhz = cpu_khz/1000);
	}

	return 0;
}

void
x86_dump_machdep_table(ulong arg)
{
        int others;
	ulong xen_wpt;
	char buf[BUFSIZE];
	struct machine_specific *ms;
	int i, max_numnodes;

	switch (arg) {
	default:
		break;
	}

        others = 0;
        fprintf(fp, "              flags: %lx (", machdep->flags);
        if (machdep->flags & KSYMS_START)
                fprintf(fp, "%sKSYMS_START", others++ ? "|" : "");
        if (machdep->flags & PAE)
                fprintf(fp, "%sPAE", others++ ? "|" : "");
        if (machdep->flags & OMIT_FRAME_PTR)
                fprintf(fp, "%sOMIT_FRAME_PTR", others++ ? "|" : "");
        if (machdep->flags & FRAMESIZE_DEBUG)
                fprintf(fp, "%sFRAMESIZE_DEBUG", others++ ? "|" : "");
        fprintf(fp, ")\n");
        fprintf(fp, "             kvbase: %lx\n", machdep->kvbase);
	fprintf(fp, "  identity_map_base: %lx\n", machdep->identity_map_base);
	fprintf(fp, "           pagesize: %d\n", machdep->pagesize);
	fprintf(fp, "          pageshift: %d\n", machdep->pageshift);
	fprintf(fp, "           pagemask: %llx\n", machdep->pagemask);
	fprintf(fp, "         pageoffset: %lx\n", machdep->pageoffset);
	fprintf(fp, "          stacksize: %ld\n", machdep->stacksize);
        fprintf(fp, "                 hz: %d\n", machdep->hz);
        fprintf(fp, "                mhz: %ld\n", machdep->mhz);
        fprintf(fp, "            memsize: %lld (0x%llx)\n", 
		machdep->memsize, machdep->memsize);
	fprintf(fp, "               bits: %d\n", machdep->bits);
	fprintf(fp, "            nr_irqs: %d\n", machdep->nr_irqs);
        fprintf(fp, "      eframe_search: x86_eframe_search()\n");
        fprintf(fp, "         back_trace: x86_back_trace_cmd()\n");
        fprintf(fp, "get_processor_speed: x86_processor_speed()\n");
	xen_wpt = XEN() && (kt->xen_flags & WRITABLE_PAGE_TABLES);
	if (machdep->flags & PAE) {
        	fprintf(fp, "              uvtop: %s()\n", 
			xen_wpt ?  "x86_uvtop_xen_wpt_PAE" : "x86_uvtop_PAE");
        	fprintf(fp, "              kvtop: x86_kvtop_PAE()%s\n",
			xen_wpt ? " -> x86_kvtop_xen_wpt_PAE()" : "");
	} else {
        	fprintf(fp, "              uvtop: %s()\n", 
			xen_wpt ?  "x86_uvtop_xen_wpt" : "x86_uvtop");
        	fprintf(fp, "              kvtop: x86_kvtop()%s\n",
			xen_wpt ? " -> x86_kvtop_xen_wpt()" : "");
	}
        fprintf(fp, "       get_task_pgd: x86_get_task_pgd()\n");
	fprintf(fp, "           dump_irq: generic_dump_irq()\n");
	fprintf(fp, "   get_irq_affinity: generic_get_irq_affinity()\n");
	fprintf(fp, "    show_interrupts: generic_show_interrupts()\n");
	fprintf(fp, "    get_stack_frame: x86_get_stack_frame()\n");
	fprintf(fp, "      get_stackbase: generic_get_stackbase()\n");
	fprintf(fp, "       get_stacktop: generic_get_stacktop()\n");
	fprintf(fp, "      translate_pte: x86_translate_pte()\n");
	fprintf(fp, "        memory_size: x86_memory_size()\n");
	fprintf(fp, "      vmalloc_start: x86_vmalloc_start()\n");
	fprintf(fp, "       is_task_addr: x86_is_task_addr()\n");
	fprintf(fp, "      verify_symbol: x86_verify_symbol()\n");
	fprintf(fp, "         dis_filter: x86_dis_filter()\n");
	fprintf(fp, "           cmd_mach: x86_cmd_mach()\n");
	fprintf(fp, "       get_smp_cpus: x86_get_smp_cpus()\n");
	fprintf(fp, "          is_kvaddr: generic_is_kvaddr()\n");
	fprintf(fp, "          is_uvaddr: %s\n", COMMON_VADDR_SPACE() ?
                        "x86_is_uvaddr()" : "generic_is_uvaddr()");
	fprintf(fp, "       verify_paddr: generic_verify_paddr()\n");
        fprintf(fp, "    init_kernel_pgd: x86_init_kernel_pgd()\n");
	fprintf(fp, "    value_to_symbol: %s\n",
		machdep->value_to_symbol == generic_machdep_value_to_symbol ?
		"generic_machdep_value_to_symbol()" :
		"x86_is_entry_tramp_address()");
	fprintf(fp, "  line_number_hooks: %s\n", machdep->line_number_hooks ? 
		"x86_line_number_hooks" : "(not used)");
	fprintf(fp, "      last_pgd_read: %lx\n", machdep->last_pgd_read);
	fprintf(fp, "      last_pmd_read: %lx\n", machdep->last_pmd_read);
	fprintf(fp, "     last_ptbl_read: %lx\n", machdep->last_ptbl_read);
	fprintf(fp, "                pgd: %lx\n", (ulong)machdep->pgd);
	fprintf(fp, "                pmd: %lx\n", (ulong)machdep->pmd);
	fprintf(fp, "               ptbl: %lx\n", (ulong)machdep->ptbl);
	fprintf(fp, "       ptrs_per_pgd: %d\n", machdep->ptrs_per_pgd);
	fprintf(fp, "  section_size_bits: %ld\n", machdep->section_size_bits);
        fprintf(fp, "   max_physmem_bits: %ld\n", machdep->max_physmem_bits);
        fprintf(fp, "  sections_per_root: %ld\n", machdep->sections_per_root);
	fprintf(fp, " xendump_p2m_create: x86_xendump_p2m_create()\n");
	fprintf(fp, " xendump_p2m_create: %s\n", PVOPS_XEN() ?
		"x86_pvops_xendump_p2m_create()" : "x86_xendump_p2m_create()");
	fprintf(fp, " xendump_panic_task: x86_xendump_panic_task()\n");
	fprintf(fp, "   get_xendump_regs: x86_get_xendump_regs()\n");
	fprintf(fp, "xen_kdump_p2m_create: x86_xen_kdump_p2m_create()\n");
	fprintf(fp, "clear_machdep_cache: x86_clear_machdep_cache()\n");
	fprintf(fp, "   INT_EFRAME_[reg]:\n");
	fprintf(fp, "%s %d\n", 
		mkstring(buf, 21, RJUST, "SS: "), INT_EFRAME_SS);
	fprintf(fp, "%s %d\n", 
		mkstring(buf, 21, RJUST, "ESP: "), INT_EFRAME_ESP);
	fprintf(fp, "%s %d\n", 
		mkstring(buf, 21, RJUST, "EFLAGS: "), INT_EFRAME_EFLAGS);
	fprintf(fp, "%s %d\n", 
		mkstring(buf, 21, RJUST, "CS: "), INT_EFRAME_CS);
	fprintf(fp, "%s %d\n", 
		mkstring(buf, 21, RJUST, "IP: "), INT_EFRAME_EIP);
	fprintf(fp, "%s %d\n", 
		mkstring(buf, 21, RJUST, "ERR: "), INT_EFRAME_ERR);
	fprintf(fp, "%s %d\n", 
		mkstring(buf, 21, RJUST, "ES: "), INT_EFRAME_ES);
	fprintf(fp, "%s %d\n", 
		mkstring(buf, 21, RJUST, "DS: "), INT_EFRAME_DS);
	fprintf(fp, "%s %d\n", 
		mkstring(buf, 21, RJUST, "EAX: "), INT_EFRAME_EAX);
	fprintf(fp, "%s %d\n", 
		mkstring(buf, 21, RJUST, "EBP: "), INT_EFRAME_EBP);
	fprintf(fp, "%s %d\n", 
		mkstring(buf, 21, RJUST, "EDI: "), INT_EFRAME_EDI);
	fprintf(fp, "%s %d\n", 
		mkstring(buf, 21, RJUST, "ESI: "), INT_EFRAME_ESI);
	fprintf(fp, "%s %d\n", 
		mkstring(buf, 21, RJUST, "EDX: "), INT_EFRAME_EDX);
	fprintf(fp, "%s %d\n", 
		mkstring(buf, 21, RJUST, "ECX: "), INT_EFRAME_ECX);
	fprintf(fp, "%s %d\n", 
		mkstring(buf, 21, RJUST, "EBX: "), INT_EFRAME_EBX);
	fprintf(fp, "%s %d\n", 
		mkstring(buf, 21, RJUST, "GS: "), INT_EFRAME_GS);

        fprintf(fp, "           machspec: x86_machine_specific\n");
	fprintf(fp, "                     idt_table: %lx\n",
		(ulong)machdep->machspec->idt_table); 
	fprintf(fp, "             entry_tramp_start: %lx\n",
		machdep->machspec->entry_tramp_start);
	fprintf(fp, "               entry_tramp_end: %lx\n",
		machdep->machspec->entry_tramp_end);
	fprintf(fp, "        entry_tramp_start_phys: %llx\n",
		machdep->machspec->entry_tramp_start_phys);
	fprintf(fp, "             last_pmd_read_PAE: %llx\n",
		machdep->machspec->last_pmd_read_PAE);
	fprintf(fp, "            last_ptbl_read_PAE: %llx\n",
		machdep->machspec->last_ptbl_read_PAE);
	fprintf(fp, "                 page_protnone: %lx\n",
		machdep->machspec->page_protnone);

	ms = machdep->machspec;
	max_numnodes = ms->max_numnodes;
	fprintf(fp, "                  MAX_NUMNODES: ");
	if (max_numnodes < 0) {
		fprintf(fp, "(unused)\n");
	} else {
		fprintf(fp, "%d\n", max_numnodes);

		fprintf(fp, "             remap_start_vaddr:");
		for (i = 0; i < max_numnodes; ++i) {
			if ((i % 8) == 0)
				fprintf(fp, "\n        ");
			fprintf(fp, "%08lx ", ms->remap_start_vaddr[i]);
		}
		fprintf(fp, "\n");

		fprintf(fp, "               remap_end_vaddr:");
		for (i = 0; i < max_numnodes; ++i) {
			if ((i % 8) == 0)
				fprintf(fp, "\n        ");
			fprintf(fp, "%08lx ", ms->remap_end_vaddr[i]);
		}
		fprintf(fp, "\n");

		fprintf(fp, "               remap_start_pfn:");
		for (i = 0; i < max_numnodes; ++i) {
			if ((i % 8) == 0)
				fprintf(fp, "\n        ");
			fprintf(fp, "%08lx ", ms->remap_start_pfn[i]);
		}
		fprintf(fp, "\n");
	}
}

/*
 *  Get a stack frame combination of pc and ra from the most relevent spot.
 */
static void
x86_get_stack_frame(struct bt_info *bt, ulong *pcp, ulong *spp)
{
	if (pcp)  
		*pcp = x86_get_pc(bt);
	if (spp)
		*spp = x86_get_sp(bt);
}

/*
 *  Get the saved PC from a user-space copy of the kernel stack.
 */
static ulong 
x86_get_pc(struct bt_info *bt)
{
	ulong offset;
	ulong eip, inactive_task_frame;

	if (tt->flags & THREAD_INFO) {
		if (VALID_MEMBER(task_struct_thread_eip))
			readmem(bt->task + OFFSET(task_struct_thread_eip), KVADDR,
				&eip, sizeof(void *), 
				"thread_struct eip", FAULT_ON_ERROR);
		else if (VALID_MEMBER(inactive_task_frame_ret_addr)) {
			readmem(bt->task + OFFSET(task_struct_thread_esp), KVADDR,
				&inactive_task_frame, sizeof(void *),
				"task_struct.inactive_task_frame", FAULT_ON_ERROR);
			readmem(inactive_task_frame + OFFSET(inactive_task_frame_ret_addr), 
				KVADDR, &eip, sizeof(void *),
				"inactive_task_frame.ret_addr", FAULT_ON_ERROR);
		} else
			error(FATAL, "cannot determine ip address\n");
		return eip;
	}

	offset = OFFSET_OPTION(task_struct_thread_eip, task_struct_tss_eip);
	
	return GET_STACK_ULONG(offset);
}

/*
 *  Get the saved SP from a user-space copy of the kernel stack if it
 *  cannot be found in the panic_ksp array.
 */
static ulong 
x86_get_sp(struct bt_info *bt)
{
	ulong offset, ksp;

	if (get_panic_ksp(bt, &ksp))
		return ksp;

	if (tt->flags & THREAD_INFO) {
                readmem(bt->task + OFFSET(task_struct_thread_esp), KVADDR,
                        &ksp, sizeof(void *),
                        "thread_struct esp", FAULT_ON_ERROR);
		if (VALID_MEMBER(inactive_task_frame_ret_addr))
			ksp += OFFSET(inactive_task_frame_ret_addr);
                return ksp;
	} 

	offset = OFFSET_OPTION(task_struct_thread_esp, task_struct_tss_esp);

	return GET_STACK_ULONG(offset);
}


/*
 *  Translate a PTE, returning TRUE if the page is _PAGE_PRESENT.
 *  If a physaddr pointer is passed in, don't print anything.
 */
static int
x86_translate_pte(ulong pte, void *physaddr, ulonglong pae_pte)
{
	int c, len1, len2, len3, others, page_present;
	char buf[BUFSIZE];
	char buf2[BUFSIZE];
	char buf3[BUFSIZE];
	char ptebuf[BUFSIZE];
	char physbuf[BUFSIZE];
	char *arglist[MAXARGS];
	ulonglong paddr;
	int nx_bit_set;

	nx_bit_set = FALSE;

	if (machdep->flags & PAE) {
        	paddr = PAE_PAGEBASE(pae_pte);
		sprintf(ptebuf, "%llx", pae_pte);
		if (pae_pte & _PAGE_NX)
			nx_bit_set = TRUE;
		pte = (ulong)pae_pte;
	} else { 
        	paddr = NONPAE_PAGEBASE(pte);
		sprintf(ptebuf, "%lx", pte);
	}

	page_present = (pte & (_PAGE_PRESENT|_PAGE_PROTNONE));

	if (physaddr) {
		if (machdep->flags & PAE) 
			*((ulonglong *)physaddr) = paddr;
		else
			*((ulong *)physaddr) = (ulong)paddr;
		return page_present;
	}

	len1 = MAX(strlen(ptebuf), strlen("PTE"));
	fprintf(fp, "%s  ", mkstring(buf, len1, CENTER|LJUST, "PTE"));

	if (!page_present && pte) {
		swap_location(machdep->flags & PAE ? pae_pte : pte, buf);
		if ((c = parse_line(buf, arglist)) != 3)
			error(FATAL, "cannot determine swap location\n");

		len2 = MAX(strlen(arglist[0]), strlen("SWAP"));
		len3 = MAX(strlen(arglist[2]), strlen("OFFSET"));

		fprintf(fp, "%s  %s\n", 
			mkstring(buf2, len2, CENTER|LJUST, "SWAP"),
			mkstring(buf3, len3, CENTER|LJUST, "OFFSET"));

		strcpy(buf2, arglist[0]);
		strcpy(buf3, arglist[2]);
		fprintf(fp, "%s  %s  %s\n",
                	mkstring(ptebuf, len1, CENTER|RJUST, NULL),
                	mkstring(buf2, len2, CENTER|RJUST, NULL),
                	mkstring(buf3, len3, CENTER|RJUST, NULL));

		return page_present;
	}

	sprintf(physbuf, "%llx", paddr);
	len2 = MAX(strlen(physbuf), strlen("PHYSICAL"));
	fprintf(fp, "%s  ", mkstring(buf, len2, CENTER|LJUST, "PHYSICAL"));

	fprintf(fp, "FLAGS\n");

	fprintf(fp, "%s  %s  ",  
		mkstring(ptebuf, len1, CENTER|RJUST, NULL),
		mkstring(physbuf, len2, CENTER|RJUST, NULL)); 
	fprintf(fp, "(");
	others = 0;

	if (pte) {
		if (pte & _PAGE_PRESENT)
			fprintf(fp, "%sPRESENT", others++ ? "|" : "");
		if (pte & _PAGE_RW)
			fprintf(fp, "%sRW", others++ ? "|" : "");
		if (pte & _PAGE_USER)
			fprintf(fp, "%sUSER", others++ ? "|" : "");
		if (pte & _PAGE_PWT)
			fprintf(fp, "%sPWT", others++ ? "|" : "");
		if (pte & _PAGE_PCD)
			fprintf(fp, "%sPCD", others++ ? "|" : "");
		if (pte & _PAGE_ACCESSED)
			fprintf(fp, "%sACCESSED", others++ ? "|" : "");
		if (pte & _PAGE_DIRTY)
			fprintf(fp, "%sDIRTY", others++ ? "|" : "");
		if ((pte & _PAGE_PSE) && (pte && _PAGE_PRESENT))
			fprintf(fp, "%sPSE", others++ ? "|" : "");
		if (pte & _PAGE_GLOBAL)
			fprintf(fp, "%sGLOBAL", others++ ? "|" : "");
		if (pte & _PAGE_PROTNONE && !(pte && _PAGE_PRESENT))
			fprintf(fp, "%sPROTNONE", others++ ? "|" : "");
		if (nx_bit_set)
			fprintf(fp, "%sNX", others++ ? "|" : "");
	} else { 
		fprintf(fp, "no mapping");
	}

	fprintf(fp, ")\n");

	return page_present;
}


/*
 *  For the time being, walk through the kernel page directory looking
 *  for the 4MB PTEs.  Zones might make this common code in the future.
 */

static uint64_t
x86_memory_size(void)
{
	int i, j;
        ulong *pp;
        ulong kpgd[PTRS_PER_PGD];
        uint64_t vm_total;
        uint64_t pgd_total;

	if (machdep->memsize)
		return machdep->memsize;

	if (!(machdep->flags & PAE)) {	
	        readmem(vt->kernel_pgd[0], KVADDR, kpgd, 
		    sizeof(ulong) * PTRS_PER_PGD,
	            "kernel page directory", FAULT_ON_ERROR);
	
	        for (i = j = 0, pp = &kpgd[0]; i < PTRS_PER_PGD; i++, pp++) {
	                if ((*pp & (_PAGE_PRESENT|_PAGE_4M)) ==
	                    (_PAGE_PRESENT|_PAGE_4M) ) {
	                        j++;
	                }
	        }
	        pgd_total = (uint64_t)j * (uint64_t)(MEGABYTES(4));
	} else
		pgd_total = 0;

       /*
	*  Use the memory node data (or its equivalent) if it's larger than
        *  the page directory total.
        */
	vm_total = total_node_memory();

	machdep->memsize = MAX(pgd_total, vm_total);

	return (machdep->memsize);
}

/*
 *  Determine where vmalloc'd memory starts.
 */
static ulong
x86_vmalloc_start(void)
{
	return (first_vmalloc_address());
}


/*
 *  Do the work for cmd_irq() -d option.
 */
void
x86_display_idt_table(void)
{
	int i;
	ulong *ip;
	char buf[BUFSIZE];

        ip = read_idt_table(READ_IDT_RUNTIME);

	for (i = 0; i < 256; i++, ip += 2) { 
		if (i < 10)
			fprintf(fp, "  ");
		else if (i < 100)
			fprintf(fp, " ");
		fprintf(fp, "[%d] %s\n", 
			i, extract_idt_function(ip, buf, NULL));
	}
}

/*
 *  Extract the function name out of the IDT entry.
 */
static char *
extract_idt_function(ulong *ip, char *buf, ulong *retaddr)
{
	ulong i1, i2, addr;
	char locbuf[BUFSIZE];
	physaddr_t phys;

	if (buf)
		BZERO(buf, BUFSIZE);

	i1 = *ip;
	i2 = *(ip+1);

	i1 &= 0x0000ffff;
	i2 &= 0xffff0000;

	addr = i1 | i2;
	if (retaddr)
		*retaddr = addr;

	if (!buf)
		return NULL;

	value_to_symstr(addr, locbuf, 0);
	if (strlen(locbuf))
		sprintf(buf, "%s", locbuf);
	else {
		sprintf(buf, "%08lx", addr);
		if (kvtop(NULL, addr, &phys, 0)) {
			addr = machdep->kvbase + (ulong)phys;
			if (value_to_symstr(addr, locbuf, 0)) {
				strcat(buf, "  <");
				strcat(buf, locbuf);
				strcat(buf, ">");
			}
		}
	}

	return buf;
}

/*
 *  Read the IDT table into a (hopefully) malloc'd buffer.
 */
static ulong *
read_idt_table(int flag)
{
	ulong *idt, addr, offset;
	physaddr_t phys;
	long desc_struct_size;
	struct syment *sp;
	struct machine_specific *ms;

	idt = NULL;
	ms = machdep->machspec;

	if (ms->idt_table)
		return ms->idt_table;

	desc_struct_size = SIZE(desc_struct) * 256;

	switch (flag)
	{
	case READ_IDT_INIT:
		if (!symbol_exists("idt_table"))
			return NULL;

       		if (!(idt = (ulong *)malloc(desc_struct_size))) {
			error(WARNING, "cannot malloc idt_table\n\n");
			return NULL;
		}

		if (!readmem(symbol_value("idt_table"), KVADDR, idt,
                    desc_struct_size, "idt_table", RETURN_ON_ERROR)) {
			error(WARNING, "cannot read idt_table\n\n");
			return NULL;
		}

               	ms->idt_table = idt;

		addr = 0;
		extract_idt_function(idt, NULL, &addr);

		if (addr) { 
			if (symbol_exists("__entry_tramp_start") &&
			    symbol_exists("__entry_tramp_end") &&
			    symbol_exists("__start___entry_text")) {
				ms->entry_tramp_start = 
					symbol_value("__start___entry_text");
				ms->entry_tramp_end = ms->entry_tramp_start +
					(symbol_value("__entry_tramp_end") -
					symbol_value("__entry_tramp_start"));
				ms->entry_tramp_start_phys = 0;
				machdep->value_to_symbol =
					x86_is_entry_tramp_address;
			} else if (!(sp = value_search(addr, &offset))) {
				addr = VIRTPAGEBASE(addr);
				if (kvtop(NULL, addr, &phys, 0) &&
				    (sp = value_search(PTOV(phys), &offset)) &&
				    STREQ(sp->name, "entry_tramp_start")) {
					ms->entry_tramp_start = 
						addr;
					ms->entry_tramp_start_phys = phys;
					ms->entry_tramp_end = addr + 
				 	    (symbol_value("entry_tramp_end") -
					    symbol_value("entry_tramp_start")); 
					machdep->value_to_symbol =
						x86_is_entry_tramp_address;
				}
			} 
		}
		break;

        case READ_IDT_RUNTIME:
		if (!symbol_exists("idt_table"))
			error(FATAL, 
			    "idt_table does not exist on this architecture\n");

		idt = (ulong *)GETBUF(desc_struct_size);
                readmem(symbol_value("idt_table"), KVADDR, idt,
                        desc_struct_size, "idt_table", FAULT_ON_ERROR);
                break;
	}

	return idt;
}

/* 
 *  If the address fits in the entry_tramp_start page, find the syment
 *  associated with it.
 */
struct syment *
x86_is_entry_tramp_address(ulong vaddr, ulong *retoffset)
{
	struct syment *sp;
	struct machine_specific *ms;
	ulong addr, offset;

	ms = machdep->machspec;

	if (!ms->entry_tramp_start ||
	    !((vaddr >= ms->entry_tramp_start) &&
	    (vaddr <= ms->entry_tramp_end))) 
		return NULL;

	/*
	 *  Check new vs. old style handling of entry_tramp addresses:
	 *
	 *   - The old way requires creation of the real symbol address from
	 *     the entry_tramp address passed in.
	 *   - The new way just uses the absolute (A) symbols that are built 
         *     in using the entry_tramp addresses, w/no phys address required.
	 */
	if (ms->entry_tramp_start_phys)  /* old */
		addr = machdep->kvbase + (ulong)ms->entry_tramp_start_phys + 
			PAGEOFFSET(vaddr);
	else                             /* new */
		addr = vaddr;

	if ((sp = value_search_base_kernel(addr, &offset))) {
		if (retoffset)
			*retoffset = offset;
		if (CRASHDEBUG(4))
  			console("x86_is_entry_tramp_address: %lx: %s %lx+%ld\n",
				vaddr, sp->name, sp->value, offset); 
		if (STREQ(sp->name, "entry_tramp_start"))
			sp++;
	}

	return sp;
}


/*
 *  X86 tasks are all stacksize-aligned, except when split from the stack.
 */
static int
x86_is_task_addr(ulong task)
{
	if (tt->flags & THREAD_INFO)
		return IS_KVADDR(task);
	else
		return (IS_KVADDR(task) && (ALIGNED_STACK_OFFSET(task) == 0));
}


/*
 *  Keep or reject a symbol from the namelist.
 */
static int
x86_verify_symbol(const char *name, ulong value, char type)
{
	if (XEN_HYPER_MODE() && STREQ(name, "__per_cpu_shift"))
		return TRUE;

	if (CRASHDEBUG(8) && name && strlen(name))
		fprintf(fp, "%08lx %s\n", value, name);

	if (STREQ(name, "_text") || STREQ(name, "_stext"))
		machdep->flags |= KSYMS_START;

	if (!name || !strlen(name) || !(machdep->flags & KSYMS_START))
		return FALSE;

	if ((type == 'A') && STRNEQ(name, "__crc_"))
		return FALSE;

        if (STREQ(name, "Letext") || STREQ(name, "gcc2_compiled."))
		return FALSE;

	return TRUE;
}

/*
 *  Filter disassembly output if the output radix is not gdb's default 10
 */
static int 
x86_dis_filter(ulong vaddr, char *inbuf, unsigned int output_radix)
{
        char buf1[BUFSIZE];
        char buf2[BUFSIZE];
        char *colon, *p1;
        int argc;
        char *argv[MAXARGS];
        ulong value;

	if (!inbuf) 
		return TRUE;
/*
 *  For some reason gdb can go off into the weeds translating text addresses,
 *  (on alpha -- not necessarily seen on x86) so this routine both fixes the 
 *  references as well as imposing the current output radix on the translations.
 */
	if (CRASHDEBUG(1))
		console("IN: %s", inbuf);

	colon = (inbuf[0] != ' ') ? strstr(inbuf, ":") : NULL;

	if (colon) {
		sprintf(buf1, "0x%lx <%s>", vaddr,
			value_to_symstr(vaddr, buf2, output_radix));
		sprintf(buf2, "%s%s", buf1, colon);
		strcpy(inbuf, buf2);
	}

	strcpy(buf1, inbuf);
	argc = parse_line(buf1, argv);

	if ((FIRSTCHAR(argv[argc-1]) == '<') && 
	    (LASTCHAR(argv[argc-1]) == '>')) {
		p1 = rindex(inbuf, '<');
		while ((p1 > inbuf) && !STRNEQ(p1, " 0x")) 
			p1--;

		if (!STRNEQ(p1, " 0x"))
			return FALSE;
		p1++;

		if (!extract_hex(p1, &value, NULLCHAR, TRUE))
			return FALSE;

		sprintf(buf1, "0x%lx <%s>\n", value,	
			value_to_symstr(value, buf2, output_radix));

		sprintf(p1, "%s", buf1);
	} else if (STREQ(argv[argc-2], "call") && 
	    hexadecimal(argv[argc-1], 0)) {
		/* 
		 *  Update module code of the form:
		 *
		 *    call   0xe081e1e0
		 *
		 *  to show a bracketed direct call target.
		 */
		p1 = &LASTCHAR(inbuf);

                if (extract_hex(argv[argc-1], &value, NULLCHAR, TRUE)) {
                	sprintf(buf1, " <%s>\n",
				value_to_symstr(value, buf2,
                                output_radix));
                        if (IS_MODULE_VADDR(value) &&
                            !strstr(buf2, "+"))
                                sprintf(p1, "%s", buf1);
		}
	} 
	else if (STREQ(argv[2], "ud2a"))
		pc->curcmd_flags |= UD2A_INSTRUCTION;
	else if (STREQ(argv[2], "(bad)"))
		pc->curcmd_flags |= BAD_INSTRUCTION;

	if (CRASHDEBUG(1))
		console("    %s", inbuf);

	return TRUE;
}


/*
 *   Override smp_num_cpus if possible and necessary.
 */
int
x86_get_smp_cpus(void)
{
	int count, cpucount;

	if ((count = get_cpus_online()) == 0) {
		count = kt->cpus;

		if (symbol_exists("cpucount")) {
			get_symbol_data("cpucount", sizeof(int), &cpucount);
			cpucount++;
			count = MAX(cpucount, kt->cpus);
		} 
	}

	if (XEN() && (count == 1) && symbol_exists("cpu_present_map")) {
        	ulong cpu_present_map;

        	get_symbol_data("cpu_present_map", sizeof(ulong), 
			&cpu_present_map);

        	cpucount = count_bits_long(cpu_present_map);
		count = MAX(cpucount, kt->cpus);
	}

	if (KVMDUMP_DUMPFILE() && (count < get_cpus_present()))
		return(get_highest_cpu_present()+1);

	return MAX(count, get_highest_cpu_online()+1);
}


/*
 *  Machine dependent command.
 */
void
x86_cmd_mach(void)
{
        int c, cflag, mflag;
	unsigned int radix;

	cflag = mflag = radix = 0;

        while ((c = getopt(argcnt, args, "cmxd")) != EOF) {
                switch(c)
                {
		case 'c':
			cflag++;
			break;			

                case 'm':
			mflag++;
                        x86_display_memmap();
                        break;

		case 'x':
			if (radix == 10)
				error(FATAL,
					"-d and -x are mutually exclusive\n");
			radix = 16;
			break;

		case 'd':
			if (radix == 16)
				error(FATAL,
					"-d and -x are mutually exclusive\n");
			radix = 10;
		break;

                default:
                        argerrs++;
                        break;
                }
        }

        if (argerrs)
                cmd_usage(pc->curcmd, SYNOPSIS);

	if (cflag)
		x86_display_cpu_data(radix);

	if (!cflag && !mflag)
		x86_display_machine_stats();
}

/*
 *  "mach" command output.
 */
static void
x86_display_machine_stats(void)
{
	int c;
        struct new_utsname *uts;
	char buf[BUFSIZE];
	ulong mhz;

        uts = &kt->utsname;

        fprintf(fp, "       MACHINE TYPE: %s\n", uts->machine);
        fprintf(fp, "        MEMORY SIZE: %s\n", get_memory_size(buf));
	fprintf(fp, "               CPUS: %d\n", kt->cpus);
	if (!STREQ(kt->hypervisor, "(undetermined)") &&
	    !STREQ(kt->hypervisor, "bare hardware"))
		fprintf(fp, "         HYPERVISOR: %s\n",  kt->hypervisor);
	fprintf(fp, "    PROCESSOR SPEED: ");
	if ((mhz = machdep->processor_speed())) 
		fprintf(fp, "%ld Mhz\n", mhz);
	else
		fprintf(fp, "(unknown)\n");
	fprintf(fp, "                 HZ: %d\n", machdep->hz);
	fprintf(fp, "          PAGE SIZE: %d\n", PAGESIZE());
//	fprintf(fp, "      L1 CACHE SIZE: %d\n", l1_cache_size());
	fprintf(fp, "KERNEL VIRTUAL BASE: %lx\n", machdep->kvbase);
	fprintf(fp, "KERNEL VMALLOC BASE: %lx\n", vt->vmalloc_start);
	fprintf(fp, "  KERNEL STACK SIZE: %ld\n", STACKSIZE());

	if (tt->flags & IRQSTACKS) {
		fprintf(fp, "HARD IRQ STACK SIZE: %ld\n", STACKSIZE());
		fprintf(fp, "    HARD IRQ STACKS:\n");
	
		for (c = 0; c < kt->cpus; c++) {
			if (!tt->hardirq_ctx[c])
				break;
			sprintf(buf, "CPU %d", c);
			fprintf(fp, "%19s: %lx\n", buf, tt->hardirq_ctx[c]);
		}

		fprintf(fp, "SOFT IRQ STACK SIZE: %ld\n", STACKSIZE());
		fprintf(fp, "    SOFT IRQ STACKS:\n");
		for (c = 0; c < kt->cpus; c++) {
			if (!tt->softirq_ctx)
				break;
			sprintf(buf, "CPU %d", c);
			fprintf(fp, "%19s: %lx\n", buf, tt->softirq_ctx[c]);
		}
	}
}

static void
x86_display_cpu_data(unsigned int radix)
{
	int cpu;
	ulong cpu_data = 0;
	
	if (symbol_exists("cpu_data"))
		cpu_data = symbol_value("cpu_data");
	else if (symbol_exists("boot_cpu_data"))
		cpu_data = symbol_value("boot_cpu_data");

	for (cpu = 0; cpu < kt->cpus; cpu++) {
		fprintf(fp, "%sCPU %d:\n", cpu ? "\n" : "", cpu);
		dump_struct("cpuinfo_x86", cpu_data, radix);	
		cpu_data += SIZE(cpuinfo_x86);
	}
}

static char *e820type[] = {
	"(invalid type)",
	"E820_RAM",
	"E820_RESERVED",
	"E820_ACPI",
	"E820_NVS",
	"E820_UNUSABLE",
};

static void
x86_display_memmap(void)
{
	ulong e820;
	int nr_map, i;
	char *buf, *e820entry_ptr;
	ulonglong addr, size;
	ulong type;

	e820 = symbol_value("e820");
	buf = (char *)GETBUF(SIZE(e820map));

        readmem(e820, KVADDR, &buf[0], SIZE(e820map), 
		"e820map", FAULT_ON_ERROR);

	nr_map = INT(buf + OFFSET(e820map_nr_map));

	fprintf(fp, "      PHYSICAL ADDRESS RANGE         TYPE\n");

	for (i = 0; i < nr_map; i++) {
		e820entry_ptr = buf + sizeof(int) + (SIZE(e820entry) * i);
		addr = ULONGLONG(e820entry_ptr + OFFSET(e820entry_addr));
		size = ULONGLONG(e820entry_ptr + OFFSET(e820entry_size));
		type = ULONG(e820entry_ptr + OFFSET(e820entry_type));
		fprintf(fp, "%016llx - %016llx  ", addr, addr+size);
		if (type >= (sizeof(e820type)/sizeof(char *)))
			fprintf(fp, "type %ld\n", type);
		else
			fprintf(fp, "%s\n", e820type[type]);
	}
}

/*
 *  Check a few functions to determine whether the kernel was built
 *  with the -fomit-frame-pointer flag.
 */
#define PUSH_BP_MOV_ESP_BP 0xe58955
#define PUSH_BP_CLR_EAX_MOV_ESP_BP 0xe589c03155ULL

static int
x86_omit_frame_pointer(void)
{
	ulonglong push_bp_mov_esp_bp;
        int i;
        char *checkfuncs[] = {"sys_open", "sys_fork", "sys_read"};

	if (pc->flags & KERNEL_DEBUG_QUERY)
		return FALSE;

        for (i = 0; i < 2; i++) {
                if (!readmem(symbol_value(checkfuncs[i]), KVADDR,
                    &push_bp_mov_esp_bp, sizeof(ulonglong),
                    "x86_omit_frame_pointer", RETURN_ON_ERROR))
                        return TRUE;
                if (!(((push_bp_mov_esp_bp & 0x0000ffffffULL) == 
		    PUSH_BP_MOV_ESP_BP) ||
                    ((push_bp_mov_esp_bp & 0xffffffffffULL) ==
                    PUSH_BP_CLR_EAX_MOV_ESP_BP)))
                        return TRUE;
        }

	return FALSE;
}

/*
 *  Disassemble an address and determine whether the instruction calls
 *  a function; if so, return a pointer to the name of the called function.
 */
char *
x86_function_called_by(ulong eip)
{
	struct syment *sp;
	char buf[BUFSIZE], *p1, *p2, *funcname;
	ulong value, offset;
	unsigned char byte;

	funcname = NULL;
	
        if (!readmem(eip, KVADDR, &byte, sizeof(unsigned char), "call byte",
            RETURN_ON_ERROR)) 
		return funcname;
        if (byte != 0xe8) 
		return funcname;

        sprintf(buf, "x/i 0x%lx", eip);

        open_tmpfile2();
        if (gdb_pass_through(buf, pc->tmpfile2, GNU_RETURN_ON_ERROR)) {
	        rewind(pc->tmpfile2);
	        while (fgets(buf, BUFSIZE, pc->tmpfile2)) {
			if ((p1 = strstr(buf, "call   "))) {
				p1 += strlen("call   ");
				if ((p2 = strstr(p1, " <"))) {
					p2 += strlen(" <");
					if ((p1 = strstr(p2, ">")))
						*p1 = NULLCHAR;
					if ((sp = symbol_search(p2)))
						funcname = sp->name;
				} else if ((p2 = strstr(p1, "0x"))) {
					if (!extract_hex(strip_linefeeds(p2),
					    &value, NULLCHAR, TRUE))
						continue;
					if ((sp = value_search(value, &offset))
					    && !offset)
						funcname = sp->name;
				} 
			}
	        }
	}
        close_tmpfile2();

	return funcname;
}

struct syment *
x86_text_lock_jmp(ulong eip, ulong *offset)
{
	int i, c;
	char buf1[BUFSIZE];
	char buf2[BUFSIZE];
        char *arglist[MAXARGS];
	struct syment *sp;
	ulong value;
	
        sprintf(buf1, "x/10i 0x%lx", eip);
	buf2[0] = NULLCHAR;
	value = 0;

        open_tmpfile2();
        if (gdb_pass_through(buf1, pc->tmpfile2, GNU_RETURN_ON_ERROR)) {
                rewind(pc->tmpfile2);
                while (fgets(buf1, BUFSIZE, pc->tmpfile2)) {
			if (!(c = parse_line(buf1, arglist)))
				continue;
			for (i = 0; i < c; i++) {
				if (STREQ(arglist[i], "jmp") && ((i+1)<c)) {
					strcpy(buf2, arglist[i+1]);
					goto done;
				}
			}
                }
        }
done:
        close_tmpfile2();

	if (strlen(buf2)) {
		value = htol(buf2, RETURN_ON_ERROR, NULL);
		if (value == BADADDR)
			return NULL;
	}

        return ((sp = value_search(value, offset))); 
}

static void
x86_init_kernel_pgd(void)
{
        int i;
	ulong value = 0;

	if (XEN()) { 
		if (PVOPS_XEN())
     			value = symbol_value("swapper_pg_dir");
		else
			get_symbol_data("swapper_pg_dir", sizeof(ulong), &value);
	} else
     		value = symbol_value("swapper_pg_dir");

       	for (i = 0; i < NR_CPUS; i++)
       		vt->kernel_pgd[i] = value;

}

static ulong
xen_m2p_nonPAE(ulong machine)
{
	ulonglong pseudo;

	pseudo = xen_m2p((ulonglong)machine);

	if (pseudo == XEN_MACHADDR_NOT_FOUND)
		return XEN_MFN_NOT_FOUND;

	return ((ulong)pseudo);
}

#include "netdump.h"
#include "xen_dom0.h"

/*
 *  From the xen vmcore, create an index of mfns for each page that makes 
 *  up the dom0 kernel's complete phys_to_machine_mapping[max_pfn] array.
 */

#define MAX_X86_FRAMES  (16)    
#define MFNS_PER_FRAME  (PAGESIZE()/sizeof(ulong))

static int 
x86_xen_kdump_p2m_create(struct xen_kdump_data *xkd)
{
	int i, j;
	ulong kvaddr;
	ulong *up;
	ulonglong *ulp;
	ulong frames;
	ulong frame_mfn[MAX_X86_FRAMES] = { 0 };
	int mfns[MAX_X86_FRAMES] = { 0 };

	/*
	 *  Temporarily read physical (machine) addresses from vmcore.
	 */ 
	pc->curcmd_flags |= XEN_MACHINE_ADDR;
	if (CRASHDEBUG(1)) 
		fprintf(fp, "readmem (temporary): force XEN_MACHINE_ADDR\n");

	if (xkd->flags & KDUMP_CR3)
		goto use_cr3;

        xkd->p2m_frames = 0;

	if (CRASHDEBUG(1))
		fprintf(fp, "x86_xen_kdump_p2m_create: p2m_mfn: %lx\n",
			xkd->p2m_mfn);

	if (!readmem(PTOB(xkd->p2m_mfn), PHYSADDR, xkd->page, PAGESIZE(), 
	    "xen kdump p2m mfn page", RETURN_ON_ERROR))
		error(FATAL, "cannot read xen kdump p2m mfn page\n");

	if (CRASHDEBUG(1)) {
		up = (ulong *)xkd->page;
		for (i = 0; i < 4; i++) {
                	fprintf(fp, "%08lx: %08lx %08lx %08lx %08lx\n",
                        	(ulong)((i * 4) * sizeof(ulong)),
                        	*up, *(up+1), *(up+2), *(up+3));
                        up += 4;
		}
		fprintf(fp, "\n");
	}

	for (i = 0, up = (ulong *)xkd->page; i < MAX_X86_FRAMES; i++, up++)
		frame_mfn[i] = *up;

	for (i = 0; i < MAX_X86_FRAMES; i++) {
		if (!frame_mfn[i])
			break;

        	if (!readmem(PTOB(frame_mfn[i]), PHYSADDR, xkd->page, 
		    PAGESIZE(), "xen kdump p2m mfn list page", RETURN_ON_ERROR))
                	error(FATAL, "cannot read xen kdump p2m mfn list page\n");

		for (j = 0, up = (ulong *)xkd->page; j < MFNS_PER_FRAME; j++, up++)
			if (*up)
				mfns[i]++;

		xkd->p2m_frames += mfns[i];
		
	        if (CRASHDEBUG(7)) {
	                up = (ulong *)xkd->page;
	                for (j = 0; j < 256; j++) {
	                        fprintf(fp, "%08lx: %08lx %08lx %08lx %08lx\n",
	                                (ulong)((j * 4) * sizeof(ulong)),
	                                *up, *(up+1), *(up+2), *(up+3));
	                        up += 4;
	                }
	        }
	}

        if (CRASHDEBUG(1))
		fprintf(fp, "p2m_frames: %d\n", xkd->p2m_frames);

        if ((xkd->p2m_mfn_frame_list = (ulong *)
	    malloc(xkd->p2m_frames * sizeof(ulong))) == NULL)
                error(FATAL, "cannot malloc p2m_frame_index_list");

	for (i = 0, frames = xkd->p2m_frames; frames; i++) {
        	if (!readmem(PTOB(frame_mfn[i]), PHYSADDR, 
		    &xkd->p2m_mfn_frame_list[i * MFNS_PER_FRAME], 
		    mfns[i] * sizeof(ulong), "xen kdump p2m mfn list page", 
		    RETURN_ON_ERROR))
                	error(FATAL, "cannot read xen kdump p2m mfn list page\n");

		frames -= mfns[i];
	}

        if (CRASHDEBUG(2)) {
                for (i = 0; i < xkd->p2m_frames; i++)
                        fprintf(fp, "%lx ", xkd->p2m_mfn_frame_list[i]);
                fprintf(fp, "\n");
        }

	pc->curcmd_flags &= ~XEN_MACHINE_ADDR;
	if (CRASHDEBUG(1)) 
		fprintf(fp, "readmem (restore): p2m translation\n");

	return TRUE;

use_cr3:
	if (CRASHDEBUG(1))
		fprintf(fp, "x86_xen_kdump_p2m_create: cr3: %lx\n", xkd->cr3);

	if (!readmem(PTOB(xkd->cr3), PHYSADDR, machdep->pgd, PAGESIZE(), 
	    "xen kdump cr3 page", RETURN_ON_ERROR))
		error(FATAL, "cannot read xen kdump cr3 page\n");

	if (CRASHDEBUG(7)) {
		fprintf(fp, "contents of page directory page:\n");	

		if (machdep->flags & PAE) {
			ulp = (ulonglong *)machdep->pgd;
			fprintf(fp, 
			    "%016llx %016llx %016llx %016llx\n",
				*ulp, *(ulp+1), *(ulp+2), *(ulp+3));
		} else {
			up = (ulong *)machdep->pgd;
			for (i = 0; i < 256; i++) {
				fprintf(fp, 
				    "%08lx: %08lx %08lx %08lx %08lx\n", 
					(ulong)((i * 4) * sizeof(ulong)),
					*up, *(up+1), *(up+2), *(up+3));
				up += 4;
			}
		}
	}

	kvaddr = symbol_value("max_pfn");
        if (!x86_xen_kdump_load_page(kvaddr, xkd->page))
                return FALSE;
	up = (ulong *)(xkd->page + PAGEOFFSET(kvaddr));

        xkd->p2m_frames = (*up/(PAGESIZE()/sizeof(ulong))) +
		((*up%(PAGESIZE()/sizeof(ulong))) ? 1 : 0);

        if (CRASHDEBUG(1))
                fprintf(fp, "max_pfn at %lx: %lx (%ld) -> %d p2m_frames\n", 
			kvaddr, *up, *up, xkd->p2m_frames);

        if ((xkd->p2m_mfn_frame_list = (ulong *)
            malloc(xkd->p2m_frames * sizeof(ulong))) == NULL)
                error(FATAL, "cannot malloc p2m_frame_index_list");

        kvaddr = symbol_value("phys_to_machine_mapping");
        if (!x86_xen_kdump_load_page(kvaddr, xkd->page))
                return FALSE;
        up = (ulong *)(xkd->page + PAGEOFFSET(kvaddr));
        kvaddr = *up;
        if (CRASHDEBUG(1))
                fprintf(fp, "phys_to_machine_mapping: %lx\n", kvaddr);

        if (CRASHDEBUG(7)) {
                fprintf(fp, "contents of first phys_to_machine_mapping page:\n");
        	if (!x86_xen_kdump_load_page(kvaddr, xkd->page))
			error(INFO, 
			    "cannot read first phys_to_machine_mapping page\n");

                 up = (ulong *)xkd->page;
                 for (i = 0; i < 256; i++) {
                         fprintf(fp, "%08lx: %08lx %08lx %08lx %08lx\n",
                         	(ulong)((i * 4) * sizeof(ulong)),
                         	*up, *(up+1), *(up+2), *(up+3));
                         up += 4;
                 }
        }

        machdep->last_ptbl_read = BADADDR;
        machdep->last_pmd_read = BADADDR;
        machdep->last_pgd_read = BADADDR;

        for (i = 0; i < xkd->p2m_frames; i++) {
                xkd->p2m_mfn_frame_list[i] = x86_xen_kdump_page_mfn(kvaddr);
                kvaddr += PAGESIZE();
        }

        if (CRASHDEBUG(1)) {
        	for (i = 0; i < xkd->p2m_frames; i++)
			fprintf(fp, "%lx ", xkd->p2m_mfn_frame_list[i]);
		fprintf(fp, "\n");
	}

        machdep->last_ptbl_read = 0;
        machdep->last_pmd_read = 0;
        machdep->last_pgd_read = 0;
	pc->curcmd_flags &= ~XEN_MACHINE_ADDR;
	if (CRASHDEBUG(1)) 
		fprintf(fp, "readmem (restore): p2m translation\n");

	return TRUE;
}

/*
 *  Find the page associate with the kvaddr, and read its contents
 *  into the passed-in buffer.
 */
static char *
x86_xen_kdump_load_page(ulong kvaddr, char *pgbuf)
{
        ulong *entry;
        ulong *up;
        ulong mfn;

        if (machdep->flags & PAE)
                return x86_xen_kdump_load_page_PAE(kvaddr, pgbuf);

        up = (ulong *)machdep->pgd;
        entry = up + (kvaddr >> PGDIR_SHIFT);
        mfn = (*entry) >> PAGESHIFT();

	if (!readmem(PTOB(mfn), PHYSADDR, pgbuf, PAGESIZE(), 
	    "xen kdump pgd entry", RETURN_ON_ERROR)) {
                error(INFO, "cannot read/find pgd entry from cr3 page\n");
		return NULL;
	}

        up = (ulong *)pgbuf;
        entry = up + ((kvaddr >> 12) & (PTRS_PER_PTE-1));
        mfn = (*entry) >> PAGESHIFT();

	if (!readmem(PTOB(mfn), PHYSADDR, pgbuf, PAGESIZE(), 
	    "xen page table page", RETURN_ON_ERROR)) {
                error(INFO, "cannot read/find page table page\n");
		return NULL;
	}

	return pgbuf;
}

static char *
x86_xen_kdump_load_page_PAE(ulong kvaddr, char *pgbuf)
{
	ulonglong *entry;
	ulonglong *up;
	ulong mfn;

        up = (ulonglong *)machdep->pgd;
        entry = up + (kvaddr >> PGDIR_SHIFT);
        mfn = (ulong)((*entry) >> PAGESHIFT());

	if (!readmem(PTOB(mfn), PHYSADDR, pgbuf, PAGESIZE(), 
	    "xen kdump pgd entry", RETURN_ON_ERROR)) {
                error(INFO, "cannot read/find pgd entry from cr3 page\n");
                return NULL;
        }

        up = (ulonglong *)pgbuf;
        entry = up + ((kvaddr >> PMD_SHIFT) & (PTRS_PER_PMD-1));
        mfn = (ulong)((*entry) >> PAGESHIFT());

	if (!readmem(PTOB(mfn), PHYSADDR, pgbuf, PAGESIZE(), 
	    "xen kdump pmd entry", RETURN_ON_ERROR)) {
                error(INFO, "cannot read/find pmd entry from pgd\n");
                return NULL;
        }

        up = (ulonglong *)pgbuf;
        entry = up + ((kvaddr >> PAGESHIFT()) & (PTRS_PER_PTE-1));
        mfn = (ulong)((*entry) >> PAGESHIFT());

	if (!readmem(PTOB(mfn), PHYSADDR, pgbuf, PAGESIZE(), 
	    "xen kdump page table page", RETURN_ON_ERROR)) {
                error(INFO, "cannot read/find page table page from pmd\n");
                return NULL;
        }

	return pgbuf;
}

/*
 *  Return the mfn value associated with a virtual address.
 */
static ulong 
x86_xen_kdump_page_mfn(ulong kvaddr)
{
        ulong *entry;
        ulong *up;
        ulong mfn;

        if (machdep->flags & PAE)
                return x86_xen_kdump_page_mfn_PAE(kvaddr);

        up = (ulong *)machdep->pgd;
        entry = up + (kvaddr >> PGDIR_SHIFT);
        mfn = (*entry) >> PAGESHIFT();

	if ((mfn != machdep->last_ptbl_read) && 
	    !readmem(PTOB(mfn), PHYSADDR, machdep->ptbl, PAGESIZE(), 
	    "xen kdump pgd entry", RETURN_ON_ERROR))
                error(FATAL, 
		    "cannot read/find pgd entry from cr3 page (mfn: %lx)\n", 
			mfn);
	machdep->last_ptbl_read = mfn;

        up = (ulong *)machdep->ptbl;
        entry = up + ((kvaddr >> 12) & (PTRS_PER_PTE-1));
        mfn = (*entry) >> PAGESHIFT();

	return mfn;
}

static ulong
x86_xen_kdump_page_mfn_PAE(ulong kvaddr)
{
	ulonglong *entry;
	ulonglong *up;
	ulong mfn;

        up = (ulonglong *)machdep->pgd;
        entry = up + (kvaddr >> PGDIR_SHIFT);
        mfn = (ulong)((*entry) >> PAGESHIFT());

	if ((mfn != machdep->last_pmd_read) &&
	    !readmem(PTOB(mfn), PHYSADDR, machdep->pmd, PAGESIZE(), 
	    "xen kdump pgd entry", RETURN_ON_ERROR))
                error(FATAL, 
		    "cannot read/find pgd entry from cr3 page (mfn: %lx)\n",
			mfn);
	machdep->last_pmd_read = mfn;

        up = (ulonglong *)machdep->pmd;
        entry = up + ((kvaddr >> PMD_SHIFT) & (PTRS_PER_PMD-1));
        mfn = (ulong)((*entry) >> PAGESHIFT());

	if ((mfn != machdep->last_ptbl_read) &&
	    !readmem(PTOB(mfn), PHYSADDR, machdep->ptbl, PAGESIZE(), 
	    "xen kdump pmd entry", RETURN_ON_ERROR))
                error(FATAL, 
		    "cannot read/find pmd entry from pgd (mfn: %lx)\n",
			mfn);
	machdep->last_ptbl_read = mfn;

        up = (ulonglong *)machdep->ptbl;
        entry = up + ((kvaddr >> PAGESHIFT()) & (PTRS_PER_PTE-1));
        mfn = (ulong)((*entry) >> PAGESHIFT());

	return mfn;
}

#include "xendump.h"

/*
 *  Create an index of mfns for each page that makes up the
 *  kernel's complete phys_to_machine_mapping[max_pfn] array.
 */
static int 
x86_xendump_p2m_create(struct xendump_data *xd)
{
	int i, idx;
	ulong mfn, kvaddr, ctrlreg[8], ctrlreg_offset;
	ulong *up;
	ulonglong *ulp;
	off_t offset; 

	/*
	 *  Check for pvops Xen kernel before presuming it's HVM.
	 */
	if (symbol_exists("pv_init_ops") && symbol_exists("xen_patch") &&
	    (xd->xc_core.header.xch_magic == XC_CORE_MAGIC))
		return x86_pvops_xendump_p2m_create(xd);

        if (!symbol_exists("phys_to_machine_mapping")) {
                xd->flags |= XC_CORE_NO_P2M;
                return TRUE;
        }

	if ((ctrlreg_offset = MEMBER_OFFSET("vcpu_guest_context", "ctrlreg")) ==
	     INVALID_OFFSET)
		error(FATAL, 
		    "cannot determine vcpu_guest_context.ctrlreg offset\n");
	else if (CRASHDEBUG(1))
		fprintf(xd->ofp, 
		    "MEMBER_OFFSET(vcpu_guest_context, ctrlreg): %ld\n",
			ctrlreg_offset);

	offset = xd->xc_core.header.xch_ctxt_offset +
		(off_t)ctrlreg_offset;

	if (lseek(xd->xfd, offset, SEEK_SET) == -1)
		error(FATAL, "cannot lseek to xch_ctxt_offset\n");

	if (read(xd->xfd, &ctrlreg, sizeof(ctrlreg)) !=
	    sizeof(ctrlreg))
		error(FATAL, "cannot read vcpu_guest_context ctrlreg[8]\n");

	mfn = (ctrlreg[3] >> PAGESHIFT()) | (ctrlreg[3] << (BITS()-PAGESHIFT()));

	for (i = 0; CRASHDEBUG(1) && (i < 8); i++) {
		fprintf(xd->ofp, "ctrlreg[%d]: %lx", i, ctrlreg[i]);
		if (i == 3)
			fprintf(xd->ofp, " -> mfn: %lx", mfn);
		fprintf(xd->ofp, "\n");
	}

	if (!xc_core_mfn_to_page(mfn, machdep->pgd))
		error(FATAL, "cannot read/find cr3 page\n");

	machdep->last_pgd_read = mfn;

	if (CRASHDEBUG(1)) {
		fprintf(xd->ofp, "contents of page directory page:\n");	

		if (machdep->flags & PAE) {
			ulp = (ulonglong *)machdep->pgd;
			fprintf(xd->ofp, 
			    "%016llx %016llx %016llx %016llx\n",
				*ulp, *(ulp+1), *(ulp+2), *(ulp+3));
		} else {
			up = (ulong *)machdep->pgd;
			for (i = 0; i < 256; i++) {
				fprintf(xd->ofp, 
				    "%08lx: %08lx %08lx %08lx %08lx\n", 
					(ulong)((i * 4) * sizeof(ulong)),
					*up, *(up+1), *(up+2), *(up+3));
				up += 4;
			}
		}
	}

	kvaddr = symbol_value("max_pfn");
	if (!x86_xendump_load_page(kvaddr, xd->page))
		return FALSE;
	up = (ulong *)(xd->page + PAGEOFFSET(kvaddr));
	if (CRASHDEBUG(1))
		fprintf(xd->ofp, "max_pfn: %lx\n", *up);

        xd->xc_core.p2m_frames = (*up/(PAGESIZE()/sizeof(ulong))) +
                ((*up%(PAGESIZE()/sizeof(ulong))) ? 1 : 0);

	if ((xd->xc_core.p2m_frame_index_list = (ulong *)
	    malloc(xd->xc_core.p2m_frames * sizeof(int))) == NULL)
        	error(FATAL, "cannot malloc p2m_frame_index_list");

	kvaddr = symbol_value("phys_to_machine_mapping");
	if (!x86_xendump_load_page(kvaddr, xd->page))
		return FALSE;
	up = (ulong *)(xd->page + PAGEOFFSET(kvaddr));
	if (CRASHDEBUG(1))
		fprintf(fp, "phys_to_machine_mapping: %lx\n", *up);

	kvaddr = *up;
	machdep->last_ptbl_read = BADADDR;
	machdep->last_pmd_read = BADADDR;

	for (i = 0; i < xd->xc_core.p2m_frames; i++) {
		if ((idx = x86_xendump_page_index(kvaddr)) == MFN_NOT_FOUND)
			return FALSE;
		xd->xc_core.p2m_frame_index_list[i] = idx; 
		kvaddr += PAGESIZE();
	}

	machdep->last_ptbl_read = 0;
	machdep->last_pmd_read = 0;

	return TRUE;
}

static int 
x86_pvops_xendump_p2m_create(struct xendump_data *xd)
{
	int i;
	ulong mfn, kvaddr, ctrlreg[8], ctrlreg_offset;
	ulong *up;
	ulonglong *ulp;
	off_t offset; 

	if ((ctrlreg_offset = MEMBER_OFFSET("vcpu_guest_context", "ctrlreg")) ==
	     INVALID_OFFSET)
		error(FATAL, 
		    "cannot determine vcpu_guest_context.ctrlreg offset\n");
	else if (CRASHDEBUG(1))
		fprintf(xd->ofp, 
		    "MEMBER_OFFSET(vcpu_guest_context, ctrlreg): %ld\n",
			ctrlreg_offset);

	offset = xd->xc_core.header.xch_ctxt_offset +
		(off_t)ctrlreg_offset;

	if (lseek(xd->xfd, offset, SEEK_SET) == -1)
		error(FATAL, "cannot lseek to xch_ctxt_offset\n");

	if (read(xd->xfd, &ctrlreg, sizeof(ctrlreg)) !=
	    sizeof(ctrlreg))
		error(FATAL, "cannot read vcpu_guest_context ctrlreg[8]\n");

	mfn = (ctrlreg[3] >> PAGESHIFT()) | (ctrlreg[3] << (BITS()-PAGESHIFT()));

	for (i = 0; CRASHDEBUG(1) && (i < 8); i++) {
		fprintf(xd->ofp, "ctrlreg[%d]: %lx", i, ctrlreg[i]);
		if (i == 3)
			fprintf(xd->ofp, " -> mfn: %lx", mfn);
		fprintf(xd->ofp, "\n");
	}

	if (!xc_core_mfn_to_page(mfn, machdep->pgd))
		error(FATAL, "cannot read/find cr3 page\n");

	machdep->last_pgd_read = mfn;

	if (CRASHDEBUG(1)) {
		fprintf(xd->ofp, "contents of page directory page:\n");	

		if (machdep->flags & PAE) {
			ulp = (ulonglong *)machdep->pgd;
			fprintf(xd->ofp, 
			    "%016llx %016llx %016llx %016llx\n",
				*ulp, *(ulp+1), *(ulp+2), *(ulp+3));
		} else {
			up = (ulong *)machdep->pgd;
			for (i = 0; i < 256; i++) {
				fprintf(xd->ofp, 
				    "%08lx: %08lx %08lx %08lx %08lx\n", 
					(ulong)((i * 4) * sizeof(ulong)),
					*up, *(up+1), *(up+2), *(up+3));
				up += 4;
			}
		}
	}

	kvaddr = symbol_value("max_pfn");
	if (!x86_xendump_load_page(kvaddr, xd->page))
		return FALSE;
	up = (ulong *)(xd->page + PAGEOFFSET(kvaddr));
	if (CRASHDEBUG(1))
		fprintf(xd->ofp, "max_pfn: %lx\n", *up);

        xd->xc_core.p2m_frames = (*up/(PAGESIZE()/sizeof(ulong))) +
                ((*up%(PAGESIZE()/sizeof(ulong))) ? 1 : 0);

	if ((xd->xc_core.p2m_frame_index_list = (ulong *)
	    malloc(xd->xc_core.p2m_frames * sizeof(int))) == NULL)
        	error(FATAL, "cannot malloc p2m_frame_index_list");

	if (symbol_exists("p2m_mid_missing"))
		return x86_pvops_xendump_p2m_l3_create(xd);
	else
		return x86_pvops_xendump_p2m_l2_create(xd);
}

static int x86_pvops_xendump_p2m_l2_create(struct xendump_data *xd)
{
	int i, idx, p;
	ulong kvaddr, *up;

	machdep->last_ptbl_read = BADADDR;
	machdep->last_pmd_read = BADADDR;

	kvaddr = symbol_value("p2m_top");

	for (p = 0; p < xd->xc_core.p2m_frames; p += XEN_PFNS_PER_PAGE) {
		if (!x86_xendump_load_page(kvaddr, xd->page))
			return FALSE;

		if (CRASHDEBUG(7))
 			x86_debug_dump_page(xd->ofp, xd->page,
                       		"contents of page:");

		up = (ulong *)(xd->page);

		for (i = 0; i < XEN_PFNS_PER_PAGE; i++, up++) {
			if ((p+i) >= xd->xc_core.p2m_frames)
				break;
			if ((idx = x86_xendump_page_index(*up)) == MFN_NOT_FOUND)
				return FALSE;
			xd->xc_core.p2m_frame_index_list[p+i] = idx;
		}

		kvaddr += PAGESIZE();
	}

	machdep->last_ptbl_read = 0;
	machdep->last_pmd_read = 0;

	return TRUE;
}

static int x86_pvops_xendump_p2m_l3_create(struct xendump_data *xd)
{
	int i, idx, j, p2m_frame, ret = FALSE;
	ulong kvaddr, *p2m_mid, p2m_mid_missing, p2m_missing, *p2m_top;

	p2m_top = NULL;
	machdep->last_ptbl_read = BADADDR;
	machdep->last_pmd_read = BADADDR;

	kvaddr = symbol_value("p2m_missing");

	if (!x86_xendump_load_page(kvaddr, xd->page))
		goto err;

	p2m_missing = *(ulong *)(xd->page + PAGEOFFSET(kvaddr));

	kvaddr = symbol_value("p2m_mid_missing");

	if (!x86_xendump_load_page(kvaddr, xd->page))
		goto err;

	p2m_mid_missing = *(ulong *)(xd->page + PAGEOFFSET(kvaddr));

	kvaddr = symbol_value("p2m_top");

	if (!x86_xendump_load_page(kvaddr, xd->page))
		goto err;

	kvaddr = *(ulong *)(xd->page + PAGEOFFSET(kvaddr));

	if (!x86_xendump_load_page(kvaddr, xd->page))
		goto err;

	if (CRASHDEBUG(7))
		x86_debug_dump_page(xd->ofp, xd->page,
					"contents of p2m_top page:");

	p2m_top = (ulong *)GETBUF(PAGESIZE());

	memcpy(p2m_top, xd->page, PAGESIZE());

	for (i = 0; i < XEN_P2M_TOP_PER_PAGE; ++i) {
		p2m_frame = i * XEN_P2M_MID_PER_PAGE;

		if (p2m_frame >= xd->xc_core.p2m_frames)
			break;

		if (p2m_top[i] == p2m_mid_missing)
			continue;

		if (!x86_xendump_load_page(p2m_top[i], xd->page))
			goto err;

		if (CRASHDEBUG(7))
			x86_debug_dump_page(xd->ofp, xd->page,
						"contents of p2m_mid page:");

		p2m_mid = (ulong *)xd->page;

		for (j = 0; j < XEN_P2M_MID_PER_PAGE; ++j, ++p2m_frame) {
			if (p2m_frame >= xd->xc_core.p2m_frames)
				break;

			if (p2m_mid[j] == p2m_missing)
				continue;

			idx = x86_xendump_page_index(p2m_mid[j]);

			if (idx == MFN_NOT_FOUND)
				goto err;

			xd->xc_core.p2m_frame_index_list[p2m_frame] = idx;
		}
	}

	machdep->last_ptbl_read = 0;
	machdep->last_pmd_read = 0;

	ret = TRUE;

err:
	if (p2m_top)
		FREEBUF(p2m_top);

	return ret;
}

static void
x86_debug_dump_page(FILE *ofp, char *page, char *name)
{
        int i;
        ulong *up;

        fprintf(ofp, "%s\n", name);

        up = (ulong *)page;
        for (i = 0; i < 256; i++) {
                fprintf(ofp, "%016lx: %08lx %08lx %08lx %08lx\n",
                        (ulong)((i * 4) * sizeof(ulong)),
                        *up, *(up+1), *(up+2), *(up+3));
                up += 4;
        }
}

/*
 *  Find the page associate with the kvaddr, and read its contents
 *  into the passed-in buffer.
 */
static char *
x86_xendump_load_page(ulong kvaddr, char *pgbuf)
{
	ulong *entry;
	ulong *up;
	ulong mfn;

	if (machdep->flags & PAE)
		return x86_xendump_load_page_PAE(kvaddr, pgbuf);

        up = (ulong *)machdep->pgd;
        entry = up + (kvaddr >> PGDIR_SHIFT);
        mfn = (*entry) >> PAGESHIFT();

        if (!xc_core_mfn_to_page(mfn, pgbuf)) {
                error(INFO, "cannot read/find pgd entry from cr3 page\n");
		return NULL;
	}

        up = (ulong *)pgbuf;
        entry = up + ((kvaddr >> 12) & (PTRS_PER_PTE-1));
        mfn = (*entry) >> PAGESHIFT();

        if (!xc_core_mfn_to_page(mfn, pgbuf)) {
                error(INFO, "cannot read/find page table page\n");
		return NULL;
	}

	return pgbuf;
}

static char *
x86_xendump_load_page_PAE(ulong kvaddr, char *pgbuf)
{
	ulonglong *entry;
	ulonglong *up;
	ulong mfn;

        up = (ulonglong *)machdep->pgd;
        entry = up + (kvaddr >> PGDIR_SHIFT);
        mfn = (ulong)((*entry) >> PAGESHIFT());

        if (!xc_core_mfn_to_page(mfn, pgbuf)) {
                error(INFO, "cannot read/find pgd entry from cr3 page\n");
                return NULL;
        }

        up = (ulonglong *)pgbuf;
        entry = up + ((kvaddr >> PMD_SHIFT) & (PTRS_PER_PMD-1));
        mfn = (ulong)((*entry) >> PAGESHIFT());

        if (!xc_core_mfn_to_page(mfn, pgbuf)) {
                error(INFO, "cannot read/find pmd entry from pgd\n");
                return NULL;
        }

        up = (ulonglong *)pgbuf;
        entry = up + ((kvaddr >> PAGESHIFT()) & (PTRS_PER_PTE-1));
        mfn = (ulong)((*entry) >> PAGESHIFT());

        if (!xc_core_mfn_to_page(mfn, pgbuf)) {
                error(INFO, "cannot read/find page table page from pmd\n");
                return NULL;
        }

	return pgbuf;
}

/*
 *  Find the dumpfile page index associated with the kvaddr.
 */
static int 
x86_xendump_page_index(ulong kvaddr)
{
	int idx;
        ulong *entry;
        ulong *up;
        ulong mfn;

	if (machdep->flags & PAE)
		return x86_xendump_page_index_PAE(kvaddr);

        up = (ulong *)machdep->pgd;
        entry = up + (kvaddr >> PGDIR_SHIFT);
        mfn = (*entry) >> PAGESHIFT();
	if ((mfn != machdep->last_ptbl_read) && 
            !xc_core_mfn_to_page(mfn, machdep->ptbl)) {
                error(INFO, "cannot read/find pgd entry from cr3 page\n");
		return MFN_NOT_FOUND;
	}
	machdep->last_ptbl_read = mfn;

        up = (ulong *)machdep->ptbl;
        entry = up + ((kvaddr>>12) & (PTRS_PER_PTE-1));
        mfn = (*entry) >> PAGESHIFT();
	if ((idx = xc_core_mfn_to_page_index(mfn)) == MFN_NOT_FOUND)
                error(INFO, "cannot determine page index for %lx\n", 
			kvaddr);

	return idx;
}

static int 
x86_xendump_page_index_PAE(ulong kvaddr)
{
	int idx;
        ulonglong *entry;
        ulonglong *up;
        ulong mfn;

        up = (ulonglong *)machdep->pgd;
        entry = up + (kvaddr >> PGDIR_SHIFT);
        mfn = (ulong)((*entry) >> PAGESHIFT());
	if ((mfn != machdep->last_pmd_read) &&
	    !xc_core_mfn_to_page(mfn, machdep->pmd)) {
                error(INFO, "cannot read/find pgd entry from cr3 page\n");
		return MFN_NOT_FOUND;
	}
	machdep->last_pmd_read = mfn;

        up = (ulonglong *)machdep->pmd;
        entry = up + ((kvaddr >> PMD_SHIFT) & (PTRS_PER_PMD-1));
        mfn = (ulong)((*entry) >> PAGESHIFT());
        if ((mfn != machdep->last_ptbl_read) &&
	    !xc_core_mfn_to_page(mfn, machdep->ptbl)) {
                error(INFO, "cannot read/find pmd entry from pgd\n");
                return MFN_NOT_FOUND;
        }
	machdep->last_ptbl_read = mfn;

        up = (ulonglong *)machdep->ptbl;
        entry = up + ((kvaddr >> PAGESHIFT()) & (PTRS_PER_PTE-1));
        mfn = (ulong)((*entry) >> PAGESHIFT());
	if ((idx = xc_core_mfn_to_page_index(mfn)) == MFN_NOT_FOUND)
                error(INFO, "cannot determine page index for %lx\n", 
			kvaddr);

	return idx;
}

/*
 *  Pull the esp from the cpu_user_regs struct in the header
 *  turn it into a task, and match it with the active_set.
 *  Unfortunately, the registers in the vcpu_guest_context 
 *  are not necessarily those of the panic task, so for now
 *  let get_active_set_panic_task() get the right task.
 */
static ulong 
x86_xendump_panic_task(struct xendump_data *xd)
{
	return NO_TASK;

#ifdef TO_BE_REVISITED
	int i;
	ulong esp;
	off_t offset;
	ulong task;


	if (INVALID_MEMBER(vcpu_guest_context_user_regs) ||
	    INVALID_MEMBER(cpu_user_regs_esp))
		return NO_TASK;

        offset = xd->xc_core.header.xch_ctxt_offset +
                (off_t)OFFSET(vcpu_guest_context_user_regs) +
		(off_t)OFFSET(cpu_user_regs_esp);

        if (lseek(xd->xfd, offset, SEEK_SET) == -1)
		return NO_TASK;

        if (read(xd->xfd, &esp, sizeof(ulong)) != sizeof(ulong))
		return NO_TASK;

        if (IS_KVADDR(esp) && (task = stkptr_to_task(esp))) {

                for (i = 0; i < NR_CPUS; i++) {
                	if (task == tt->active_set[i]) {
                        	if (CRASHDEBUG(0))
                                	error(INFO,
                            "x86_xendump_panic_task: esp: %lx -> task: %lx\n",
                                        	esp, task);
                        	return task;
			}
		}               

               	error(WARNING,
		    "x86_xendump_panic_task: esp: %lx -> task: %lx (not active)\n",
			esp);
        }

	return NO_TASK;
#endif
}

/*
 *  Because of an off-by-one vcpu bug in early xc_domain_dumpcore()
 *  instantiations, the registers in the vcpu_guest_context are not 
 *  necessarily those of the panic task.  If not, the eip/esp will be
 *  in stop_this_cpu, as a result of the IP interrupt in panic(),
 *  but the trace is strange because it comes out of the hypervisor
 *  at least if the vcpu had been idle.
 */
static void 
x86_get_xendump_regs(struct xendump_data *xd, struct bt_info *bt, ulong *eip, ulong *esp)
{
	ulong task, xeip, xesp;
	off_t offset;

        if (INVALID_MEMBER(vcpu_guest_context_user_regs) ||
            INVALID_MEMBER(cpu_user_regs_eip) ||
            INVALID_MEMBER(cpu_user_regs_esp))
                goto generic;

        offset = xd->xc_core.header.xch_ctxt_offset +
                (off_t)OFFSET(vcpu_guest_context_user_regs) +
                (off_t)OFFSET(cpu_user_regs_esp);
        if (lseek(xd->xfd, offset, SEEK_SET) == -1)
                goto generic;
        if (read(xd->xfd, &xesp, sizeof(ulong)) != sizeof(ulong))
                goto generic;

        offset = xd->xc_core.header.xch_ctxt_offset +
                (off_t)OFFSET(vcpu_guest_context_user_regs) +
                (off_t)OFFSET(cpu_user_regs_eip);
        if (lseek(xd->xfd, offset, SEEK_SET) == -1)
                goto generic;
        if (read(xd->xfd, &xeip, sizeof(ulong)) != sizeof(ulong))
                goto generic;

        if (IS_KVADDR(xesp) && (task = stkptr_to_task(xesp)) &&
	    (task == bt->task)) {
		if (CRASHDEBUG(1))
			fprintf(xd->ofp, 
		"hooks from vcpu_guest_context: eip: %lx esp: %lx\n", xeip, xesp);
		*eip = xeip;
		*esp = xesp;
		return;
	}

generic:
	return machdep->get_stack_frame(bt, eip, esp);
}

/* for Xen Hypervisor analysis */

static int
x86_xenhyper_is_kvaddr(ulong addr)
{
	if (machdep->flags & PAE) {
		return (addr >= HYPERVISOR_VIRT_START_PAE);
	}
	return (addr >= HYPERVISOR_VIRT_START);
}

static ulong
x86_get_stackbase_hyper(ulong task)
{
	struct xen_hyper_vcpu_context *vcc;
	int pcpu;
	ulong init_tss;
	ulong esp, base;
	char *buf;

	/* task means vcpu here */
	vcc = xen_hyper_vcpu_to_vcpu_context(task);
	if (!vcc)
		error(FATAL, "invalid vcpu\n");

	pcpu = vcc->processor;
	if (!xen_hyper_test_pcpu_id(pcpu)) {
		error(FATAL, "invalid pcpu number\n");
	}

	if (symbol_exists("init_tss")) {
		init_tss = symbol_value("init_tss");
		init_tss += XEN_HYPER_SIZE(tss_struct) * pcpu;
	} else {
		init_tss = symbol_value("per_cpu__init_tss");
		init_tss = xen_hyper_per_cpu(init_tss, pcpu);
	}
	
	buf = GETBUF(XEN_HYPER_SIZE(tss_struct));
	if (!readmem(init_tss, KVADDR, buf,
			XEN_HYPER_SIZE(tss_struct), "init_tss", RETURN_ON_ERROR)) {
		error(FATAL, "cannot read init_tss.\n");
	}
	esp = ULONG(buf + XEN_HYPER_OFFSET(tss_struct_esp0));
	FREEBUF(buf);
	base = esp & (~(STACKSIZE() - 1));

	return base;
}

static ulong
x86_get_stacktop_hyper(ulong task)
{
	return x86_get_stackbase_hyper(task) + STACKSIZE();
}

static void
x86_get_stack_frame_hyper(struct bt_info *bt, ulong *pcp, ulong *spp)
{
	struct xen_hyper_vcpu_context *vcc;
	int pcpu;
	ulong *regs;
	ulong esp, eip;

	/* task means vcpu here */
	vcc = xen_hyper_vcpu_to_vcpu_context(bt->task);
	if (!vcc)
		error(FATAL, "invalid vcpu\n");

	pcpu = vcc->processor;
	if (!xen_hyper_test_pcpu_id(pcpu)) {
		error(FATAL, "invalid pcpu number\n");
	}

	if (bt->flags & BT_TEXT_SYMBOLS_ALL) {
		if (spp)
			*spp = x86_get_stackbase_hyper(bt->task);
		if (pcp)
			*pcp = 0;
		bt->flags &= ~BT_TEXT_SYMBOLS_ALL;
		return;
	}

	regs = (ulong *)xen_hyper_id_to_dumpinfo_context(pcpu)->pr_reg_ptr;
	esp = XEN_HYPER_X86_NOTE_ESP(regs);
	eip = XEN_HYPER_X86_NOTE_EIP(regs);

	if (spp) {
		if (esp < x86_get_stackbase_hyper(bt->task) ||
			esp >= x86_get_stacktop_hyper(bt->task))
			*spp = x86_get_stackbase_hyper(bt->task);
		else
			*spp = esp;
	}
	if (pcp) {
		if (is_kernel_text(eip))
			*pcp = eip;
		else
			*pcp = 0;
	}
}

static void
x86_init_hyper(int when)
{
	switch (when)
	{
	case PRE_SYMTAB:
		machdep->verify_symbol = x86_verify_symbol;
                if (pc->flags & KERNEL_DEBUG_QUERY)
                        return;
                machdep->pagesize = memory_page_size();
                machdep->pageshift = ffs(machdep->pagesize) - 1;
                machdep->pageoffset = machdep->pagesize - 1;
                machdep->pagemask = ~((ulonglong)machdep->pageoffset);
		machdep->stacksize = machdep->pagesize * 4; /* ODA: magic num */
        	if ((machdep->pgd = (char *)malloc(PAGESIZE())) == NULL)
                	error(FATAL, "cannot malloc pgd space.");
                if ((machdep->pmd = (char *)malloc(PAGESIZE())) == NULL)
                        error(FATAL, "cannot malloc pmd space.");
        	if ((machdep->ptbl = (char *)malloc(PAGESIZE())) == NULL)
                	error(FATAL, "cannot malloc ptbl space.");
		machdep->last_pgd_read = 0;
		machdep->last_pmd_read = 0;
		machdep->last_ptbl_read = 0;
		machdep->machspec = &x86_machine_specific; /* some members used */
		break;

	case PRE_GDB:
		if (symbol_exists("create_pae_xen_mappings") ||
		    symbol_exists("idle_pg_table_l3")) {
                	machdep->flags |= PAE;
			PGDIR_SHIFT = PGDIR_SHIFT_3LEVEL;
			PTRS_PER_PTE = PTRS_PER_PTE_3LEVEL;
			PTRS_PER_PGD = PTRS_PER_PGD_3LEVEL;
                        machdep->kvtop = x86_kvtop_PAE;
			machdep->kvbase = HYPERVISOR_VIRT_START_PAE;
		} else {
			PGDIR_SHIFT = PGDIR_SHIFT_2LEVEL;
                        PTRS_PER_PTE = PTRS_PER_PTE_2LEVEL;
                        PTRS_PER_PGD = PTRS_PER_PGD_2LEVEL;
                	machdep->kvtop = x86_kvtop;
			free(machdep->pmd);
			machdep->pmd = machdep->pgd;   
			machdep->kvbase = HYPERVISOR_VIRT_START;
		}
		machdep->ptrs_per_pgd = PTRS_PER_PGD;
		machdep->identity_map_base = DIRECTMAP_VIRT_START;
                machdep->is_kvaddr = x86_xenhyper_is_kvaddr;
	        machdep->eframe_search = x86_eframe_search;
	        machdep->back_trace = x86_back_trace_cmd;
	        machdep->processor_speed = x86_processor_speed;		/* ODA: check */
		machdep->dump_irq = generic_dump_irq; 			/* ODA: check */
		machdep->get_stack_frame = x86_get_stack_frame_hyper;
		machdep->get_stackbase = x86_get_stackbase_hyper;
		machdep->get_stacktop = x86_get_stacktop_hyper;
		machdep->translate_pte = x86_translate_pte;
		machdep->memory_size = xen_hyper_x86_memory_size;
		machdep->dis_filter = x86_dis_filter;
//		machdep->cmd_mach = x86_cmd_mach;			/* ODA: check */
		machdep->get_smp_cpus = xen_hyper_x86_get_smp_cpus;
//		machdep->line_number_hooks = x86_line_number_hooks;	/* ODA: check */
		machdep->flags |= FRAMESIZE_DEBUG;			/* ODA: check */
		machdep->value_to_symbol = generic_machdep_value_to_symbol;
		machdep->clear_machdep_cache = x86_clear_machdep_cache;

		/* machdep table for Xen Hypervisor */
		xhmachdep->pcpu_init = xen_hyper_x86_pcpu_init;
		break;

	case POST_GDB:
#if 0	/* ODA: need this ? */
		if (x86_omit_frame_pointer()) {
			machdep->flags |= OMIT_FRAME_PTR;
#endif
		XEN_HYPER_STRUCT_SIZE_INIT(cpu_time, "cpu_time");
		XEN_HYPER_STRUCT_SIZE_INIT(cpuinfo_x86, "cpuinfo_x86");
		XEN_HYPER_STRUCT_SIZE_INIT(tss_struct, "tss_struct");
		XEN_HYPER_MEMBER_OFFSET_INIT(tss_struct_esp0, "tss_struct", "esp0");
		XEN_HYPER_MEMBER_OFFSET_INIT(cpu_time_local_tsc_stamp, "cpu_time", "local_tsc_stamp");
		XEN_HYPER_MEMBER_OFFSET_INIT(cpu_time_stime_local_stamp, "cpu_time", "stime_local_stamp");
		XEN_HYPER_MEMBER_OFFSET_INIT(cpu_time_stime_master_stamp, "cpu_time", "stime_master_stamp");
		XEN_HYPER_MEMBER_OFFSET_INIT(cpu_time_tsc_scale, "cpu_time", "tsc_scale");
		XEN_HYPER_MEMBER_OFFSET_INIT(cpu_time_calibration_timer, "cpu_time", "calibration_timer");
		if (symbol_exists("cpu_data")) {
			xht->cpu_data_address = symbol_value("cpu_data");
		}
/* KAK Can this be calculated? */
		if (!machdep->hz) {
			machdep->hz = XEN_HYPER_HZ;
		}
		break;

	case POST_INIT:
		break;
	}
}

#endif /* X86 */
