| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509 |
- // Copyright (C) 2012 Zeex
- //
- // Permission is hereby granted, free of charge, to any person obtaining a
- // copy of this software and associated documentation files (the "Software"),
- // to deal in the Software without restriction, including without limitation
- // the rights to use, copy, modify, merge, publish, distribute, sublicense,
- // and/or sell copies of the Software, and to permit persons to whom the
- // Software is furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- // DEALINGS IN THE SOFTWARE.
- #if defined DISASM_INC
- #endinput
- #endif
- #define DISASM_INC
- #include <string>
- #include "amx_base"
- #include "amx_header"
- #include "amx_memory"
- #include "opcode"
- #define DISASM_MAX_INSN_NAME 15
- #define DISASM_MAX_PUBLIC_NAME 32
- #define DISASM_MAX_NATIVE_NAME 100
- enum DisasmInsnInfo {
- DisasmInsnInfo_name[DISASM_MAX_INSN_NAME],
- DisasmInsnInfo_num_opers,
- bool:DisasmInsnInfo_needs_reloc
- }
- enum DisasmContext {
- DisasmContext_start_ip,
- DisasmContext_end_ip,
- DisasmContext_nip,
- DisasmContext_cip,
- Opcode:DisasmContext_opcode,
- DisasmContext_insn[DisasmInsnInfo]
- }
- static stock const insn_table[][DisasmInsnInfo] = {
- { "none", 0, false },
- { "load.pri", 1, false },
- { "load.alt", 1, false },
- { "load.s.pri", 1, false },
- { "load.s.alt", 1, false },
- { "lref.pri", 1, false },
- { "lref.alt", 1, false },
- { "lref.s.pri", 1, false },
- { "lref.s.alt", 1, false },
- { "load.i", 0, false },
- { "lodb.i", 1, false },
- { "const.pri", 1, false },
- { "const.alt", 1, false },
- { "addr.pri", 1, false },
- { "addr.alt", 1, false },
- { "stor.pri", 1, false },
- { "stor.alt", 1, false },
- { "stor.s.pri", 1, false },
- { "stor.s.alt", 1, false },
- { "sref.pri", 1, false },
- { "sref.alt", 1, false },
- { "sref.s.pri", 1, false },
- { "sref.s.alt", 1, false },
- { "stor.i", 0, false },
- { "strb.i", 1, false },
- { "lidx", 0, false },
- { "lidx.b", 1, false },
- { "idxaddr", 0, false },
- { "idxaddr.b", 1, false },
- { "align.pri", 1, false },
- { "align.alt", 1, false },
- { "lctrl", 1, false },
- { "sctrl", 1, false },
- { "move.pri", 0, false },
- { "move.alt", 0, false },
- { "xchg", 0, false },
- { "push.pri", 0, false },
- { "push.alt", 0, false },
- { "push.r", 1, false },
- { "push.c", 1, false },
- { "push", 1, false },
- { "push.s", 1, false },
- { "pop.pri", 0, false },
- { "pop.alt", 0, false },
- { "stack", 1, false },
- { "heap", 1, false },
- { "proc", 0, false },
- { "ret", 0, false },
- { "retn", 0, false },
- { "call", 1, true },
- { "call.pri", 0, false },
- { "jump", 1, true },
- { "jrel", 1, true },
- { "jzer", 1, true },
- { "jnz", 1, true },
- { "jeq", 1, true },
- { "jneq", 1, true },
- { "jless", 1, true },
- { "jleq", 1, true },
- { "jgrtr", 1, true },
- { "jgeq", 1, true },
- { "jsless", 1, true },
- { "jsleq", 1, true },
- { "jsgrtr", 1, true },
- { "jsgeq", 1, true },
- { "shl", 0, false },
- { "shr", 0, false },
- { "sshr", 0, false },
- { "shl.c.pri", 1, false },
- { "shl.c.alt", 1, false },
- { "shr.c.pri", 1, false },
- { "shr.c.alt", 1, false },
- { "smul", 0, false },
- { "sdiv", 0, false },
- { "sdiv.alt", 0, false },
- { "umul", 0, false },
- { "udiv", 0, false },
- { "udiv.alt", 0, false },
- { "add", 0, false },
- { "sub", 0, false },
- { "sub.alt", 0, false },
- { "and", 0, false },
- { "or", 0, false },
- { "xort", 0, false },
- { "not", 0, false },
- { "neg", 0, false },
- { "invert", 0, false },
- { "add.c", 1, false },
- { "smul.c", 1, false },
- { "zero.pri", 0, false },
- { "zero.alt", 0, false },
- { "zero", 1, false },
- { "zero.s", 1, false },
- { "sign.pri", 0, false },
- { "sign.alt", 0, false },
- { "eq", 0, false },
- { "neq", 0, false },
- { "less", 0, false },
- { "leq", 0, false },
- { "grtr", 0, false },
- { "geq", 0, false },
- { "sless", 0, false },
- { "sleq", 0, false },
- { "sgrtr", 0, false },
- { "sgeq", 0, false },
- { "eq.c.pri", 1, false },
- { "eq.c.alt", 1, false },
- { "inc.pri", 0, false },
- { "inc.alt", 0, false },
- { "inc", 1, false },
- { "inc.s", 1, false },
- { "inc.i", 0, false },
- { "dec.pri", 0, false },
- { "dec.alt", 0, false },
- { "dec", 1, false },
- { "dec.s", 1, false },
- { "dec.i", 0, false },
- { "movs", 1, false },
- { "cmps", 1, false },
- { "fill", 1, false },
- { "halt", 1, false },
- { "bounds", 1, false },
- { "sysreq.pri", 1, false },
- { "sysreq.c", 1, false },
- { "file", -1, false }, // obsolete
- { "line", -1, false }, // obsolete
- { "symbol", -1, false }, // obsolete
- { "srange", -1, false }, // obsolete
- { "jump.pri", 0, false },
- { "switch", 1, true },
- { "casetbl", -1, true },
- { "swap.pri", 0, false },
- { "swap.alt", 0, false },
- { "push.adr", 1, false },
- { "nop", 0, false },
- { "sysreq.d", 1, false },
- { "symtag", 1, false }, // obsolete
- { "break", 0, false }
- };
- stock DisasmInit(ctx[DisasmContext], start = 0, end = 0) {
- new hdr[AMX_HDR];
- GetAmxHeader(hdr);
- new dat = hdr[AMX_HDR_DAT];
- new cod = hdr[AMX_HDR_COD];
- new code_base = cod - dat;
- start += code_base;
- ctx[DisasmContext_nip] = start;
- ctx[DisasmContext_cip] = start;
- ctx[DisasmContext_start_ip] = start;
- if (end != 0) {
- ctx[DisasmContext_end_ip] = code_base + end;
- } else {
- ctx[DisasmContext_end_ip] = code_base + (dat - cod);
- }
- }
- stock bool:DisasmDecodeInsn(ctx[DisasmContext]) {
- new ip = ctx[DisasmContext_nip];
- if (ip >= 0) {
- return false;
- }
- new Opcode:opcode = UnrelocateOpcode(Opcode:ReadAmxMemory(ip));
- if (opcode <= OP_NONE || _:opcode >= NUM_OPCODES) {
- return false;
- }
- ctx[DisasmContext_cip] = ip;
- ctx[DisasmContext_opcode] = opcode;
- ctx[DisasmContext_insn] = insn_table[_:opcode];
- ip += 4;
- if (opcode == OP_CASETBL) {
- new n = ReadAmxMemory(ip);
- ip += 4;
- ip += (2 * n + 1) * 4;
- ctx[DisasmContext_insn][DisasmInsnInfo_num_opers] = n;
- } else {
- ip += 4 * insn_table[_:opcode][DisasmInsnInfo_num_opers];
- }
- ctx[DisasmContext_nip] = ip;
- return true;
- }
- stock Opcode:DisasmNextInsn(ctx[DisasmContext]) {
- if (DisasmDecodeInsn(ctx)) {
- return ctx[DisasmContext_opcode];
- }
- return OP_NONE;
- }
- stock Opcode:DisasmGetOpcode(ctx[DisasmContext]) {
- return ctx[DisasmContext_opcode];
- }
- stock DisasmGetOperand(ctx[DisasmContext], index = 0) {
- return ReadAmxMemory(ctx[DisasmContext_cip] + (index + 1) * 4);
- }
- stock DisasmGetNumOperands(ctx[DisasmContext]) {
- return ctx[DisasmContext_insn][DisasmInsnInfo_num_opers];
- }
- stock bool:DisasmNeedReloc(ctx[DisasmContext]) {
- return ctx[DisasmContext_insn][DisasmInsnInfo_needs_reloc];
- }
- stock DisasmGetNextIp(ctx[DisasmContext]) {
- return ctx[DisasmContext_nip];
- }
- stock DisasmGetCurIp(ctx[DisasmContext]) {
- return ctx[DisasmContext_cip];
- }
- stock DisasmGetInsnName(ctx[DisasmContext], name[], size = sizeof(name)) {
- name[0] = '\0';
- strcat(name, ctx[DisasmContext_insn][DisasmInsnInfo_name], size);
- }
- static stock ToHexStr(x) {
- new s[11];
- new i = 0;
- new j = 0;
- while (i < sizeof(s) && j < 8) {
- new n = x >> (7 - j) * 4 & 0xF;
- switch (n) {
- case 0x0..0x9:
- s[i] = n + '0';
- case 0xA..0xF:
- s[i] = n + 'a' - 0xA;
- }
- i++;
- j++;
- }
- return s;
- }
- static stock bool:IsPrintableAscii(c) {
- return 32 <= c <= 126;
- }
- static stock ToPrintableAscii(c) {
- return IsPrintableAscii(c) ? c : ' ';
- }
- stock DisasmWriteCode(File:file) {
- new ctx[DisasmContext];
- DisasmInit(ctx);
- new base = GetAmxBaseAddress();
- new hdr[AMX_HDR];
- GetAmxHeader(hdr);
- new dat = hdr[AMX_HDR_DAT];
- new cod = hdr[AMX_HDR_COD];
- fwrite(file, "; CODE\n\n");
- while (DisasmGetNextIp(ctx) < ctx[DisasmContext_end_ip])
- {
- if (!DisasmDecodeInsn(ctx)) {
- new cip = DisasmGetNextIp(ctx);
- ctx[DisasmContext_nip] += 4;
- fwrite(file, ToHexStr(cip + dat - cod));
- fwrite(file, " ???? ");
- fwrite(file, ToHexStr(ReadAmxMemory(cip)));
- fwrite(file, "\n");
- continue;
- }
- new Opcode:opcode = DisasmGetOpcode(ctx);
- if (opcode == OP_PROC) {
- fwrite(file, "\n");
- }
- new cip = DisasmGetCurIp(ctx);
- new insn_name[DISASM_MAX_INSN_NAME];
- DisasmGetInsnName(ctx, insn_name);
- fwrite(file, ToHexStr(cip + dat - cod));
- fwrite(file, " ");
- fwrite(file, insn_name);
- fwrite(file, " ");
- switch (opcode) {
- case OP_PROC: {
- new name[32];
- new address = cip + dat - cod;
- if (address == hdr[AMX_HDR_CIP]) {
- strcat(name, "main");
- } else {
- new index = GetPublicIndexFromAddress(address);
- if (index >= 0) {
- GetPublicNameFromIndex(index, name);
- }
- }
- if (strlen(name) != 0) {
- fwrite(file, "; ");
- fwrite(file, name);
- }
- }
- case OP_CASETBL: {
- new num = DisasmGetNumOperands(ctx);
- fwrite(file, ToHexStr(num));
- fwrite(file, " ");
- new rel_addr = DisasmGetOperand(ctx, 1) - (base + cod);
- fwrite(file, ToHexStr(rel_addr));
- for (new i = 1; i <= num; i++) {
- fwrite(file, "\n case ");
- new val = DisasmGetOperand(ctx, i * 2);
- fwrite(file, ToHexStr(val));
- fwrite(file, " ");
- rel_addr = DisasmGetOperand(ctx, i * 2 + 1) - (base + cod);
- fwrite(file, ToHexStr(rel_addr));
- }
- }
- case OP_CALL: {
- new name[DISASM_MAX_PUBLIC_NAME];
- new address = DisasmGetOperand(ctx) - base - cod;
- if (address == hdr[AMX_HDR_CIP]) {
- strcat(name, "main");
- } else {
- new index = GetPublicIndexFromAddress(address);
- if (index >= 0) {
- GetPublicNameFromIndex(index, name);
- }
- }
- fwrite(file, ToHexStr(address));
- if (strlen(name) > 0) {
- fwrite(file, "; ");
- fwrite(file, name);
- }
- }
- case OP_SYSREQ_C, OP_SYSREQ_D: {
- new name[DISASM_MAX_NATIVE_NAME];
- new address = DisasmGetOperand(ctx);
- if (opcode == OP_SYSREQ_C) {
- new index = DisasmGetOperand(ctx);
- GetNativeNameFromIndex(index, name);
- } else {
- new index = GetNativeIndexFromAddress(address);
- if (index >= 0) {
- GetNativeNameFromIndex(index, name);
- }
- }
- fwrite(file, ToHexStr(address));
- if (strlen(name) > 0) {
- fwrite(file, "; ");
- fwrite(file, name);
- }
- }
- default: {
- new n = DisasmGetNumOperands(ctx);
- for (new i = 0; i < n; i++) {
- new operand = DisasmGetOperand(ctx, i);
- if (DisasmNeedReloc(ctx)) {
- operand -= base + cod;
- }
- fwrite(file, ToHexStr(operand));
- }
- }
- }
- fwrite(file, "\n");
- }
- }
- stock DisasmWriteDataRowChar(File:file, start, num, max) {
- new cur = start;
- new end = start + num*4;
- while (cur < max) {
- new p[4 char + 1];
- p[0] = ReadAmxMemory(cur);
- new u[4 + 1];
- u[0] = ToPrintableAscii(p{0});
- u[1] = ToPrintableAscii(p{1});
- u[2] = ToPrintableAscii(p{2});
- u[3] = ToPrintableAscii(p{3});
- u[4] = '\0';
- if (cur < end) {
- fwrite(file, u);
- } else {
- fwrite(file, " ");
- }
- cur += 4;
- }
- }
- stock DisasmWriteDataRowHex(File:file, start, num, max) {
- new cur = start;
- new end = start + num*4;
- while (cur < max) {
- if (cur < end) {
- fwrite(file, ToHexStr(ReadAmxMemory(cur)));
- } else {
- fwrite(file, " ");
- }
- fwrite(file, " ");
- cur += 4;
- }
- }
- stock DisasmWriteData(File:file) {
- fwrite(file, "\n\n; DATA\n");
- new hdr[AMX_HDR];
- GetAmxHeader(hdr);
- new dat = hdr[AMX_HDR_DAT];
- new hea = hdr[AMX_HDR_HEA];
- new data_end = hea - dat;
- for (new i = 0; i < data_end; i += 0x10) {
- fwrite(file, ToHexStr(i));
- fwrite(file, " ");
- DisasmWriteDataRowHex(file, i, 4, min(i + 0x10, data_end));
- fwrite(file, " ");
- DisasmWriteDataRowChar(file, i, 4, min(i + 0x10, data_end));
- fwrite(file, "\n");
- }
- }
- stock DisasmWriteFile(File:file) {
- DisasmWriteCode(file);
- DisasmWriteData(file);
- }
- stock bool:DisasmWrite(const filename[]) {
- new File:file = fopen(filename, io_write);
- if (file) {
- DisasmWriteFile(file);
- fclose(file);
- return true;
- }
- return false;
- }
- stock DisasmDump(const filename[]) {
- DisasmWrite(filename);
- }
|