winamp/Src/Wasabi/api/script/debugger/disasm.cpp

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);
}
}
}