#include <u.h>
#include <libc.h>
#include "8i.h"
static char *opstr[] = { /* Edit s/O(.*),/[O\1]= "\1",/g */
[OBAD]= "BAD",
[O0F]= "0F",
[OAAA]= "AAA",
[OAAD]= "AAD",
[OAAM]= "AAM",
[OAAS]= "AAS",
[OADC]= "ADC",
[OADD]= "ADD",
[OAND]= "AND",
[OARPL]= "ARPL",
[OASIZE]= "ASIZE",
[OBOUND]= "BOUND",
[OBT]= "BT",
[OBTS]= "BTS",
[OCALL]= "CALL",
[OCBW]= "CBW",
[OCLC]= "CLC",
[OCLD]= "CLD",
[OCLI]= "CLI",
[OCMC]= "CMC",
[OCMOV]= "CMOV",
[OCMP]= "CMP",
[OCMPS]= "CMPS",
[OCWD]= "CWD",
[ODAA]= "DAA",
[ODAS]= "DAS",
[ODEC]= "DEC",
[ODIV]= "DIV",
[OENTER]= "ENTER",
[OGP1]= "GP1",
[OGP2]= "GP2",
[OGP3b]= "GP3b",
[OGP3v]= "GP3v",
[OGP4]= "GP4",
[OGP5]= "GP5",
[OHLT]= "HLT",
[OIDIV]= "IDIV",
[OIMUL]= "IMUL",
[OIN]= "IN",
[OINC]= "INC",
[OINS]= "INS",
[OINT]= "INT",
[OIRET]= "IRET",
[OJUMP]= "JUMP",
[OLAHF]= "LAHF",
[OLFP]= "LFP",
[OLEA]= "LEA",
[OLEAVE]= "LEAVE",
[OLOCK]= "LOCK",
[OLODS]= "LODS",
[OLOOP]= "LOOP",
[OLOOPNZ]= "LOOPNZ",
[OLOOPZ]= "LOOPZ",
[OMOV]= "MOV",
[OMOVS]= "MOVS",
[OMUL]= "MUL",
[ONEG]= "NEG",
[ONOP]= "NOP",
[ONOT]= "NOT",
[OOR]= "OR",
[OOSIZE]= "OSIZE",
[OOUT]= "OUT",
[OOUTS]= "OUTS",
[OPOP]= "POP",
[OPOPA]= "POPA",
[OPOPF]= "POPF",
[OPUSH]= "PUSH",
[OPUSHA]= "PUSHA",
[OPUSHF]= "PUSHF",
[ORCL]= "RCL",
[ORCR]= "RCR",
[OREPE]= "REPE",
[OREPNE]= "REPNE",
[ORET]= "RET",
[ORETF]= "RETF",
[OROL]= "ROL",
[OROR]= "ROR",
[OSAHF]= "SAHF",
[OSAR]= "SAR",
[OSBB]= "SBB",
[OSCAS]= "SCAS",
[OSEG]= "SEG",
[OSET]= "SET",
[OSHL]= "SHL",
[OSHLD]= "SHLD",
[OSHR]= "SHR",
[OSHRD]= "SHRD",
[OSTC]= "STC",
[OSTD]= "STD",
[OSTI]= "STI",
[OSTOS]= "STOS",
[OSUB]= "SUB",
[OTEST]= "TEST",
[OWAIT]= "WAIT",
[OXCHG]= "XCHG",
[OXLAT]= "XLAT",
[OXOR]= "XOR",
NUMOP,
};
static char *littlereg[] = {
"AL", "CL", "DL", "BL", "AH", "CH", "DH", "BH"
};
static char *bigreg[] = {
"AX", "CX", "DX", "BX", "SP", "BP", "SI", "DI",
"ES", "CS", "SS", "DS", "FS", "GS",
};
static int
isstring(int a)
{
return a==AXb || a==AXv || a==AYb || a==AYv;
}
static char* memstr[] = {
"BX+SI",
"BX+DI",
"BP+SI",
"BP+DI",
"SI",
"DI",
"BP",
"BX",
};
static void
memconv(char *p, Inst *ip, Iarg*)
{
if(ip->sreg != 'D'){
sprint(p, "%cS:", ip->sreg);
p += strlen(p);
}
if(ip->mod == 0 && ip->rm == 6){
sprint(p, "[%lX]", ip->disp);
return;
}
if(ip->mod != 0)
sprint(p, "[%s%+lX]", memstr[ip->rm], ip->disp);
else
sprint(p, "[%s]", memstr[ip->rm]);
}
static void
argconv(char *p, Inst *ip, Iarg *iarg)
{
switch(iarg->atype){
default:
case ANONE: /* no argument */
strcpy(p, "<badarg>");
break;
case A0: /* constant 0 */
strcpy(p, "0");
break;
case A1: /* constant 1 */
strcpy(p, "1");
break;
case A3: /* constant 3 */
strcpy(p, "3");
break;
case A4: /* constant 4 */
strcpy(p, "4");
break;
case AAp: /* 32-bit or 48-bit direct address */
case AMp: /* 32-bit or 48-bit memory address */
sprint(p, "[%4.4X:%*.*luX]", iarg->seg, ip->opsize/4, ip->opsize/4, iarg->off);
break;
case AEp: /* call indirect through memory */
print("call\n");
memconv(p, ip, iarg);
break;
case AEb: /* r/m8 from modrm byte */
if(ip->mod == 3){
sprint(p, littlereg[iarg->seg]);
break;
}
memconv(p, ip, iarg);
break;
case AEv: /* r/m16 or r/m32 from modrm byte */
case AEw: /* r/m16 */
if(ip->mod == 3){
sprint(p, bigreg[iarg->seg]);
break;
}
memconv(p, ip, iarg);
break;
case AFv:
break;
case AGb: /* r8 from modrm byte */
sprint(p, littlereg[iarg->seg]);
break;
case AGv: /* r16 or r32 from modrm byte */
case AGw: /* r/m16 */
sprint(p, bigreg[iarg->seg]);
break;
case AIb: /* immediate byte */
case AIc: /* immediate byte sign-extended */
case AIw: /* immediate 16-bit word */
case AIv: /* immediate 16-bit or 32-bit word */
sprint(p, "%*.*lX", ip->opsize/4, ip->opsize/4, iarg->val);
break;
case AJb: /* relative offset byte */
case AJv: /* relative offset 16-bit or 32-bit word */
sprint(p, "%*.*lX", ip->addrsize/4, ip->addrsize/4, iarg->off);
break;
case AJr: /* jump through register */
sprint(p, bigreg[ip->rm]);
break;
case AM: /* memory address from modrm */
case AMa: /* something for bound */
memconv(p, ip, iarg);
break;
case AMa2:
break;
case AOb: /* immediate word-sized offset to a byte */
case AOv: /* immediate word-size offset to a word */
memconv(p, ip, iarg);
break;
case ASw: /* segment register selected by r field of modrm */
sprint(p, bigreg[iarg->seg]);
break;
case AXb: /* byte at DS:SI (should not be called) */
case AXv: /* word at DS:SI */
case AYb: /* byte at ES:DI */
case AYv: /* word at ES:DI */
abort();
case AAL: /* registers; should be in same order as RAL: etc. */
case AAH:
case ABL:
case ABH:
case ACL:
case ACH:
case ADL:
case ADH:
strcpy(p, littlereg[iarg->atype-AAL]);
break;
case AAX: /* registers; should be in same order as RAX: etc. */
case ABX:
case ACX:
case ADX:
case ABP:
case ASP:
case ADI:
case ASI:
case AES:
case ACS:
case ASS:
case ADS:
case AFS:
case AGS:
strcpy(p, bigreg[iarg->atype - AAX]);
break;
}
}
static char *jmpstr[] = {
"JO", "JNO", "JC", "JNC", "JZ", "JNZ", "JBE", "JA",
"JS", "JNS", "JP", "JNP", "JL", "JGE", "JLE", "JG",
};
int
instfmt(Fmt *fmt)
{
int x;
char buf[100];
Inst *ip;
ip = va_arg(fmt->args, Inst*);
if(ip == nil){
fmtstrcpy(fmt, "<null>");
return 0;
}
if(ip->op == OBAD || ip->op >= NUMOP){
fmtstrcpy(fmt, "ILLEGAL INSTRUCTION");
return 0;
}
buf[0] = '\0';
if(ip->repeat)
sprint(buf+strlen(buf), "%s: ", opstr[ip->repeat]);
if(ip->opsize == 32)
strcat(buf, "O32: ");
if(ip->op == OJUMP){
switch(ip->i){
case 0xE3:
strcat(buf, "JCXZ");
break;
case 0xEB:
case 0xE9:
case 0xEA:
case 0xFF:
strcat(buf, "JMP");
break;
default:
strcat(buf, jmpstr[ip->i&0xF]);
break;
}
}else
strcat(buf, opstr[ip->op]);
sprint(buf+strlen(buf), "(%c)", ip->opsize==8 ? 'B' : ip->opsize == 16 ? 'W' : 'L');
if(isstring(x=ip->arg1.atype) || isstring(x=ip->arg2.atype)){
// if(ip->opsize == 8)
// strcat(buf, "B");
// else
// strcat(buf, "W");
USED(x);
}else{
if(ip->arg1.atype){
strcat(buf, "\t");
argconv(buf+strlen(buf), ip, &ip->arg1);
}
if(ip->arg2.atype){
strcat(buf, ", ");
argconv(buf+strlen(buf), ip, &ip->arg2);
}
if(ip->arg3.atype){
strcat(buf, ", ");
argconv(buf+strlen(buf), ip, &ip->arg3);
}
}
fmtstrcpy(fmt, buf);
return 0;
}
|