397 lines
6.6 KiB
C
397 lines
6.6 KiB
C
#include <u.h>
|
|
#include <lib9.h>
|
|
#include "dat.h"
|
|
#include "fns.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",
|
|
[OBTC]= "BTC",
|
|
[OBTR]= "BTR",
|
|
[OBTS]= "BTS",
|
|
[OBSF]= "BSF",
|
|
[OBSR]= "BSR",
|
|
[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",
|
|
[OMOVZX]= "MOVZX",
|
|
[OMOVSX]= "MOVSX",
|
|
[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",
|
|
};
|
|
|
|
static char *memstr16[] = {
|
|
"BX+SI",
|
|
"BX+DI",
|
|
"BP+SI",
|
|
"BP+DI",
|
|
"SI",
|
|
"DI",
|
|
"BP",
|
|
"BX",
|
|
};
|
|
|
|
static char *memstr32[] = {
|
|
"EAX",
|
|
"ECX",
|
|
"EDX",
|
|
"EBX",
|
|
"0",
|
|
"EBP",
|
|
"ESI",
|
|
"EDI",
|
|
};
|
|
|
|
static int
|
|
argconv(char *p, Inst *i, Iarg *a)
|
|
{
|
|
print_func_entry();
|
|
jmp_buf jmp;
|
|
char *s;
|
|
|
|
s = p;
|
|
switch(a->tag){
|
|
default:
|
|
abort();
|
|
|
|
case TCON:
|
|
print_func_exit();
|
|
return sprint(p, "%lud", a->val);
|
|
case TREG:
|
|
case TREG|TH:
|
|
switch(a->len){
|
|
case 1:
|
|
print_func_exit();
|
|
return sprint(p, "%c%c", "ACDB"[a->reg], "LH"[(a->tag & TH) != 0]);
|
|
case 4:
|
|
*p++ = 'E';
|
|
case 2:
|
|
p += sprint(p, "%c%c",
|
|
"ACDBSBSDECSDFGIF"[a->reg],
|
|
"XXXXPPIISSSSSSPL"[a->reg]);
|
|
print_func_exit();
|
|
return p - s;
|
|
}
|
|
case TMEM:
|
|
break;
|
|
}
|
|
|
|
/* setup trap jump in case we dereference bad memory */
|
|
memmove(jmp, a->cpu->jmp, sizeof jmp);
|
|
if(setjmp(a->cpu->jmp)){
|
|
p += sprint(p, "<%.4lux:%.4lux>", a->seg, a->off);
|
|
goto out;
|
|
}
|
|
|
|
switch(a->atype){
|
|
default:
|
|
abort();
|
|
|
|
case AAp:
|
|
p += sprint(p, "[%.4lux:%.4lux]", a->seg, a->off);
|
|
break;
|
|
|
|
case AJb:
|
|
case AJv:
|
|
p += sprint(p, "[%.4lux]", a->off);
|
|
break;
|
|
|
|
case AIc:
|
|
p += sprint(p, "$%.2lx", ars(a));
|
|
break;
|
|
case AIb:
|
|
case AIw:
|
|
case AIv:
|
|
p += sprint(p, "$%.*lux", (int)a->len*2, ar(a));
|
|
break;
|
|
|
|
case AMp:
|
|
*p++ = '*';
|
|
case AEb:
|
|
case AEw:
|
|
case AEv:
|
|
case AM:
|
|
case AMa:
|
|
case AMa2:
|
|
case AOb:
|
|
case AOv:
|
|
if(i->sreg != RDS)
|
|
p += sprint(p, "%cS:", "ECSDFG"[i->sreg - RES]);
|
|
if(a->atype == AOb || a->atype == AOv || (i->mod == 0 &&
|
|
(i->alen == 2 && i->rm == 6) ||
|
|
(i->alen == 4 && ((i->rm == 5) ||
|
|
(i->rm == 4 && i->index == 4 && i->base == 5))))){
|
|
p += sprint(p, "[%.*lux]", (int)i->alen*2, a->off);
|
|
break;
|
|
}
|
|
*p++ = '[';
|
|
if(i->alen == 2)
|
|
p += sprint(p, "%s", memstr16[i->rm]);
|
|
else{
|
|
if(i->rm == 4){
|
|
if(i->index != 4)
|
|
p += sprint(p, "%c*%s+", "1248"[i->scale], memstr32[i->index]);
|
|
if(i->base != 5)
|
|
p += sprint(p, "%s", memstr32[i->base]);
|
|
else{
|
|
if(i->mod == 0)
|
|
p += sprint(p, "%.4lux", i->off);
|
|
else
|
|
p += sprint(p, "EBP");
|
|
}
|
|
} else
|
|
p += sprint(p, "%s", memstr32[i->rm]);
|
|
}
|
|
if(i->mod != 0)
|
|
p += sprint(p, "%+lx", i->disp);
|
|
*p++ = ']';
|
|
break;
|
|
|
|
case AXb:
|
|
case AXv:
|
|
if(a->sreg != RDS)
|
|
p += sprint(p, "%cS:", "ECSDFG"[a->sreg - RES]);
|
|
p += sprint(p, "[SI]");
|
|
break;
|
|
case AYb:
|
|
case AYv:
|
|
if(a->sreg != RDS)
|
|
p += sprint(p, "%cS:", "ECSDFG"[a->sreg - RES]);
|
|
p += sprint(p, "[DI]");
|
|
break;
|
|
}
|
|
|
|
out:
|
|
memmove(a->cpu->jmp, jmp, sizeof jmp);
|
|
*p = 0;
|
|
print_func_exit();
|
|
return p - s;
|
|
}
|
|
|
|
static char *jmpstr[] = {
|
|
"JO", "JNO", "JC", "JNC", "JZ", "JNZ", "JBE", "JA",
|
|
"JS", "JNS", "JP", "JNP", "JL", "JGE", "JLE", "JG",
|
|
};
|
|
|
|
int
|
|
instfmt(Fmt *fmt)
|
|
{
|
|
print_func_entry();
|
|
Inst *i;
|
|
char *p, buf[256];
|
|
|
|
i = va_arg(fmt->args, Inst*);
|
|
p = buf;
|
|
|
|
if(i->olen == 4)
|
|
p += sprint(p, "O32: ");
|
|
if(i->alen == 4)
|
|
p += sprint(p, "A32: ");
|
|
if(i->rep)
|
|
p += sprint(p, "%s: ", opstr[i->rep]);
|
|
|
|
if(i->op == OXLAT && i->sreg != RDS)
|
|
p += sprint(p, "%cS:", "ECSDFG"[i->sreg - RES]);
|
|
|
|
if(i->op == OJUMP){
|
|
switch(i->code){
|
|
case 0xE3:
|
|
p += sprint(p, "%s ", "JCXZ");
|
|
break;
|
|
case 0xEB:
|
|
case 0xE9:
|
|
case 0xEA:
|
|
case 0xFF:
|
|
p += sprint(p, "%s ", "JMP");
|
|
break;
|
|
default:
|
|
p += sprint(p, "%s ", jmpstr[i->code&0xF]);
|
|
break;
|
|
}
|
|
} else
|
|
p += sprint(p, "%s ", opstr[i->op]);
|
|
|
|
|
|
for(;;){
|
|
if(i->a1 == nil)
|
|
break;
|
|
p += argconv(p, i, i->a1);
|
|
if(i->a2 == nil)
|
|
break;
|
|
*p++ = ',';
|
|
*p++ = ' ';
|
|
p += argconv(p, i, i->a2);
|
|
if(i->a3 == nil)
|
|
break;
|
|
*p++ = ',';
|
|
*p++ = ' ';
|
|
p += argconv(p, i, i->a3);
|
|
break;
|
|
}
|
|
*p = 0;
|
|
fmtstrcpy(fmt, buf);
|
|
print_func_exit();
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
flagfmt(Fmt *fmt)
|
|
{
|
|
print_func_entry();
|
|
char buf[16];
|
|
unsigned long f;
|
|
|
|
f = va_arg(fmt->args, unsigned long);
|
|
sprint(buf, "%c%c%c%c%c%c%c",
|
|
(f & CF) ? 'C' : 'c',
|
|
(f & SF) ? 'S' : 's',
|
|
(f & ZF) ? 'Z' : 'z',
|
|
(f & OF) ? 'O' : 'o',
|
|
(f & PF) ? 'P' : 'p',
|
|
(f & DF) ? 'D' : 'd',
|
|
(f & IF) ? 'I' : 'i');
|
|
fmtstrcpy(fmt, buf);
|
|
print_func_exit();
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
cpufmt(Fmt *fmt)
|
|
{
|
|
print_func_entry();
|
|
char buf[512];
|
|
jmp_buf jmp;
|
|
Cpu *cpu;
|
|
Inst i;
|
|
|
|
cpu = va_arg(fmt->args, Cpu*);
|
|
|
|
memmove(jmp, cpu->jmp, sizeof jmp);
|
|
if(setjmp(cpu->jmp) == 0)
|
|
decode(amem(cpu, 1, RCS, cpu->reg[RIP]), &i);
|
|
memmove(cpu->jmp, jmp, sizeof jmp);
|
|
|
|
snprint(buf, sizeof(buf),
|
|
"%.6lux "
|
|
"%.8lux %.8lux %.8lux %.8lux %.8lux %.8lux %.8lux %.8lux "
|
|
"%.4lux %.4lux %.4lux %.4lux "
|
|
"%J %.4lux %.2ux %I",
|
|
|
|
cpu->ic,
|
|
|
|
cpu->reg[RAX],
|
|
cpu->reg[RBX],
|
|
cpu->reg[RCX],
|
|
cpu->reg[RDX],
|
|
|
|
cpu->reg[RDI],
|
|
cpu->reg[RSI],
|
|
|
|
cpu->reg[RBP],
|
|
cpu->reg[RSP],
|
|
|
|
cpu->reg[RDS],
|
|
cpu->reg[RES],
|
|
cpu->reg[RSS],
|
|
cpu->reg[RCS],
|
|
|
|
cpu->reg[RFL],
|
|
cpu->reg[RIP],
|
|
|
|
i.code,
|
|
&i);
|
|
|
|
fmtstrcpy(fmt, buf);
|
|
print_func_exit();
|
|
return 0;
|
|
}
|