194 lines
5.6 KiB
C++
194 lines
5.6 KiB
C++
|
#include <precomp.h>
|
||
|
#include <api/script/debugger/disasm.h>
|
||
|
#include <api/script/opcodes.h>
|
||
|
#include <api/script/vcpu.h>
|
||
|
#include <api/script/debugger/sourcecodeline.h>
|
||
|
// ---------------------------------------------------------------------
|
||
|
|
||
|
typedef struct {
|
||
|
const wchar_t *opname;
|
||
|
unsigned __int8 opval;
|
||
|
int type;
|
||
|
} opentry;
|
||
|
|
||
|
opentry _optable[] = {
|
||
|
{L"nop", OPCODE_NOP, OPCODE_TYPE_VOID},
|
||
|
{L"push", OPCODE_PUSH, OPCODE_TYPE_VAR},
|
||
|
{L"popi", OPCODE_POPI, OPCODE_TYPE_VOID},
|
||
|
{L"pop", OPCODE_POP, OPCODE_TYPE_VAR},
|
||
|
{L"set ", OPCODE_SET, OPCODE_TYPE_VOID},
|
||
|
{L"retf", OPCODE_RETF, OPCODE_TYPE_VOID},
|
||
|
{L"call", OPCODE_CALLC, OPCODE_TYPE_PTR},
|
||
|
{L"call", OPCODE_CALLM, OPCODE_TYPE_DLF},
|
||
|
{L"call", OPCODE_CALLM2, OPCODE_TYPE_NDLF},
|
||
|
{L"umv", OPCODE_UMV, OPCODE_TYPE_DISCARD},
|
||
|
{L"cmpeq", OPCODE_CMPEQ, OPCODE_TYPE_VOID},
|
||
|
{L"cmpne", OPCODE_CMPNE, OPCODE_TYPE_VOID},
|
||
|
{L"cmpa", OPCODE_CMPA, OPCODE_TYPE_VOID},
|
||
|
{L"cmpae", OPCODE_CMPAE, OPCODE_TYPE_VOID},
|
||
|
{L"cmpb", OPCODE_CMPB, OPCODE_TYPE_VOID},
|
||
|
{L"cmpbe", OPCODE_CMPBE, OPCODE_TYPE_VOID},
|
||
|
{L"jiz", OPCODE_JIZ, OPCODE_TYPE_PTR},
|
||
|
{L"jnz", OPCODE_JNZ, OPCODE_TYPE_PTR},
|
||
|
{L"jmp", OPCODE_JMP, OPCODE_TYPE_PTR},
|
||
|
{L"incs", OPCODE_INCS, OPCODE_TYPE_VOID},
|
||
|
{L"decs", OPCODE_DECS, OPCODE_TYPE_VOID},
|
||
|
{L"incp", OPCODE_INCP, OPCODE_TYPE_VOID},
|
||
|
{L"decp", OPCODE_DECP, OPCODE_TYPE_VOID},
|
||
|
{L"add", OPCODE_ADD, OPCODE_TYPE_VOID},
|
||
|
{L"sub", OPCODE_SUB, OPCODE_TYPE_VOID},
|
||
|
{L"mul", OPCODE_MUL, OPCODE_TYPE_VOID},
|
||
|
{L"div", OPCODE_DIV, OPCODE_TYPE_VOID},
|
||
|
{L"mod", OPCODE_MOD, OPCODE_TYPE_VOID},
|
||
|
{L"neg", OPCODE_NEG, OPCODE_TYPE_VOID},
|
||
|
{L"shl", OPCODE_SHL, OPCODE_TYPE_VOID},
|
||
|
{L"shr", OPCODE_SHR, OPCODE_TYPE_VOID},
|
||
|
{L"bnot", OPCODE_BNOT, OPCODE_TYPE_VOID},
|
||
|
{L"bxor", OPCODE_XOR, OPCODE_TYPE_VOID},
|
||
|
{L"band", OPCODE_AND, OPCODE_TYPE_VOID},
|
||
|
{L"bor", OPCODE_OR, OPCODE_TYPE_VOID},
|
||
|
{L"not", OPCODE_NOT, OPCODE_TYPE_VOID},
|
||
|
{L"and", OPCODE_LAND, OPCODE_TYPE_VOID},
|
||
|
{L"or", OPCODE_LOR, OPCODE_TYPE_VOID},
|
||
|
{L"del", OPCODE_DELETE, OPCODE_TYPE_VOID},
|
||
|
{L"new", OPCODE_NEW, OPCODE_TYPE_CLASSID},
|
||
|
{L"cmpl", OPCODE_CMPLT, OPCODE_TYPE_VOID},
|
||
|
};
|
||
|
|
||
|
int MakiDisassembler::optable[256];
|
||
|
int MakiDisassembler::optableready = 0;
|
||
|
|
||
|
|
||
|
MakiDisassembler::MakiDisassembler(int _vcpuid) {
|
||
|
if (!optableready) {
|
||
|
MEMSET(optable, 0, sizeof(optable));
|
||
|
for (int i=0;i<sizeof(_optable)/sizeof(opentry);i++) {
|
||
|
opentry e = _optable[i];
|
||
|
optable[e.opval] = i;
|
||
|
}
|
||
|
optableready = 1;
|
||
|
}
|
||
|
vcpuid = _vcpuid;
|
||
|
disassemble();
|
||
|
}
|
||
|
|
||
|
MakiDisassembler::~MakiDisassembler() {
|
||
|
lines.deleteAll();
|
||
|
}
|
||
|
|
||
|
int MakiDisassembler::getVCPUId() {
|
||
|
return vcpuid;
|
||
|
}
|
||
|
|
||
|
int MakiDisassembler::getNumLines() {
|
||
|
return lines.getNumItems();
|
||
|
}
|
||
|
|
||
|
SourceCodeLine *MakiDisassembler::enumLine(int n) {
|
||
|
return lines.enumItem(n);
|
||
|
}
|
||
|
|
||
|
int MakiDisassembler::findLine(int pointer) {
|
||
|
int i;
|
||
|
for (i=0;i<lines.getNumItems();i++) {
|
||
|
SourceCodeLine *l = lines.enumItem(i);
|
||
|
int ip = l->getPointer();
|
||
|
int il = l->getLength();
|
||
|
if (pointer >= ip && pointer < ip+il) {
|
||
|
return i;
|
||
|
}
|
||
|
}
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
|
||
|
void MakiDisassembler::disassemble() {
|
||
|
int size;
|
||
|
const char *codeblock = VCPU::getCodeBlock(vcpuid, &size);
|
||
|
if (codeblock != NULL) {
|
||
|
|
||
|
const char *p = codeblock;
|
||
|
|
||
|
unsigned char opcode = OPCODE_NOP;
|
||
|
|
||
|
while (p < codeblock+size) {
|
||
|
const char *start_of_instruction = p;
|
||
|
opcode = *p;
|
||
|
p+=sizeof(opcode);
|
||
|
|
||
|
StringW inst;
|
||
|
int a = optable[opcode];
|
||
|
int id;
|
||
|
int size = 0;
|
||
|
inst = _optable[a].opname;
|
||
|
switch (_optable[a].type) {
|
||
|
case OPCODE_TYPE_VOID:
|
||
|
size = 1;
|
||
|
break;
|
||
|
case OPCODE_TYPE_VAR:
|
||
|
id = *(int *)p; p+=sizeof(int);
|
||
|
inst += StringPrintfW(L" var %08X", id);
|
||
|
size = 5;
|
||
|
break;
|
||
|
case OPCODE_TYPE_PTR:
|
||
|
id = *(int *)p; p+=sizeof(int);
|
||
|
inst += StringPrintfW(L" %08X", id+(p-codeblock));
|
||
|
size = 5;
|
||
|
break;
|
||
|
case OPCODE_TYPE_DLF: {
|
||
|
id = *(int *)p; p+=sizeof(int);
|
||
|
int np = *(int *)p;
|
||
|
if ((np & 0xFFFF0000) == 0xFFFF0000) {
|
||
|
p+=sizeof(int);
|
||
|
np &= 0xFFFF;
|
||
|
} else
|
||
|
np = -1;
|
||
|
int i = VCPU::dlfBase(vcpuid)+id;
|
||
|
if (i != -1) {
|
||
|
VCPUdlfEntry *e = VCPU::DLFentryTable.enumItem(i);
|
||
|
if (e != NULL) {
|
||
|
if (np != -1) inst += StringPrintfW(L"(%d)", np);
|
||
|
inst += L" ";
|
||
|
inst += e->functionName;
|
||
|
}
|
||
|
}
|
||
|
size = 5 + ((np == -1) ? 0 : 4);
|
||
|
break;
|
||
|
}
|
||
|
case OPCODE_TYPE_NDLF: {
|
||
|
id = *(int *)p; p+=sizeof(int);
|
||
|
int np = *p; p++;
|
||
|
int i = VCPU::dlfBase(vcpuid)+id;
|
||
|
if (i != -1) {
|
||
|
VCPUdlfEntry *e = VCPU::DLFentryTable.enumItem(i);
|
||
|
if (e != NULL) {
|
||
|
inst += StringPrintfW(L"(%d) ", np);
|
||
|
inst += e->functionName;
|
||
|
}
|
||
|
}
|
||
|
size = 6;
|
||
|
break;
|
||
|
}
|
||
|
case OPCODE_TYPE_CLASSID: {
|
||
|
id = *(int *)p; p+=sizeof(int);
|
||
|
const wchar_t *cn = WASABI_API_MAKI->vcpu_getClassName(vcpuid, id);
|
||
|
inst += L" ";
|
||
|
inst += cn;
|
||
|
size = 5;
|
||
|
break;
|
||
|
}
|
||
|
case OPCODE_TYPE_DISCARD:
|
||
|
id = *(int *)p; p+=sizeof(int);
|
||
|
size = 5;
|
||
|
break;
|
||
|
}
|
||
|
SourceCodeLineI *scl = new SourceCodeLineI();
|
||
|
scl->setLine(inst),
|
||
|
scl->setPointer(start_of_instruction-codeblock);
|
||
|
scl->setLength(size);
|
||
|
lines.addItem(scl);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|