/*
 * Copyright 1999 Silicon Graphics, Inc. All rights reserved.
 */
#include <lcrash.h>
#include <asm/lc_dis.h>
#include <strings.h>

static int instr_buf_init = 1;
static instr_buf_t instrbuf;
static unsigned char *codeptr;

/* Forward declarations for local functions 
 */
static int seg_prefix(int);
static int op_e(int, int, instr_rec_t *);

static opcode_rec_t op_386[] = {

	/* 0x00 */
	{ "addb", Eb, Gb },	
	{ "addS", Ev, Gv },	
	{ "addb", Gb, Eb },	
	{ "addS", Gv, Ev },	
	{ "addb", AL, Ib },	
	{ "addS", eAX, Iv },	
	{ "pushS", es },		
	{ "popS", es },		

	/* 0x08 */	
	{ "orb", Eb, Gb },	
	{ "orS", Ev, Gv },	
	{ "orb", Gb, Eb },	
	{ "orS", Gv, Ev },	
	{ "orb", AL, Ib },	
	{ "orS", eAX, Iv },	
	{ "pushS", cs },		
	{ "(bad)", BAD },

	/* 0x10 */
	{ "adcb", Eb, Gb },
	{ "adcS", Ev, Gv },
	{ "adcb", Gb, Eb },
	{ "adcS", Gv, Ev },
	{ "adcb", AL, Ib },
	{ "adcS", eAX, Iv },
	{ "pushS", ss },
	{ "popS", ss },

	/* 0x18 */
	{ "sbbb", Eb, Gb },
	{ "sbbS", Ev, Gv },
	{ "sbbb", Gb, Eb },
	{ "sbbS", Gv, Ev },
	{ "sbbb", AL, Ib },
	{ "sbbS", eAX, Iv },
	{ "pushS", ds },
	{ "popS", ds },

	/* 0x20 */
	{ "andb", Eb, Gb },
	{ "andS", Ev, Gv },
	{ "andb", Gb, Eb },
	{ "andS", Gv, Ev },
	{ "andb", AL, Ib },
	{ "andS", eAX, Iv },      
	{ "(bad)", BAD },     /* SEG ES prefix */
	{ "daa", NONE },

	/* 0x28 */
	{ "subb", Eb, Gb },
	{ "subS", Ev, Gv },
	{ "subb", Gb, Eb },
	{ "subS", Gv, Ev },
	{ "subb", AL, Ib },
	{ "subS", eAX, Iv },
	{ "(bad)", BAD },      /* SEG CS prefix */
	{ "das", NONE },

	/* 0x30 */
	{ "xorb", Eb, Gb },
	{ "xorS", Ev, Gv },
	{ "xorb", Gb, Eb },
	{ "xorS", Gv, Ev },
	{ "xorb", AL, Ib },
	{ "xorS", eAX, Iv },
	{ "(bad)", BAD },      /* SEG SS prefix */
	{ "aaa", NONE },

	/* 0x38 */
	{ "cmpb", Eb, Gb },
	{ "cmpS", Ev, Gv },
	{ "cmpb", Gb, Eb },
	{ "cmpS", Gv, Ev },
	{ "cmpb", AL, Ib },
	{ "cmpS", eAX, Iv },
	{ "(bad)", BAD },	/* SEG DS previx */
	{ "aas", NONE },

	/* 0x40 */
	{ "incS", eAX },
	{ "incS", eCX },
	{ "incS", eDX },
	{ "incS", eBX },
	{ "incS", eSP },
	{ "incS", eBP },
	{ "incS", eSI },
	{ "incS", eDI },

	/* 0x48 */
	{ "decS", eAX },
	{ "decS", eCX },
	{ "decS", eDX },
	{ "decS", eBX },
	{ "decS", eSP },
	{ "decS", eBP },
	{ "decS", eSI },
	{ "decS", eDI },

	/* 0x50 */
	{ "pushS", eAX },
	{ "pushS", eCX },
	{ "pushS", eDX },
	{ "pushS", eBX },
	{ "pushS", eSP },
	{ "pushS", eBP },
	{ "pushS", eSI },
	{ "pushS", eDI },

	/* 0x58 */
	{ "popS", eAX },
	{ "popS", eCX },
	{ "popS", eDX },
	{ "popS", eBX },
	{ "popS", eSP },
	{ "popS", eBP },
	{ "popS", eSI },
	{ "popS", eDI },

	/* 0x60 */
	{ "pusha", NONE },
	{ "popa", NONE },
	{ "boundS", Gv, Ma },
	{ "arpl", Ew, Gw },
	{ "(bad)", BAD }, 	/* seg fs */
	{ "(bad)", BAD },	/* seg gs */
	{ "(bad)", BAD },	/* op size prefix */
	{ "(bad)", BAD },	/* adr size prefix */

	/* 0x68 */
	{ "pushS", Iv },         
	{ "imulS", Gv, Ev, Iv },
	{ "pushS", sIb },   /* push of byte really pushes 2 or 4 bytes */
	{ "imulS", Gv, Ev, Ib },
	{ "insb", Yb, indirDX },
	{ "insS", Yv, indirDX },
	{ "outsb", indirDX, Xb },
	{ "outsS", indirDX, Xv },

	/* 0x70 */
	{ "jo", Jb },
	{ "jno", Jb },
	{ "jb", Jb },
	{ "jae", Jb },
	{ "je", Jb },
	{ "jne", Jb },
	{ "jbe", Jb },
	{ "ja", Jb },

	/* 0x78 */
	{ "js", Jb },
	{ "jns", Jb },
	{ "jp", Jb },
	{ "jnp", Jb },
	{ "jl", Jb },
	{ "jnl", Jb },
	{ "jle", Jb },
	{ "jg", Jb },

	/* 0x80 */
	{ GRP1b },
	{ GRP1S },
	{ "(bad)", BAD },
	{ GRP1Ss },
	{ "testb", Eb, Gb },
	{ "testS", Ev, Gv },
	{ "xchgb", Eb, Gb },
	{ "xchgS", Ev, Gv },

	/* 0x88 */
	{ "movb", Eb, Gb },
	{ "movS", Ev, Gv },
	{ "movb", Gb, Eb },
	{ "movS", Gv, Ev },
	{ "movw", Ew, Sw },
	{ "leaS", Gv, M },
	{ "movw", Sw, Ew },
	{ "popS", Ev },

	/* 0x90 */
	{ "nop", NONE },
	{ "xchgS", eCX, eAX },
	{ "xchgS", eDX, eAX },
	{ "xchgS", eBX, eAX },
	{ "xchgS", eSP, eAX },
	{ "xchgS", eBP, eAX },
	{ "xchgS", eSI, eAX },
	{ "xchgS", eDI, eAX },

	/* 0x98 */
	{ "cWtS", NONE },
	{ "cStd", NONE },
	{ "lcall", Ap },
	{ "(bad)", BAD }, 	/* fwait */
	{ "pushf", NONE },
	{ "popf", NONE },
	{ "sahf", NONE },
	{ "lahf", NONE },

	/* 0xa0 */
	{ "movb", AL, Ob },
	{ "movS", eAX, Ov },
	{ "movb", Ob, AL },
	{ "movS", Ov, eAX },
	{ "movsb", Yb, Xb },
	{ "movsS", Yv, Xv },
	{ "cmpsb", Yb, Xb },
	{ "cmpsS", Yv, Xv },

	/* 0xa8 */
	{ "testb", AL, Ib },
	{ "testS", eAX, Iv },
	{ "stosb", Yb, AL },
	{ "stosS", Yv, eAX },
	{ "lodsb", AL, Xb },
	{ "lodsS", eAX, Xv },
	{ "scasb", AL, Yb },
	{ "scasS", eAX, Yv },

	/* 0xb0 */
	{ "movb", AL, Ib },
	{ "movb", CL, Ib },
	{ "movb", DL, Ib },
	{ "movb", BL, Ib },
	{ "movb", AH, Ib },
	{ "movb", CH, Ib },
	{ "movb", DH, Ib },
	{ "movb", BH, Ib },

	/* 0xb8 */
	{ "movS", eAX, Iv },
	{ "movS", eCX, Iv },
	{ "movS", eDX, Iv },
	{ "movS", eBX, Iv },
	{ "movS", eSP, Iv },
	{ "movS", eBP, Iv },
	{ "movS", eSI, Iv },
	{ "movS", eDI, Iv },

	/* 0xc0 */
	{ GRP2b },
	{ GRP2S },
	{ "ret", Iw },
	{ "ret", NONE },
	{ "lesS", Gv, Mp },
	{ "ldsS", Gv, Mp },
	{ "movb", Eb, Ib },
	{ "movS", Ev, Iv },

	/* 0xc8 */
	{ "enter", Iw, Ib },
	{ "leave", NONE },
	{ "lret", Iw },
	{ "lret", NONE },
	{ "int3", NONE },
	{ "int", Ib },
	{ "into", NONE },
	{ "iret", NONE },

	/* 0xd0 */
	{ GRP2b_one },
	{ GRP2S_one },
	{ GRP2b_cl },
	{ GRP2S_cl },
	{ "aam", Ib },
	{ "aad", Ib },
	{ "(bad)", BAD },
	{ "xlat", NONE },

	/* 0xd8 */
	{ FLOAT, NONE },
	{ FLOAT, NONE },
	{ FLOAT, NONE },
	{ FLOAT, NONE },
	{ FLOAT, NONE },
	{ FLOAT, NONE },
	{ FLOAT, NONE },
	{ FLOAT, NONE },

	/* 0xe0 */
	{ "loopne", Jb },
	{ "loope", Jb },
	{ "loop", Jb },
	{ "jCcxz", Jb },
	{ "inb", AL, Ib },
	{ "inS", eAX, Ib },
	{ "outb", Ib, AL },
	{ "outS", Ib, eAX },

	/* 0xe8 */
	{ "call", Av },
	{ "jmp", Jv },
	{ "ljmp", Ap },
	{ "jmp", Jb },
	{ "inb", AL, indirDX },
	{ "inS", eAX, indirDX },
	{ "outb", indirDX, AL },
	{ "outS", indirDX, eAX },

	/* 0xf0 */
	{ "(bad)", BAD },                  /* lock prefix */
	{ "(bad)", BAD },
	{ "(bad)", BAD },                  /* repne */
	{ "(bad)", BAD },                  /* repz */
	{ "hlt", NONE },
	{ "cmc", NONE },
	{ GRP3b },
	{ GRP3S },

	/* 0xf8 */
	{ "clc", NONE },
	{ "stc", NONE },
	{ "cli", NONE },
	{ "sti", NONE },
	{ "cld", NONE },
	{ "std", NONE },
	{ GRP4 },
	{ GRP5 },
};

static opcode_rec_t op_386_twobyte[] = {

	/* 0x00 */
	{ GRP6 },
	{ GRP7 },
	{ "larS", Gv, Ew },
	{ "lslS", Gv, Ew },  
	{ "(bad)", BAD },
	{ "(bad)", BAD },
	{ "clts", NONE },
	{ "(bad)", BAD },

	/* 0x08 */
	{ "invd", NONE },
	{ "wbinvd", NONE },
	{ "(bad)", BAD },
	{ "ud2a", NONE },  
	{ "(bad)", BAD },
	{ "(bad)", BAD },
	{ "(bad)", BAD },
	{ "(bad)", BAD },

	/* 0x10 */
	{ "(bad)", BAD },
	{ "(bad)", BAD },
	{ "(bad)", BAD },
	{ "(bad)", BAD },
	{ "(bad)", BAD },
	{ "(bad)", BAD },
	{ "(bad)", BAD },
	{ "(bad)", BAD },

	/* 0x18 */
	{ "(bad)", BAD },
	{ "(bad)", BAD },
	{ "(bad)", BAD },
	{ "(bad)", BAD },
	{ "(bad)", BAD },
	{ "(bad)", BAD },
	{ "(bad)", BAD },
	{ "(bad)", BAD },

	/* 0x20 */
	/* these are all backward in appendix A of the intel book */
	{ "movl", Rd, Cd },
	{ "movl", Rd, Dd },
	{ "movl", Cd, Rd },
	{ "movl", Dd, Rd },  
	{ "movl", Rd, Td },
	{ "(bad)", BAD },
	{ "movl", Td, Rd },
	{ "(bad)", BAD },

	/* 0x28 */
	{ "(bad)", BAD },
	{ "(bad)", BAD },
	{ "(bad)", BAD },
	{ "(bad)", BAD },
	{ "(bad)", BAD },
	{ "(bad)", BAD },
	{ "(bad)", BAD },
	{ "(bad)", BAD },

	/* 0x30 */
	{ "wrmsr", NONE },  
	{ "rdtsc", NONE },  
	{ "rdmsr", NONE },  
	{ "rdpmc", NONE },  
	{ "(bad)", BAD },
	{ "(bad)", BAD },
	{ "(bad)", BAD },
	{ "(bad)", BAD },

	/* 0x38 */
	{ "(bad)", BAD },
	{ "(bad)", BAD },
	{ "(bad)", BAD },
	{ "(bad)", BAD },
	{ "(bad)", BAD },
	{ "(bad)", BAD },
	{ "(bad)", BAD },
	{ "(bad)", BAD },

	/* 0x40 */
	{ "cmovo", Gv,Ev }, 
	{ "cmovno", Gv,Ev }, 
	{ "cmovb", Gv,Ev }, 
	{ "cmovae", Gv,Ev },
	{ "cmove", Gv,Ev }, 
	{ "cmovne", Gv,Ev }, 
	{ "cmovbe", Gv,Ev }, 
	{ "cmova", Gv,Ev },

	/* 0x48 */
	{ "cmovs", Gv,Ev }, 
	{ "cmovns", Gv,Ev }, 
	{ "cmovp", Gv,Ev }, 
	{ "cmovnp", Gv,Ev },
	{ "cmovl", Gv,Ev }, 
	{ "cmovge", Gv,Ev }, 
	{ "cmovle", Gv,Ev }, 
	{ "cmovg", Gv,Ev },  

	/* 0x50 */
	{ "(bad)", BAD },
	{ "(bad)", BAD },
	{ "(bad)", BAD },
	{ "(bad)", BAD },
	{ "(bad)", BAD },
	{ "(bad)", BAD },
	{ "(bad)", BAD },
	{ "(bad)", BAD },

	/* 0x58 */
	{ "(bad)", BAD },
	{ "(bad)", BAD },
	{ "(bad)", BAD },
	{ "(bad)", BAD },
	{ "(bad)", BAD },
	{ "(bad)", BAD },
	{ "(bad)", BAD },
	{ "(bad)", BAD },

	/* 0x60 */
	{ "punpcklbw", MX, EM },
	{ "punpcklwd", MX, EM },
	{ "punpckldq", MX, EM },
	{ "packsswb", MX, EM },
	{ "pcmpgtb", MX, EM },
	{ "pcmpgtw", MX, EM },
	{ "pcmpgtd", MX, EM },
	{ "packuswb", MX, EM },

	/* 0x68 */
	{ "punpckhbw", MX, EM },
	{ "punpckhwd", MX, EM },
	{ "punpckhdq", MX, EM },
	{ "packssdw", MX, EM },
	{ "(bad)", BAD },
	{ "(bad)", BAD },
	{ "movd", MX, Ev },
	{ "movq", MX, EM },

	/* 0x70 */
	{ "(bad)", BAD },
	{ GRP10 },
	{ GRP11 },
	{ GRP12 },
	{ "pcmpeqb", MX, EM },
	{ "pcmpeqw", MX, EM },
	{ "pcmpeqd", MX, EM },
	{ "emms" , NONE },

	/* 0x78 */
	{ "(bad)", BAD },
	{ "(bad)", BAD },
	{ "(bad)", BAD },
	{ "(bad)", BAD },
	{ "(bad)", BAD },
	{ "(bad)", BAD },
	{ "movd", Ev, MX },
	{ "movq", EM, MX },

	/* 0x80 */
	{ "jo", Jv },
	{ "jno", Jv },
	{ "jb", Jv },
	{ "jae", Jv },  
	{ "je", Jv },
	{ "jne", Jv },
	{ "jbe", Jv },
	{ "ja", Jv },  

	/* 0x88 */
	{ "js", Jv },
	{ "jns", Jv },
	{ "jp", Jv },
	{ "jnp", Jv },  
	{ "jl", Jv },
	{ "jge", Jv },
	{ "jle", Jv },
	{ "jg", Jv },  

	/* 0x90 */
	{ "seto", Eb },
	{ "setno", Eb },
	{ "setb", Eb },
	{ "setae", Eb },
	{ "sete", Eb },
	{ "setne", Eb },
	{ "setbe", Eb },
	{ "seta", Eb },

	/* 0x98 */
	{ "sets", Eb },
	{ "setns", Eb },
	{ "setp", Eb },
	{ "setnp", Eb },
	{ "setl", Eb },
	{ "setge", Eb },
	{ "setle", Eb },
	{ "setg", Eb },  

	/* 0xa0 */
	{ "pushS", fs },
	{ "popS", fs },
	{ "cpuid", NONE },
	{ "btS", Ev, Gv },  
	{ "shldS", Ev, Gv, Ib },
	{ "shldS", Ev, Gv, CL },
	{ "(bad)", BAD },
	{ "(bad)", BAD },

	/* 0xa8 */
	{ "pushS", gs },
	{ "popS", gs },
	{ "rsm", NONE },
	{ "btsS", Ev, Gv },  
	{ "shrdS", Ev, Gv, Ib },
	{ "shrdS", Ev, Gv, CL },
	{ "(bad)", BAD },
	{ "imulS", Gv, Ev },  

	/* 0xb0 */
	{ "cmpxchgb", Eb, Gb },
	{ "cmpxchgS", Ev, Gv },
	{ "lssS", Gv, Mp },	/* 386 lists only Mp */
	{ "btrS", Ev, Gv },  
	{ "lfsS", Gv, Mp },	/* 386 lists only Mp */
	{ "lgsS", Gv, Mp },	/* 386 lists only Mp */
	{ "movzbS", Gv, Eb },
	{ "movzwS", Gv, Ew },  

	/* 0xb8 */
	{ "ud2b", NONE },
	{ "(bad)", BAD },
	{ GRP8 },
	{ "btcS", Ev, Gv },  
	{ "bsfS", Gv, Ev },
	{ "bsrS", Gv, Ev },
	{ "movsbS", Gv, Eb },
	{ "movswS", Gv, Ew },  

	/* 0xc0 */
	{ "xaddb", Eb, Gb },
	{ "xaddS", Ev, Gv },
	{ "(bad)", BAD },
	{ "(bad)", BAD },
	{ "(bad)", BAD },
	{ "(bad)", BAD },
	{ "(bad)", BAD },
	{ GRP9 },  

	/* 0xc8 */
	{ "bswap", eAX },
	{ "bswap", eCX },
	{ "bswap", eDX },
	{ "bswap", eBX },
	{ "bswap", eSP },
	{ "bswap", eBP },
	{ "bswap", eSI },
	{ "bswap", eDI },

	/* 0xd0 */
	{ "(bad)", BAD },
	{ "psrlw", MX, EM },
	{ "psrld", MX, EM },
	{ "psrlq", MX, EM },
	{ "(bad)", BAD },
	{ "pmullw", MX, EM },
	{ "(bad)", BAD },
	{ "(bad)", BAD },

	/* 0xd8 */
	{ "psubusb", MX, EM },
	{ "psubusw", MX, EM },
	{ "(bad)", BAD },
	{ "pand", MX, EM },
	{ "paddusb", MX, EM },
	{ "paddusw", MX, EM },
	{ "(bad)", BAD },
	{ "pandn", MX, EM },

	/* 0xe0 */
	{ "(bad)", BAD },
	{ "psraw", MX, EM },
	{ "psrad", MX, EM },
	{ "(bad)", BAD },
	{ "(bad)", BAD },
	{ "pmulhw", MX, EM },
	{ "(bad)", BAD },
	{ "(bad)", BAD },

	/* 0xe8 */
	{ "psubsb", MX, EM },
	{ "psubsw", MX, EM },
	{ "(bad)", BAD },
	{ "por", MX, EM },
	{ "paddsb", MX, EM },
	{ "paddsw", MX, EM },
	{ "(bad)", BAD },
	{ "pxor", MX, EM },

	/* 0xf0 */
	{ "(bad)", BAD },
	{ "psllw", MX, EM },
	{ "pslld", MX, EM },
	{ "psllq", MX, EM },
	{ "(bad)", BAD },
	{ "pmaddwd", MX, EM },
	{ "(bad)", BAD },
	{ "(bad)", BAD },

	/* 0xf8 */
	{ "psubb", MX, EM },
	{ "psubw", MX, EM },
	{ "psubd", MX, EM },
	{ "(bad)", BAD },
	{ "paddb", MX, EM },
	{ "paddw", MX, EM },
	{ "paddd", MX, EM },
	{ "(bad)", BAD },
};

static opcode_rec_t grps[][8] = {
	/* GRP1b */
	{
		{ "addb", Eb, Ib },
		{ "orb", Eb, Ib },
		{ "adcb", Eb, Ib },
		{ "sbbb", Eb, Ib },
		{ "andb", Eb, Ib },
		{ "subb", Eb, Ib },
		{ "xorb", Eb, Ib },
		{ "cmpb", Eb, Ib }
	},
	/* GRP1S */
	{
		{ "addS", Ev, Iv },
		{ "orS", Ev, Iv },
		{ "adcS", Ev, Iv },
		{ "sbbS", Ev, Iv },
		{ "andS", Ev, Iv },
		{ "subS", Ev, Iv },
		{ "xorS", Ev, Iv },
		{ "cmpS", Ev, Iv }
	},
	/* GRP1Ss */
	{
		{ "addS", Ev, sIb },
		{ "orS", Ev, sIb },
		{ "adcS", Ev, sIb },
		{ "sbbS", Ev, sIb },
		{ "andS", Ev, sIb },
		{ "subS", Ev, sIb },
		{ "xorS", Ev, sIb },
		{ "cmpS", Ev, sIb }
	},
	/* GRP2b */
	{
		{ "rolb", Eb, Ib },
		{ "rorb", Eb, Ib },
		{ "rclb", Eb, Ib },
		{ "rcrb", Eb, Ib },
		{ "shlb", Eb, Ib },
		{ "shrb", Eb, Ib },
		{ "(bad)", BAD },
		{ "sarb", Eb, Ib },
	},
	/* GRP2S */
	{
		{ "rolS", Ev, Ib },
		{ "rorS", Ev, Ib },
		{ "rclS", Ev, Ib },
		{ "rcrS", Ev, Ib },
		{ "shlS", Ev, Ib },
		{ "shrS", Ev, Ib },
		{ "(bad)", BAD },
		{ "sarS", Ev, Ib },
	},
	/* GRP2b_one */
	{
		{ "rolb", Eb },
		{ "rorb", Eb },
		{ "rclb", Eb },
		{ "rcrb", Eb },
		{ "shlb", Eb },
		{ "shrb", Eb },
		{ "(bad)", BAD },
		{ "sarb", Eb },
	},
	/* GRP2S_one */
	{
		{ "rolS", Ev },
		{ "rorS", Ev },
		{ "rclS", Ev },
		{ "rcrS", Ev },
		{ "shlS", Ev },
		{ "shrS", Ev },
		{ "(bad)", BAD },
		{ "sarS", Ev },
	},
	/* GRP2b_cl */
	{
		{ "rolb", Eb, CL },
		{ "rorb", Eb, CL },
		{ "rclb", Eb, CL },
		{ "rcrb", Eb, CL },
		{ "shlb", Eb, CL },
		{ "shrb", Eb, CL },
		{ "(bad)", BAD },
		{ "sarb", Eb, CL },
	},
	/* GRP2S_cl */
	{
		{ "rolS", Ev, CL },
		{ "rorS", Ev, CL },
		{ "rclS", Ev, CL },
		{ "rcrS", Ev, CL },
		{ "shlS", Ev, CL },
		{ "shrS", Ev, CL },
		{ "(bad)", BAD },
		{ "sarS", Ev, CL }
	},
	/* GRP3b */
	{
		{ "testb", Eb, Ib },
		{ "(bad)", Eb },
		{ "notb", Eb },
		{ "negb", Eb },
		{ "mulb", AL, Eb },
		{ "imulb", AL, Eb },
		{ "divb", AL, Eb },
		{ "idivb", AL, Eb }
	},
	/* GRP3S */
	{
		{ "testS", Ev, Iv },
		{ "(bad)", BAD },
		{ "notS", Ev },
		{ "negS", Ev },
		{ "mulS", eAX, Ev },
		{ "imulS", eAX, Ev },
		{ "divS", eAX, Ev },
		{ "idivS", eAX, Ev },
	},
	/* GRP4 */
	{
		{ "incb", Eb },
		{ "decb", Eb },
		{ "(bad)", BAD },
		{ "(bad)", BAD },
		{ "(bad)", BAD },
		{ "(bad)", BAD },
		{ "(bad)", BAD },
		{ "(bad)", BAD },
	},
	/* GRP5 */
	{
		{ "incS", Ev },
		{ "decS", Ev },
		{ "call", indirEv },
		{ "lcall", indirEv },
		{ "jmp", indirEv },
		{ "ljmp", indirEv },
		{ "pushS", Ev },
		{ "(bad)", BAD },
	},
	/* GRP6 */
	{
		{ "sldt", Ew },
		{ "str", Ew },
		{ "lldt", Ew },
		{ "ltr", Ew },
		{ "verr", Ew },
		{ "verw", Ew },
		{ "(bad)", BAD },
		{ "(bad)", BAD }
	},
	/* GRP7 */
	{
		{ "sgdt", Ew },
		{ "sidt", Ew },
		{ "lgdt", Ew },
		{ "lidt", Ew },
		{ "smsw", Ew },
		{ "(bad)", BAD },
		{ "lmsw", Ew },
		{ "invlpg", Ew },
	},
	/* GRP8 */
	{
		{ "(bad)", BAD },
		{ "(bad)", BAD },
		{ "(bad)", BAD },
		{ "(bad)", BAD },
		{ "btS", Ev, Ib },
		{ "btsS", Ev, Ib },
		{ "btrS", Ev, Ib },
		{ "btcS", Ev, Ib },
	},
	/* GRP9 */
	{
		{ "(bad)", BAD },
		{ "cmpxchg8b", Ev },
		{ "(bad)", BAD },
		{ "(bad)", BAD },
		{ "(bad)", BAD },
		{ "(bad)", BAD },
		{ "(bad)", BAD },
		{ "(bad)", BAD },
	},
	/* GRP10 */
	{
		{ "(bad)", BAD },
		{ "(bad)", BAD },
		{ "psrlw", MS, Ib },
		{ "(bad)", BAD },
		{ "psraw", MS, Ib },
		{ "(bad)", BAD },
		{ "psllw", MS, Ib },
		{ "(bad)", BAD },
	},
	/* GRP11 */
	{
		{ "(bad)", BAD },
		{ "(bad)", BAD },
		{ "psrld", MS, Ib },
		{ "(bad)", BAD },
		{ "psrad", MS, Ib },
		{ "(bad)", BAD },
		{ "pslld", MS, Ib },
		{ "(bad)", BAD },
	},
	/* GRP12 */
	{
		{ "(bad)", BAD },
		{ "(bad)", BAD },
		{ "psrlq", MS, Ib },
		{ "(bad)", BAD },
		{ "(bad)", BAD },
		{ "(bad)", BAD },
		{ "psllq", MS, Ib },
		{ "(bad)", BAD },
	}
};

static opcode_rec_t float_grps[][8] = {
	/* d8 */
	{
		{ "fadd",   ST, STi },
		{ "fmul",   ST, STi },
		{ "fcom",   STi },
		{ "fcomp",  STi },
		{ "fsub",   ST, STi },
		{ "fsubr",  ST, STi },
		{ "fdiv",   ST, STi },
		{ "fdivr",  ST, STi },
	},
	/* d9 */
	{
		{ "fld",    STi },
		{ "fxch",   STi },
		{ FGRPd9_2 },
		{ "(bad)" },
		{ FGRPd9_4 },
		{ FGRPd9_5 },
		{ FGRPd9_6 },
		{ FGRPd9_7 },
	},
	/* da */
	{
		{ "fcmovb", ST, STi },
		{ "fcmove", ST, STi },
		{ "fcmovbe",ST, STi },
		{ "fcmovu", ST, STi },
		{ "(bad)" },
		{ FGRPda_5 },
		{ "(bad)" },
		{ "(bad)" },
		},
	/* db */
	{
		{ "fcmovnb",ST, STi },
		{ "fcmovne",ST, STi },
		{ "fcmovnbe",ST, STi },
		{ "fcmovnu",ST, STi },
		{ FGRPdb_4 },
		{ "fucomi", ST, STi },
		{ "fcomi",  ST, STi },
		{ "(bad)" },
	},
	/* dc */
	{
		{ "fadd",   STi, ST },
		{ "fmul",   STi, ST },
		{ "(bad)" },
		{ "(bad)" },
		{ "fsub",   STi, ST },
		{ "fsubr",  STi, ST },
		{ "fdiv",   STi, ST },
		{ "fdivr",  STi, ST },
	},
	/* dd */
	{
		{ "ffree",  STi },
		{ "(bad)" },
		{ "fst",    STi },
		{ "fstp",   STi },
		{ "fucom",  STi },
		{ "fucomp", STi },
		{ "(bad)" },
		{ "(bad)" },
	},
	/* de */
	{
		{ "faddp",  STi, ST },
		{ "fmulp",  STi, ST },
		{ "(bad)" },
		{ FGRPde_3 },
		{ "fsubp",  STi, ST },
		{ "fsubrp", STi, ST },
		{ "fdivp",  STi, ST },
		{ "fdivrp", STi, ST },
	},
	/* df */
	{
		{ "(bad)" },
		{ "(bad)" },
		{ "(bad)" },
		{ "(bad)" },
		{ FGRPdf_4 },
		{ "fucomip",ST, STi },
		{ "fcomip", ST, STi },
		{ "(bad)" },
	},
};

static char *fgrps[][8] = {
	/* d9_2  0 */
	{
	"fnop","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)",
	},
	/* d9_4  1 */
	{
	"fchs","fabs","(bad)","(bad)","ftst","fxam","(bad)","(bad)",
	},
	/* d9_5  2 */
	{
	"fld1","fldl2t","fldl2e","fldpi","fldlg2","fldln2","fldz","(bad)",
	},
	/* d9_6  3 */
	{
	"f2xm1","fyl2x","fptan","fpatan","fxtract","fprem1","fdecstp","fincstp",
	},
	/* d9_7  4 */
	{
	"fprem","fyl2xp1","fsqrt","fsincos","frndint","fscale","fsin","fcos",
	},
	/* da_5  5 */
	{
	"(bad)","fucompp","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)",
	},
	/* db_4  6 */
	{
	"feni(287 only)","fdisi(287 only)","fNclex","fNinit",
	"fNsetpm(287 only)","(bad)","(bad)","(bad)",
	},
	/* de_3  7 */
	{
	"(bad)","fcompp","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)",
	},
	/* df_4  8 */
	{
	"fNstsw","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)",
	},
};

static char *float_mem[] = {
	/* 0xd8 */
	"fadds","fmuls","fcoms","fcomps","fsubs","fsubrs","fdivs","fdivrs",
	/* 0xd9 */
	"flds","(bad)","fsts","fstps","fldenv","fldcw","fNstenv","fNstcw",
	/* 0xda */
	"fiaddl","fimull","ficoml","ficompl","fisubl","fisubrl","fidivl",
	"fidivrl",
	/* 0xdb */
	"fildl","(bad)","fistl","fistpl","(bad)","fldt","(bad)","fstpt",
	/* 0xdc */
	"faddl","fmull","fcoml","fcompl","fsubl","fsubrl","fdivl","fdivrl",
	/* 0xdd */
	"fldl","(bad)","fstl","fstpl","frstor","(bad)","fNsave","fNstsw",
	/* 0xde */
	"fiadd","fimul","ficom","ficomp","fisub","fisubr","fidiv","fidivr",
	/* 0xdf */
	"fild","(bad)","fist","fistp","fbld","fildll","fbstp","fistpll",
};

static const unsigned char onebyte_has_modrm[256] = {
	/* 00 */ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,
	/* 10 */ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,
	/* 20 */ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,
	/* 30 */ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,
	/* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
	/* 50 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
	/* 60 */ 0,0,1,1,0,0,0,0,0,1,0,1,0,0,0,0,
	/* 70 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
	/* 80 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
	/* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
	/* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
	/* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
	/* c0 */ 1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0,
	/* d0 */ 1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,
	/* e0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
	/* f0 */ 0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1
};

static const unsigned char twobyte_has_modrm[256] = {
	/* 00 */ 1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0, /* 0f */
	/* 10 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1f */
	/* 20 */ 1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0, /* 2f */
	/* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */
	/* 40 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 4f */
	/* 50 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 5f */
	/* 60 */ 1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1, /* 6f */
	/* 70 */ 0,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1, /* 7f */
	/* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */
	/* 90 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 9f */
	/* a0 */ 0,0,0,1,1,1,1,1,0,0,0,1,1,1,1,1, /* af */
	/* b0 */ 1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1, /* bf */
	/* c0 */ 1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0, /* cf */
	/* d0 */ 0,1,1,1,0,1,0,0,1,1,0,1,1,1,0,1, /* df */
	/* e0 */ 0,1,1,0,0,1,0,0,1,1,0,1,1,1,0,1, /* ef */
	/* f0 */ 0,1,1,1,0,1,0,0,1,1,1,0,1,1,1,0  /* ff */
};

#ifdef NOT_USED
static int reg_num[] = {
	0, 1, 2, 3, 4, 5, 6, 7,
	0, 1, 2, 3, 4, 5, 6, 7,
	0, 1, 2, 3, 4, 5, 6, 7,
};
#endif

static char *reg_name[] = {
	"%eax","%ecx","%edx","%ebx","%esp","%ebp","%esi","%edi",
	"%ax","%cx","%dx","%bx","%sp","%bp","%si","%di",
	"%al","%cl","%dl","%bl","%ah","%ch","%dh","%bh",
	"%es","%cs","%ss","%ds","%fs","%gs",
	"bx+si","bx+di","bp+si","bp+di",
};

static int reg_32[] = {
	R_eAX, R_eCX, R_eDX, R_eBX, R_eSP, R_eBP, R_eSI, R_eDI,
};
static int reg_16[] = {
	R_AX, R_CX, R_DX, R_BX, R_SP, R_BP, R_SI, R_DI,
};
static int reg_8[] = {
	R_AL, R_CL, R_DL, R_BL, R_AH, R_CH, R_DH, R_BH,
};
static int reg_seg[] = {
	R_ES, R_CS, R_SS, R_DS, R_FS, R_GS, R_BAD, R_BAD,
};
static int reg_index[] = {
	R_BX_SI, R_BX_DI, R_BP_SI, R_BP_DI, R_SI, R_DI, R_BP, R_BX,
};

static char *optype_name[] = {
	"NONE","A","C","D","E","M_indirE","F","G","I","sI","J","M",
	"O","P","Q","R","S","T","V","W","X","Y","MMX","EM","MS","GRP",
	"REG",
};

static char *opmods[] = {
	"NONE","a","b","c","d","dg","p","pi",
	"ps","q","s","ss","si","v","w",
};

static char *reg_opname[] = {
	"eAX","eCX","eDX","eBX","eSP","eBP","eSI","eDI",
	"AX","CX","DX","BX","SP","BP","SI","DI",
	"AL","CL","DL","BL","AH","CH","DH","BH",
	"ES","CS","SS","DS","FS","GS",
};

static void
printaddr(kaddr_t addr, int flag, FILE *ofp)
{
	int offset = 0;
	syment_t *sp;

	if ((sp = kl_lkup_symaddr(addr))) {
		offset = addr - sp->s_addr;
	}

	/* Print out address
	 */
	fprintf(ofp, "0x%x", addr);

	/* Print out symbol name
	 */
	if (sp) {
		if (offset) {
			fprintf(ofp, " <%s+%d>",
				sp->s_name, offset);
		} else {
			fprintf(ofp, " <%s>", sp->s_name);
		}
	}

	/* Line things up properly for current function
	 */
	if (flag) {
		if (offset == 0) {
			fprintf(ofp, ":       ");
		} else if (offset < 10) {
			fprintf(ofp, ":     ");
		} else if (offset < 100) {
			fprintf(ofp, ":    ");
		} else if (offset < 1000) {
			fprintf(ofp, ":   ");
		} else if (offset < 10000) {
			fprintf(ofp, ":  ");
		} else {
			fprintf(ofp, ": ");
		}
	}
}

static void
print_optype(int m, int t, FILE *ofp)
{
	if (m >= M_BAD) {
		fprintf(ofp, "BAD");
	} else if (m == M_REG) {
		if (t >= R_BAD) {
			fprintf(ofp, "REG_BAD");
		} else {
			fprintf(ofp, "%s", reg_opname[t]);
		}
	} else {
		if (t == T_NONE) {
			fprintf(ofp, "%s", optype_name[m]);
		} else if (t >= T_BAD) {
			fprintf(ofp, "%s(bad)", optype_name[m]);
		} else {
			fprintf(ofp, "%s%s", optype_name[m], opmods[t]);
		}
	}
}

static void
get_modrm_info(unsigned char modr, int *mod_rm, int *reg_op)
{
	*mod_rm = ((modr >> 6) << 3) | (modr & 7);
	*reg_op = (modr >> 3) & 7; 
}

static int
is_prefix(unsigned char c)
{
	int prefix = 0;

	switch(c) {
		case 0xf3:
			prefix = PREFIX_REPZ;
			break;
		case 0xf2:
			prefix = PREFIX_REPNZ;
			break;
		case 0xf0:
			prefix = PREFIX_LOCK;
			break;
		case 0x2e:
			prefix = PREFIX_CS;
			break;
		case 0x36:
			prefix = PREFIX_SS;
			break;
		case 0x3e:
			prefix = PREFIX_DS;
			break;
		case 0x26:
			prefix = PREFIX_ES;
			break;
		case 0x64:
			prefix = PREFIX_FS;
			break;
		case 0x65:
			prefix = PREFIX_GS;
			break;
		case 0x66:
			prefix = PREFIX_DATA;
			break;
		case 0x67:
			prefix = PREFIX_ADR;
			break;
		case 0x9b:
			prefix = PREFIX_FWAIT;
			break;
	}
	return(prefix);
}

static int
get_modrm_reg16(int mod_rm, int opdata, instr_rec_t *irp)
{
	int reg, mod;

	mod = irp->modrm >> 6;
	switch (mod_rm) {
		case 0x6:
			break;

		default:
			reg = mod_rm - (mod * 8);
			return(reg_index[reg]);
	}
	return(R_BAD);
}

static int
get_modrm_reg32(int mod_rm, int opdata, instr_rec_t *irp)
{
	int reg;

	switch (mod_rm) {
		case 0x0:
		case 0x1:
		case 0x2:
		case 0x3:
		case 0x6:
		case 0x7:
			return(mod_rm);
		case 0x18:
		case 0x19:
		case 0x1a:
		case 0x1b:
		case 0x1c:
		case 0x1d:
		case 0x1e:
		case 0x1f:
			reg = mod_rm - 0x18;
			switch (opdata) {
				case T_b:
					return(reg_8[reg]);
				case T_w:
					return(reg_16[reg]);
				case T_v:
					if (irp->dflag) {
						return(reg_32[reg]);
					} else {
						return(reg_16[reg]);
					}
			}
	}
	return(R_BAD);
}

static void
print_instrname(char *name, instr_rec_t *irp, FILE *ofp)
{
	char *cp, *np, name_str[100];

	strncpy (name_str, name, 100);
	np = name;
	cp = name_str;
	while (*np) {
		if (*np == 'C') {		/* For jcxz/jecxz */
			if (irp->aflag) {
				*cp++ = 'e';
			}
		} else if (*np == 'N') {
			if ((irp->prefixes & PREFIX_FWAIT) == 0) {
				*cp++ = 'n';
			}
		} else if (*np == 'S') {
			/* operand size flag 
			 */
			if (irp->dflag) {
				*cp++ = 'l';
			} else {
				*cp++ = 'w';
			}
		} else if (*np == 'W') {
			/* operand size flag for cwtl, cbtw 
			 */
			if (irp->dflag) {
				*cp++ = 'w';
			} else {
				*cp++ = 'b';
			}
		} else {
			*cp++ = *np;
		}
		np++;
	}
	while(*cp) {
		*cp++ = ' ';
	}
	*cp = 0;
	fprintf(ofp, "%s", name_str);
}

static void
op_a(int opnum, int opdata, instr_rec_t *irp)
{
	int offset;
	kaddr_t pc;

	pc = instrbuf.addr + (instrbuf.ptr - instrbuf.buf);
	switch(opdata) {
		case T_p:
			if (irp->aflag) {
				irp->operand[opnum].op_addr = 
					*(uint32_t*)codeptr;
				codeptr += 4; 
			} else {
				irp->operand[opnum].op_addr = 
					*(uint16_t*)codeptr;
				codeptr += 2;
			}
			irp->operand[opnum].op_seg = *(uint16_t*)codeptr;
			irp->operand[opnum].op_type = O_LPTR;
			codeptr += 2;
			break;
		case T_v:
			if (irp->aflag) {
				offset = *(int*)codeptr;
				irp->operand[opnum].op_addr = pc + offset + 5;
				codeptr += 4;
			} else {
				offset = *(short*)codeptr;
				irp->operand[opnum].op_addr = pc + offset + 3;
				codeptr += 2;
			}
			irp->operand[opnum].op_type = O_ADDR;
			break;
		default:
			break;
	}
}

static void
op_c(int opnum, int opdata, instr_rec_t *irp)
{
	int reg;

	reg = (irp->modrm  >> 3) & 7;
	irp->operand[opnum].op_type = (O_REG|O_CR);
	irp->operand[opnum].op_reg = reg;

}

static void
op_d(int opnum, int opdata, instr_rec_t *irp)
{
	int reg;

	reg = (irp->modrm  >> 3) & 7;
	irp->operand[opnum].op_type = (O_REG|O_DB);
	irp->operand[opnum].op_reg = reg;

}

static void
op_indir_e(int opnum, int opdata, instr_rec_t *irp)
{
	op_e(opnum, opdata, irp);
	irp->operand[opnum].op_type |= O_INDIR;
}

static void
get_modrm_data16(int opnum, int opdata, instr_rec_t *irp)
{
	int reg, mod, mod_rm, reg_op;

	get_modrm_info(irp->modrm, &mod_rm, &reg_op);
	mod = irp->modrm >> 6;
	switch(mod_rm) {
		case 0:
		case 1:
		case 2:
		case 3:
		case 4:
		case 5:
		case 7:
			reg = get_modrm_reg16(mod_rm, opdata, irp);
			irp->operand[opnum].op_reg = reg;
			irp->operand[opnum].op_type = (O_REG|O_BASE);
			break;

		case 6:
			/* 16-bit displacement */
			irp->operand[opnum].op_type = O_DISP;
			irp->operand[opnum].op_disp = *(uint16_t*)codeptr;
			codeptr += 2;
			break;
		case 8:
			/* disp8[BX+SI] */
			irp->operand[opnum].op_type = (O_REG|O_DISP);
			irp->operand[opnum].op_reg = R_BX_SI;
			irp->operand[opnum].op_disp = *(signed char*)codeptr;
			codeptr++;
			break;
		case 9:
			/* disp8[BX+DI] */
			irp->operand[opnum].op_type = (O_REG|O_DISP);
			irp->operand[opnum].op_reg = R_BX_DI;
			irp->operand[opnum].op_disp = *(signed char*)codeptr;
			codeptr++;
			break;
		case 10:
			/* disp8[BP+SI] */
			irp->operand[opnum].op_type = (O_REG|O_DISP);
			irp->operand[opnum].op_reg = R_BP_SI;
			irp->operand[opnum].op_disp = *(signed char*)codeptr;
			codeptr++;
			break;

		case 11:
			/* disp8[BP+DI] */
			irp->operand[opnum].op_type = (O_REG|O_DISP);
			irp->operand[opnum].op_reg = R_BP_DI;
			irp->operand[opnum].op_disp = *(signed char*)codeptr;
			codeptr++;
			break;

		case 12:
			/* disp8[SI] */
			irp->operand[opnum].op_type = (O_REG|O_DISP);
			irp->operand[opnum].op_reg = R_SI;
			irp->operand[opnum].op_disp = *(signed char*)codeptr;
			codeptr++;
			break;

		case 13:
			/* disp8[DI] */
			irp->operand[opnum].op_type = (O_REG|O_DISP);
			irp->operand[opnum].op_reg = R_DI;
			irp->operand[opnum].op_disp = *(signed char*)codeptr;
			codeptr++;
			break;

		case 14:
			/* disp8[BP] */
			irp->operand[opnum].op_type = (O_REG|O_DISP);
			irp->operand[opnum].op_reg = R_BP;
			irp->operand[opnum].op_disp = *(signed char*)codeptr;
			codeptr++;
			break;

		case 15:
			/* disp8[BX] */
			irp->operand[opnum].op_type = (O_REG|O_DISP);
			irp->operand[opnum].op_reg = R_BX;
			irp->operand[opnum].op_disp = *(signed char*)codeptr;
			codeptr++;
			break;

		case 16:
			/* disp16[BX+SI] */
			irp->operand[opnum].op_type = (O_REG|O_DISP);
			irp->operand[opnum].op_reg = R_BX_SI;
			irp->operand[opnum].op_disp = *(short*)codeptr;
			codeptr += 2;
			break;

		case 17:
			/* disp16[BX+DI] */
			irp->operand[opnum].op_type = (O_REG|O_DISP);
			irp->operand[opnum].op_reg = R_BX_DI;
			irp->operand[opnum].op_disp = *(short*)codeptr;
			codeptr += 2;
			break;

		case 18:
			/* disp16[BP+SI] */
			irp->operand[opnum].op_type = (O_REG|O_DISP);
			irp->operand[opnum].op_reg = R_BP_SI;
			irp->operand[opnum].op_disp = *(short*)codeptr;
			codeptr += 2;
			break;

		case 19:
			/* disp16[BP+DI] */
			irp->operand[opnum].op_type = (O_REG|O_DISP);
			irp->operand[opnum].op_reg = R_BP_DI;
			irp->operand[opnum].op_disp = *(short*)codeptr;
			codeptr += 2;
			break;

		case 20:
			/* disp16[SI] */
			irp->operand[opnum].op_type = (O_REG|O_DISP);
			irp->operand[opnum].op_reg = R_SI;
			irp->operand[opnum].op_disp = *(short*)codeptr;
			codeptr += 2;
			break;

		case 21:
			/* disp16[DI] */
			irp->operand[opnum].op_type = (O_REG|O_DISP);
			irp->operand[opnum].op_reg = R_DI;
			irp->operand[opnum].op_disp = *(short*)codeptr;
			codeptr += 2;
			break;

		case 22:
			/* disp16[BP] */
			irp->operand[opnum].op_type = (O_REG|O_DISP);
			irp->operand[opnum].op_reg = R_BP;
			irp->operand[opnum].op_disp = *(short*)codeptr;
			codeptr += 2;
			break;

		case 23:
			/* disp16[BX] */
			irp->operand[opnum].op_type = (O_REG|O_DISP);
			irp->operand[opnum].op_reg = R_BX;
			irp->operand[opnum].op_disp = *(short*)codeptr;
			codeptr += 2;
			break;
	}
}

static void
get_modrm_data32(int opnum, int opdata, instr_rec_t *irp)
{
	int reg, mod, mod_rm, reg_op;

	get_modrm_info(irp->modrm, &mod_rm, &reg_op);
	mod = irp->modrm >> 6;
	switch(mod_rm) {
		case 0:
		case 1:
		case 2:
		case 3:
		case 6:
		case 7:
			reg = get_modrm_reg32(mod_rm, opdata, irp);
			irp->operand[opnum].op_reg = reg;
			irp->operand[opnum].op_type = (O_REG|O_BASE);
			break;

		case 5:
			/* 32-bit displacement */
			irp->operand[opnum].op_type = O_DISP;
			irp->operand[opnum].op_disp = *(kaddr_t*)codeptr;
			codeptr += 4;
			break;
		case 8:
			/* disp8[EAX] */
			irp->operand[opnum].op_type = (O_REG|O_DISP);
			irp->operand[opnum].op_reg = R_eAX;
			irp->operand[opnum].op_disp = *(signed char*)codeptr;
			codeptr++;
			break;
		case 9:
			/* disp8[ECX] */
			irp->operand[opnum].op_type = (O_REG|O_DISP);
			irp->operand[opnum].op_reg = R_eCX;
			irp->operand[opnum].op_disp = *(signed char*)codeptr;
			codeptr++;
			break;
		case 10:
			/* disp8[EDX] */
			irp->operand[opnum].op_type = (O_REG|O_DISP);
			irp->operand[opnum].op_reg = R_eDX;
			irp->operand[opnum].op_disp = *(signed char*)codeptr;
			codeptr++;
			break;

		case 11:
			/* disp8[EBX] */
			irp->operand[opnum].op_type = (O_REG|O_DISP);
			irp->operand[opnum].op_reg = R_eBX;
			irp->operand[opnum].op_disp = *(signed char*)codeptr;
			codeptr++;
			break;

		case 13:
			/* disp8[EBP] */
			irp->operand[opnum].op_type = (O_REG|O_DISP);
			irp->operand[opnum].op_reg = R_eBP;
			irp->operand[opnum].op_disp = *(signed char*)codeptr;
			codeptr++;
			break;

		case 14:
			/* disp8[ESI] */
			irp->operand[opnum].op_type = (O_REG|O_DISP);
			irp->operand[opnum].op_reg = R_eSI;
			irp->operand[opnum].op_disp = *(signed char*)codeptr;
			codeptr++;
			break;
		case 15:
			/* disp8[EDI] */
			irp->operand[opnum].op_type = (O_REG|O_DISP);
			irp->operand[opnum].op_reg = R_eDI;
			irp->operand[opnum].op_disp = *(signed char*)codeptr;
			codeptr++;
			break;

		case 16:
			/* disp32[EAX] */
			irp->operand[opnum].op_type = (O_REG|O_DISP);
			irp->operand[opnum].op_reg = R_eAX;
			irp->operand[opnum].op_disp = *(int*)codeptr;
			codeptr += 4;
			break;

		case 17:
			/* disp32[ECX] */
			irp->operand[opnum].op_type = (O_REG|O_DISP);
			irp->operand[opnum].op_reg = R_eCX;
			irp->operand[opnum].op_disp = *(int*)codeptr;
			codeptr += 4;
			break;

		case 18:
			/* disp32[EDX] */
			irp->operand[opnum].op_type = (O_REG|O_DISP);
			irp->operand[opnum].op_reg = R_eDX;
			irp->operand[opnum].op_disp = *(int*)codeptr;
			codeptr += 4;
			break;

		case 19:
			/* disp32[EBX] */
			irp->operand[opnum].op_type = (O_REG|O_DISP);
			irp->operand[opnum].op_reg = R_eBX;
			irp->operand[opnum].op_disp = *(int*)codeptr;
			codeptr += 4;
			break;

		case  4: /* [..][..] (SIB) */
		case 12: /* disp8[..][..] (SIB) */
		case 20: { /* disp32[..][..] (SIB) */
			int s, i, b, mod, rm, havebase;

			s = (irp->sib >> 6) & 3;
			i = (irp->sib >> 3) & 7;
			b = irp->sib & 7;
			mod = irp->modrm >> 6;
			rm = irp->modrm & 7;
			havebase = 1;
			switch (mod) {
				case 0:
					if (b == 5) {
						havebase = 0;
						irp->operand[opnum].op_disp =
							*(int*)codeptr;
						irp->operand[opnum].op_type = 
							O_DISP;
						codeptr += 4;
					}
					break;
				case 1:
					irp->operand[opnum].op_disp = 
						*(signed char*) codeptr; 
					codeptr++;
					irp->operand[opnum].op_type = O_DISP;
					break;
				case 2:
					irp->operand[opnum].op_disp =
						*(int*)codeptr;
					codeptr += 4;
					irp->operand[opnum].op_type = O_DISP;
					break;
			}
			if (havebase) {
				irp->operand[opnum].op_base = b;
				irp->operand[opnum].op_type |= O_BASE;
			}
			if (i != 4) {
				irp->operand[opnum].op_index = i;
				irp->operand[opnum].op_type |= O_INDEX;
			}
			if (s) {
				irp->operand[opnum].op_scale = s;
				irp->operand[opnum].op_type |= O_SCALE;
			}
			break;
		}
		case 21:
			/* disp32[EBP] */
			irp->operand[opnum].op_type = (O_REG|O_DISP);
			irp->operand[opnum].op_reg = R_eBP;
			irp->operand[opnum].op_disp = *(int*)codeptr;
			codeptr += 4;
			break;
		case 22:
			/* disp32[ESI] */
			irp->operand[opnum].op_type = (O_REG|O_DISP);
			irp->operand[opnum].op_reg = R_eSI;
			irp->operand[opnum].op_disp = *(int*)codeptr;
			codeptr += 4;
			break;
		case 23:
			/* disp32[EDI] */
			irp->operand[opnum].op_type = (O_REG|O_DISP);
			irp->operand[opnum].op_reg = R_eDI;
			irp->operand[opnum].op_disp = *(int*)codeptr;
			codeptr += 4;
			break;
	}
}

static int
op_e(int opnum, int opdata, instr_rec_t *irp)
{
	int reg, mod, mod_rm, reg_op;

	get_modrm_info(irp->modrm, &mod_rm, &reg_op);
	mod = irp->modrm >> 6;

	if (mod == 3) {
		/* ((mod_rm >= 24) && (mod_rm <=31)) */
		if (opdata == T_NONE) {
			return(1);
		}
		if (irp->aflag) {
			reg = get_modrm_reg32(mod_rm, opdata, irp); 
		} else {
			reg = get_modrm_reg16(mod_rm, opdata, irp); 
		}
		irp->operand[opnum].op_type = O_REG;
		irp->operand[opnum].op_reg = reg;
		if ((reg = R_BAD)) {
			return(1);
		} else {
			return(0);
		}
	}
	if (irp->aflag) {
		get_modrm_data32(opnum, opdata, irp);
	} else {
		get_modrm_data16(opnum, opdata, irp);
	}
	if (seg_prefix(irp->prefixes)) {
		irp->operand[opnum].op_type |= O_SEG;
		irp->operand[opnum].op_seg = seg_prefix(irp->prefixes);
	}
	return(0);
}

static int
op_g(int opnum, int opdata, instr_rec_t *irp)
{
	int reg, mod_rm, reg_op;

	get_modrm_info(irp->modrm, &mod_rm, &reg_op);
	irp->operand[opnum].op_type = O_REG;
	if ((reg_op < 0) || (reg_op >= 8)){
		irp->operand[opnum].op_reg = R_BAD;
		return(1);
	}
	switch(opdata) {
		case T_b:
			reg = reg_8[reg_op];
			break;
		case T_w:
			reg = reg_16[reg_op];
			break;
		case T_d:
			reg = reg_32[reg_op];
			break;
		case T_v:
			if (irp->dflag) {
				reg = reg_32[reg_op];
			} else {
				reg = reg_16[reg_op];
			}
			break;
		default:	
			irp->operand[opnum].op_reg = R_BAD;
			return(1);
	}
	irp->operand[opnum].op_reg = reg;
	return(0);
}

static void
op_i(int opnum, int opdata, instr_rec_t *irp)
{
	irp->operand[opnum].op_type = O_IMMEDIATE;
	switch (opdata) {
		case T_b:
			irp->operand[opnum].op_addr = *(unsigned char*)codeptr;
			codeptr++;
			break;
		case T_w:
			irp->operand[opnum].op_addr = *(uint16_t*)codeptr;
			codeptr += 2;
			break;
		case T_v:
			if (irp->dflag) {
				irp->operand[opnum].op_addr = 
					*(uint32_t*)codeptr;
				codeptr += 4;
			} else {
				irp->operand[opnum].op_addr = 
					*(uint16_t*)codeptr;
				codeptr += 2;
			}
			break;
	}
}

static void
op_s(int opnum, int opdata, instr_rec_t *irp)
{
	int reg;

	reg = (irp->modrm >> 3) & 7;
	irp->operand[opnum].op_reg = reg_seg[reg];
	irp->operand[opnum].op_type = O_REG;
}

static void
op_si(int opnum, int opdata, instr_rec_t *irp)
{
	int val;

	irp->operand[opnum].op_type = O_IMMEDIATE;
	switch (opdata) {
		case T_b:
			val = *(signed char*)codeptr++;
			irp->operand[opnum].op_addr = val;
			break;
		case T_v:
			if (irp->dflag) {
				irp->operand[opnum].op_addr = *(int*)codeptr;
				codeptr += 4;
			} else {
				val = *(short*)codeptr;
				irp->operand[opnum].op_addr = val;
				codeptr += 2;
			}
			break;
		case T_w:
			val = *(short*)codeptr;
			irp->operand[opnum].op_addr = val;
			codeptr += 2;
			break;
	}
}

static void
op_j(int opnum, int opdata, instr_rec_t *irp)
{
	kaddr_t pc;

	pc = instrbuf.addr + (instrbuf.ptr - instrbuf.buf);
	pc += (codeptr - instrbuf.ptr);
	switch (opdata) {
		case T_b:
			pc++; 
			pc += *(signed char *)codeptr++;
			break;
		case T_v:
			if (irp->dflag) {
				/* 32-bit */
				pc += 4;
				pc += *(int*)codeptr;
				codeptr += 4;
			} else {
				/* 16-bit */
				pc += 2;
				pc += *(short*)codeptr;
				codeptr += 2;
			}
			break;
	}
	irp->operand[opnum].op_type = O_ADDR;
	irp->operand[opnum].op_addr = pc;
}

static void
op_m(int opnum, int opdata, instr_rec_t *irp)
{
	op_e(opnum, 0, irp); 
}

static void
op_o(int opnum, int opdata, instr_rec_t *irp)
{
	if (irp->aflag) {
		irp->operand[opnum].op_addr = *(uint32_t*)codeptr;
		codeptr += 4;
	} else {
		irp->operand[opnum].op_addr = *(uint16_t*)codeptr;
		codeptr += 2;
	}
	irp->operand[opnum].op_type = O_OFF;
}

static void
op_r(int opnum, int opdata, instr_rec_t *irp)
{
	int rm;
	rm = irp->modrm & 7;
	switch (opdata) {
		case T_d:
			irp->operand[opnum].op_reg = reg_32[rm];
			break;
		case T_w:
			irp->operand[opnum].op_reg = reg_16[rm];
			break;
	}
	irp->operand[opnum].op_type = O_REG;
}

static void
op_x(int opnum, int opdata, instr_rec_t *irp)
{
	irp->operand[opnum].op_seg = R_DS;
	if (irp->aflag) {
		irp->operand[opnum].op_reg = R_eSI;
	} else {
		irp->operand[opnum].op_reg = R_SI;
	}
	irp->operand[opnum].op_type = O_SEG;
}

static void
op_y(int opnum, int opdata, instr_rec_t *irp)
{
	irp->operand[opnum].op_seg = R_ES;
	if (irp->aflag) {
		irp->operand[opnum].op_reg = R_eDI;
	} else {
		irp->operand[opnum].op_reg = R_DI;
	}
	irp->operand[opnum].op_type = O_SEG;
}

static void
get_operand_info(int opnum, instr_rec_t *irp)
{
	int opcode, opdata;

	switch(opnum) {
		case 0:
			opcode = irp->opcodep->Op1;
			opdata = irp->opcodep->opdata1;
			break;
		case 1:
			opcode = irp->opcodep->Op2;
			opdata = irp->opcodep->opdata2;
			break;
		case 2:
			opcode = irp->opcodep->Op3;
			opdata = irp->opcodep->opdata3;
			break;
	}
	switch (opcode) {
		case M_A:
			op_a(opnum, opdata, irp);
			break;

		case M_C:
			op_c(opnum, opdata, irp);
			break;

		case M_D:
			op_d(opnum, opdata, irp);
			break;

		case M_E:
			op_e(opnum, opdata, irp);
			break;

		case M_indirE:
			op_indir_e(opnum, opdata, irp);
			break;

		case M_G:
			op_g(opnum, opdata, irp);
			break;

		case M_I:
			op_i(opnum, opdata, irp);
			break;

		case M_sI:
			op_si(opnum, opdata, irp);
			break;

		case M_J: 
			op_j(opnum, opdata, irp);
			break;

		case M_M: 
			op_m(opnum, opdata, irp);
			break;

		case M_O:
			op_o(opnum, opdata, irp);
			break;

		case M_R:
			op_r(opnum, opdata, irp);
			break;

		case M_S:
			op_s(opnum, opdata, irp);
			break;

		case M_X:
			op_x(opnum, opdata, irp);
			break;

		case M_Y:
			op_y(opnum, opdata, irp);
			break;

		case M_REG:
		case M_indirREG:
			irp->operand[opnum].op_type = O_REG;
			if (opdata >= R_AX) {
				irp->operand[opnum].op_reg = opdata;
			} else {
				if (irp->dflag) {
					irp->operand[opnum].op_reg = 
						reg_32[opdata];
				} else {
					irp->operand[opnum].op_reg = 
						reg_16[opdata];
				}
			}
			if (opcode == M_indirREG) {
				/* The O_BASE gets the right results */
				irp->operand[opnum].op_type |= O_BASE;
			}
			break;
	}
}

/* Temporary opcode_rec_s struct that we keep around for the times
 * when we have to construct a special case instruction (e.g. some
 * floating point instructions).
 */
static opcode_rec_t tempop;
static char fwait_name[] = "fwait";

int
get_instr_info(kaddr_t pc, instr_rec_t *irp)
{
	int opcode, size = 0, p, prefixes = 0;
	unsigned char modrm = 0;
	opcode_rec_t *op;

	if (instr_buf_init) {
		bzero(&instrbuf, sizeof(instrbuf));
		instr_buf_init = 0;
	}

	/* Check to see instrbuf is valid and if there are enough 
	 * bytes in our instruction cache to cover the worst case 
	 * scenario for this pc.
	 */
	if (!instrbuf.addr || (pc < instrbuf.addr) || 
			(pc > (instrbuf.addr + instrbuf.size - 15))) { 
		instrbuf.addr = pc;
		instrbuf.size = 256;
		GET_BLOCK(pc, 256, instrbuf.buf);
		if (KL_ERROR) {
			return(0);
		}
	} 

	/* Make sure that the instruction pointer points to the 
	 * right byte in the buffer.
	 */
	instrbuf.ptr = instrbuf.buf + (pc - instrbuf.addr);
	codeptr = instrbuf.ptr;
	irp->addr = pc;

	/* Check for prefixes 
	 */
	while((p = is_prefix(*codeptr))) {
		prefixes |= p;
		codeptr++;
		if ((prefixes & PREFIX_FWAIT) && 
			((*codeptr < 0xd8) || (*codeptr > 0xdf))) {

			/* If there is an fwait prefix that is not
			 * followed by a float instruction, we need to
			 * create a special instruction record so that
			 * the "fwait" gets printed out.
			 */
			bzero(&tempop, sizeof(tempop));
			tempop.name = fwait_name;
			irp->opcodep = &tempop;
			size = ((unsigned)codeptr - (unsigned)instrbuf.ptr);
			instrbuf.ptr = codeptr;
			irp->size = size;
			return(size);
		}
	}
	if (prefixes & PREFIX_DATA) {
		irp->dflag ^= 1;
	}
	if (prefixes & PREFIX_ADR) {
		irp->aflag ^= 1;
	}

	/* Check for one or two byte opcode, capture the opcode and
	 * check for a ModR/M byte.
	 */
	if (*codeptr == 0x0f) {
		opcode = *((unsigned short*)codeptr);
		codeptr++;
		op = &op_386_twobyte[*codeptr];
		if(twobyte_has_modrm[*codeptr]) {
			codeptr++;
			modrm = *codeptr++;
		} else {
			codeptr++;
		}
	} else {
		opcode = *codeptr;
		op = &op_386[*codeptr];
		if(onebyte_has_modrm[*codeptr]) {
			codeptr++;
			modrm = *codeptr++;
		} else {
			codeptr++;
		}
	}
	/* See if the get_op bits from the modrm are needed to determine
	 * the actual instruction.
	 */
	if (op->Op1 == M_GRP) {
		op = &grps[op->opdata1][(modrm & 0x38) >> 3];

		/* Put something unique in opcode
		 */
		opcode = ((opcode << 8)|((modrm & 0x38) >> 3));
	} else if (op->Op1 == M_FLOAT) {
		int mod, rm, reg;

		mod = modrm >> 6;
		rm = modrm & 7;
		reg = (modrm >> 3) & 7; 
		bzero(&tempop, sizeof(tempop));
		if (mod != 3) {
			tempop.name = float_mem[(opcode - 0xd8) * 8 + reg];
			tempop.Op1 = M_E;
			tempop.opdata1 = T_v;
			op = &tempop;
		} else {
			op = &float_grps[opcode - 0xd8][reg];
			if (op->Op1 == M_FGRP) {
				tempop.name = fgrps[op->opdata1][rm];
				/* instruction fnstsw is only one with 
				 * strange arg 
				 */
				if ((opcode == 0xdf) && (*codeptr == 0xe0)) {
					irp->operand[1].op_type = O_REG;
					irp->operand[1].op_reg = R_eAX;
				}				
				op = &tempop;
			} 
		}
	}
	irp->opcodep = op;
	irp->opcode = opcode;
	irp->modrm = modrm; 
	irp->prefixes = prefixes; 

	/* Check to see if this is a bad instruction (per a table entry)
	 */
	if (op->opdata1 == T_BAD) {
		/* Back off the modrm if we grabbed one and return
		 * from here.
		 */
		if (modrm) {
			codeptr--;
			size = ((unsigned)codeptr - (unsigned)instrbuf.ptr);
			instrbuf.ptr = codeptr;
			irp->size = size;
			return(size);
		}
	}

	/* Check to see if there is an SIB byte.
	 */
	if (((modrm & 0xc0) != 0xc0) && ((modrm & 7) == 4)) {
		/* There is an SIB byte
		 */
		irp->sib = *codeptr++;
		irp->have_sib = 1;
	}

	/* Gather information on operands 
	 */
	if (op->Op1 && (op->Op1 != M_BAD)) {
		get_operand_info(0, irp);
	}
	if (op->Op2 && (op->Op2 != M_BAD)) {
		get_operand_info(1, irp);
	}
	if (op->Op3 && (op->Op3 != M_BAD)) {
		get_operand_info(2, irp);
	}

	/* Determine total instruction size and adjust instrbuf ptr
	 */
	size = ((unsigned)codeptr - (unsigned)instrbuf.ptr);
	instrbuf.ptr = codeptr;
	irp->size = size;
	return(size);
}

static int
seg_prefix(int prefixes) {
	if (prefixes & PREFIX_CS) {
		return(R_CS);
	} else if (prefixes & PREFIX_DS) {
		return(R_DS);
	} else if (prefixes & PREFIX_SS) {
		return(R_SS);
	} else if (prefixes & PREFIX_ES) {
		return(R_ES);
	} else if (prefixes & PREFIX_FS) {
		return(R_FS);
	} else if (prefixes & PREFIX_GS) {
		return(R_GS);
	} 
	return(0);
}

#ifdef NOT_USED
static void
print_seg_prefix(instr_rec_t *irp, FILE *ofp)
{
	if (irp->prefixes & PREFIX_CS) {
		fprintf(ofp, "%%cs:");
	}
	if (irp->prefixes & PREFIX_DS) {
		fprintf(ofp, "%%ds:");
	}
	if (irp->prefixes & PREFIX_SS) {
		fprintf(ofp, "%%ss:");
	}
	if (irp->prefixes & PREFIX_ES) {
		fprintf(ofp, "%%es:");
	}
	if (irp->prefixes & PREFIX_FS) {
		fprintf(ofp, "%%fs:");
	}
	if (irp->prefixes & PREFIX_GS) {
		fprintf(ofp, "%%gs:");
	}
}
#endif

static int
print_prefixes(instr_rec_t *irp, FILE *ofp)
{
	int cnt = 0;

	if (irp->prefixes & PREFIX_REPZ) {
		fprintf(ofp, "repz ");
		cnt++;
	}
	if (irp->prefixes & PREFIX_REPNZ) {
		fprintf(ofp, "repnz ");
		cnt++;
	}
	if (irp->prefixes & PREFIX_LOCK) {
		fprintf(ofp, "lock ");
		cnt++;
	}
	if (irp->prefixes & PREFIX_ADR) {
		if (irp->aflag) {
			fprintf(ofp, "addr32 ");
		} else {
			fprintf(ofp, "addr16 ");
		}
		cnt++;
	}
	return(cnt);
}

static void
print_sib_value(int opnum, instr_rec_t *irp, FILE *ofp)
{
	if (irp->operand[opnum].op_type & O_REG) {
		if (irp->operand[opnum].op_type & O_BASE) {
			fprintf(ofp, "(%s)", 
				reg_name[irp->operand[opnum].op_reg]);
		} else {
			fprintf(ofp, "%s", 
				reg_name[irp->operand[opnum].op_reg]);
		}
		return;
	} else if (irp->operand[opnum].op_type & O_IMMEDIATE) {
		fprintf(ofp, "$0x%x", irp->operand[opnum].op_addr);
		return;
	}
	fprintf(ofp, "(");
	if (irp->operand[opnum].op_type & O_BASE) {
		fprintf(ofp, "%s,", reg_name[irp->operand[opnum].op_base]);
	} else {
		fprintf(ofp, ",");
	}
	if (irp->operand[opnum].op_type & O_INDEX) {
		fprintf(ofp, "%s,", reg_name[irp->operand[opnum].op_index]);
	} 
	fprintf(ofp, "%d)", (1 << irp->operand[opnum].op_scale));
}

static void
print_opvalue(int opnum, instr_rec_t *irp, FILE *ofp)
{
	if (irp->operand[opnum].op_type & O_REG) {
		if (irp->operand[opnum].op_type & (O_BASE|O_DISP)) {
			fprintf(ofp, "(%s)", 
				reg_name[irp->operand[opnum].op_reg]);
		} else {
			fprintf(ofp, "%s", 
				reg_name[irp->operand[opnum].op_reg]);
		}
	} else if (irp->operand[opnum].op_type & O_IMMEDIATE) {
		fprintf(ofp, "$0x%x", irp->operand[opnum].op_addr);
	} else if (irp->operand[opnum].op_type & O_ADDR) {
		/* jump or call address */
		printaddr(irp->operand[opnum].op_addr, 0, ofp);
	} else if (irp->operand[opnum].op_type & O_OFF) {
		fprintf(ofp, "0x%x", irp->operand[opnum].op_addr);
	}
}

int
print_instr(kaddr_t pc, FILE *ofp, int flag)
{
	int p = 0, i, j, size, print_comma = 0;
	instr_rec_t irp;
	opcode_rec_t *op;

	bzero(&irp, sizeof(irp));
	/* XXX -- For now, make aflag and dflag equal to one.  Should get
	 * this from some sort of configuration struct (set via 
	 * initialization)
	 */
	irp.aflag = 1;
	irp.dflag = 1;
	size = get_instr_info(pc, &irp);
	op = irp.opcodep;
	if (!op) {
		fprintf(ofp, "BAD INSTR (pc=0x%x)\n", pc);
		return(0);
	}
	printaddr(pc, 1, ofp);
	if (flag) {
		fprintf(ofp, "0x%04x  ", irp.opcode);
	}
	if (irp.prefixes) {
		p = print_prefixes(&irp, ofp);
	}
	print_instrname(op->name, &irp, ofp);
	/* HACK! but necessary to match i386-dis.c output for fwait.
	 */
	if (!strcmp(op->name, "fwait")) {
		fprintf(ofp, "\n");
		return(irp.size);
	}
	if (p || (strlen(op->name) >= 7)) {
		fprintf(ofp, " ");
	} else {
		for (i = 0; i < (7 - strlen(op->name)); i++) {
			fprintf(ofp, " ");
		}
	}
	for (j = 0; j < 3; j++) {
		if (irp.opcode == 0xc8) {
			i = j;
		} else {
			i = 2 - j;
		}
		if(irp.operand[i].op_type) {
			if (print_comma) {
				fprintf(ofp, ",");
			}
			if (irp.operand[i].op_type & O_LPTR) {
				fprintf(ofp, "0x%x,0x%x",
					irp.operand[i].op_seg,
					irp.operand[i].op_addr);
				print_comma++;
				continue;
			}
			if (irp.operand[i].op_type & O_CR) {
				fprintf(ofp, "%%cr%d", irp.operand[i].op_reg);
				print_comma++;
				continue;
			}
			if (irp.operand[i].op_type & O_DB) {
				fprintf(ofp, "%%db%d", irp.operand[i].op_reg);
				print_comma++;
				continue;
			}
			if (irp.operand[i].op_type & O_SEG) {
				fprintf(ofp, "%s:(%s)", 
					reg_name[irp.operand[i].op_seg],
					reg_name[irp.operand[i].op_reg]);
				print_comma++;
				continue;
			}
			if (irp.operand[i].op_type & O_INDIR) {
				fprintf(ofp, "*");
			}
			if (irp.operand[i].op_type & O_DISP) {
				fprintf(ofp, "0x%x", irp.operand[i].op_disp);
			}
			if (irp.have_sib) {
				print_sib_value(i, &irp, ofp);
			} else {
				print_opvalue(i, &irp, ofp);
			}
			print_comma++;
		}
	}
	if (flag) {
		fprintf(ofp, "  (%d %s)\n", 
			irp.size, (irp.size > 1) ? "bytes" : "byte"); 
	} else {
		fprintf(ofp, "\n");
	}
	return(irp.size);
}

void
list_instructions(FILE *ofp)
{
	int i, j, print_comma = 0;

	fprintf(ofp, "ONE BYTE INSTRUCTIONS:\n\n");
	for(i = 0; i < 256; i++) {
		fprintf(ofp, "0x%04x  %s", i, op_386[i].name);
		for (j = 0; j < (10 - strlen(op_386[i].name)); j++) {
			fprintf(ofp, " ");
		}
		if (op_386[i].Op1) {
			print_optype(op_386[i].Op1, op_386[i].opdata1, ofp);
			print_comma++;
		}
		if (op_386[i].Op2) {
			if (print_comma) {
				fprintf(ofp, ",");
			}
			print_optype(op_386[i].Op2, op_386[i].opdata2, ofp);
			print_comma++;
		}
		if (op_386[i].Op3) {
			if (print_comma) {
				fprintf(ofp, ",");
			}
			print_optype(op_386[i].Op3, op_386[i].opdata3, ofp);
		}
		fprintf(ofp, "\n");
		
	}

	fprintf(ofp, "\nTWO BYTE INSTRUCTIONS:\n\n");
	for(i = 0; i < 256; i++) {
		fprintf(ofp, "0x0f%02x  %s", i, op_386_twobyte[i].name);
		for (j = 0; j < (10 - strlen(op_386_twobyte[i].name)); j++) {
			fprintf(ofp, " ");
		}
		if (op_386_twobyte[i].Op1) {
			print_optype(op_386_twobyte[i].Op1, 
				op_386_twobyte[i].opdata1, ofp);
			print_comma++;
		}
		if (op_386_twobyte[i].Op2) {
			if (print_comma) {
				fprintf(ofp, ",");
			}
			print_optype(op_386_twobyte[i].Op2, 
				op_386_twobyte[i].opdata2, ofp);
			print_comma++;
		}
		if (op_386_twobyte[i].Op3) {
			if (print_comma) {
				fprintf(ofp, ",");
			}
			print_optype(op_386_twobyte[i].Op3, 
				op_386_twobyte[i].opdata3, ofp);
		}
		fprintf(ofp, "\n");
	}
}

void
free_instr_stream(instr_rec_t *irp)
{
	instr_rec_t *ptr;

	if(irp) {
		while (irp->prev) {
			irp = irp->prev;
		}
		while (irp) {
			ptr = irp;
			irp = irp->next;
			kl_free_block(ptr);
		}
	}
}

instr_rec_t *
get_instr_stream(kaddr_t pc, int bcount, int acount)
{
	int size, count = 0;
	kaddr_t addr, start_addr, end_addr;
        syment_t *sp1, *sp2;
	instr_rec_t *fst = (instr_rec_t *)NULL, *lst, *ptr, *cur;

	if (!(sp1 = kl_lkup_symaddr(pc))) {
		return((instr_rec_t *)NULL);
	}
	start_addr = sp1->s_addr;
	if (pc <= (sp1->s_addr + (bcount * 15))) {
		if ((sp2 = kl_lkup_symaddr(sp1->s_addr - 4))) {
			start_addr = sp2->s_addr;
		}
	} 
	if (pc > (sp1->s_next->s_addr - (acount * 15))) {
		if (sp1->s_next->s_next) {
			end_addr = sp1->s_next->s_next->s_addr;
		} else {
			end_addr = sp1->s_next->s_addr;
		}
	} else {
		end_addr = sp1->s_next->s_addr;
	}
	addr = start_addr;
	while (addr <= pc) {
		if (addr >= end_addr) {
			/* We've gone too far (beyond the end of this
			 * function) The pc most likely was not valid
			 * (it pointed into the middle of an instruction).
			 */
			free_instr_stream(cur);
			return((instr_rec_t *)NULL);
		}
		if (count <= bcount) {
			/* Allocate another record
			 */
			cur = (instr_rec_t *)
				kl_alloc_block(sizeof(instr_rec_t), K_TEMP);
			count++;
			cur->aflag = cur->dflag = 1;
			if ((ptr = fst)) {
				while (ptr->next) {
					ptr = ptr->next;
				}
				ptr->next = cur;
				cur->prev = ptr;
			} else {
				fst = cur; 
			}
		} else {
			/* Pull the last record to the front of the list
			 */
			ptr = fst;
			if (ptr->next) {
				fst = ptr->next;
				fst->prev = (instr_rec_t *)NULL;
				cur->next = ptr;
			}
			bzero(ptr, sizeof(*ptr));
			ptr->aflag = ptr->dflag = 1;
			if (ptr != fst) {
				ptr->prev = cur;
			}
			cur = ptr;

		}
		size = get_instr_info(addr, cur);
		if (size == 0) {
			free_instr_stream(cur);
			return((instr_rec_t *)NULL);
		}
		addr += size;
	}
	if (acount) {
		lst = cur;
		for (count = 0; count < acount; count++) {
			ptr = (instr_rec_t *) 
				kl_alloc_block(sizeof(instr_rec_t), K_TEMP);
			ptr->aflag = ptr->dflag = 1;
			size = get_instr_info(addr, ptr);
			if (size == 0) {
				kl_free_block(ptr);
				return(cur);
			}
			lst->next = ptr;
			ptr->prev = lst;
			lst = ptr;
			addr += size;
		}
	}
	return(cur);
}

/*
 * print_instr_stream()
 */
kaddr_t
print_instr_stream(kaddr_t value, int bcount, int acount, int flags, FILE *ofp)
{
	kaddr_t v = value;
	instr_rec_t *cur_irp, *irp;

	if ((cur_irp = get_instr_stream(v, bcount, acount))) {
		irp = cur_irp;

		/* Walk back to the start of the stream and then
		 * print out all instructions in the stream.
		 */
		while (irp->prev) {
			irp = irp->prev;
		}
		while (irp) {
			if (flags & C_FULL) {
				print_instr(irp->addr, ofp, 1);
			} else {
				print_instr(irp->addr, ofp, 0);
			}
			if (irp->addr >= value) {
				v += irp->size;
			}
			irp = irp->next;
		}
		free_instr_stream(cur_irp);
	}
	return(v);
}

/*
 * dump_instr() -- architecture specific instruction dump routine
 */
void
dump_instr(kaddr_t addr, uint64_t count, int flags, FILE *ofp)
{
	fprintf(ofp, "This operation not supported for i386 architecture.\n");
}
