From 6cbc4203b5cd59690d40c96673418508eb61f980 Mon Sep 17 00:00:00 2001 From: Zeex Date: Fri, 29 Aug 2014 22:38:56 +0700 Subject: [PATCH] Backport pawndisasm from Pawn 3.3.3875 --- source/compiler/CMakeLists.txt | 4 +- source/compiler/pawndisasm.c | 579 +++++++++++++++++++++++++++++++++ 2 files changed, 582 insertions(+), 1 deletion(-) create mode 100644 source/compiler/pawndisasm.c diff --git a/source/compiler/CMakeLists.txt b/source/compiler/CMakeLists.txt index 8c1a85a..c206e6d 100644 --- a/source/compiler/CMakeLists.txt +++ b/source/compiler/CMakeLists.txt @@ -61,7 +61,6 @@ IF(UNIX AND NOT CMAKE_BUILD_TYPE STREQUAL "Debug") ADD_CUSTOM_COMMAND(TARGET pawnc POST_BUILD COMMAND strip ARGS -K pc_compile -K pc_addconstant -K pc_addtag -K pc_enablewarning ${CMAKE_BINARY_DIR}/libpawnc.so) ENDIF(UNIX AND NOT CMAKE_BUILD_TYPE STREQUAL "Debug") - # The Pawn compiler driver (console program) SET(PAWNCC_SRCS pawncc.c) IF(WIN32) @@ -76,3 +75,6 @@ IF(WIN32) ENDIF(WIN32) ADD_EXECUTABLE(pawncc ${PAWNCC_SRCS}) TARGET_LINK_LIBRARIES(pawncc pawnc) + +# The Pawn disassembler +ADD_EXECUTABLE(pawndisasm pawndisasm.c) diff --git a/source/compiler/pawndisasm.c b/source/compiler/pawndisasm.c new file mode 100644 index 0000000..1280dbc --- /dev/null +++ b/source/compiler/pawndisasm.c @@ -0,0 +1,579 @@ +/* Pawn disassembler - crude, but (perhaps) useful + * + * Copyright (c) ITB CompuPhase, 2007 + * + * This software is provided "as-is", without any express or implied warranty. + * In no event will the authors be held liable for any damages arising from + * the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software in + * a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * + * Version: $Id$ + */ +#include +#include +#include +#include +#include "../amx/amx.h" + +static FILE *fpamx; +static AMX_HEADER amxhdr; + +typedef cell (*OPCODE_PROC)(FILE *ftxt,const cell *params,cell opcode,cell cip); + +cell parm0(FILE *ftxt,const cell *params,cell opcode,cell cip); +cell parm1(FILE *ftxt,const cell *params,cell opcode,cell cip); +cell parm2(FILE *ftxt,const cell *params,cell opcode,cell cip); +cell parm3(FILE *ftxt,const cell *params,cell opcode,cell cip); +cell parm4(FILE *ftxt,const cell *params,cell opcode,cell cip); +cell parm5(FILE *ftxt,const cell *params,cell opcode,cell cip); +cell parm1_p(FILE *ftxt,const cell *params,cell opcode,cell cip); +cell do_proc(FILE *ftxt,const cell *params,cell opcode,cell cip); +cell do_call(FILE *ftxt,const cell *params,cell opcode,cell cip); +cell do_jump(FILE *ftxt,const cell *params,cell opcode,cell cip); +cell do_switch(FILE *ftxt,const cell *params,cell opcode,cell cip); +cell casetbl(FILE *ftxt,const cell *params,cell opcode,cell cip); +cell icasetbl(FILE *ftxt,const cell *params,cell opcode,cell cip); +cell do_file(FILE *ftxt,const cell *params,cell opcode,cell cip); +cell do_symbol(FILE *ftxt,const cell *params,cell opcode,cell cip); + + +typedef struct { + cell opcode; + char *name; + OPCODE_PROC func; +} OPCODE; + +static OPCODE opcodelist[] = { + { 0, "???", parm0 }, + { 1, "load.pri", parm1 }, + { 2, "load.alt", parm1 }, + { 3, "load.s.pri", parm1 }, + { 4, "load.s.alt", parm1 }, + { 5, "lref.pri", parm1 }, + { 6, "lref.alt", parm1 }, + { 7, "lref.s.pri", parm1 }, + { 8, "lref.s.alt", parm1 }, + { 9, "load.i", parm0 }, + { 10, "lodb.i", parm1 }, + { 11, "const.pri", parm1 }, + { 12, "const.alt", parm1 }, + { 13, "addr.pri", parm1 }, + { 14, "addr.alt", parm1 }, + { 15, "stor.pri", parm1 }, + { 16, "stor.alt", parm1 }, + { 17, "stor.s.pri", parm1 }, + { 18, "stor.s.alt", parm1 }, + { 19, "sref.pri", parm1 }, + { 20, "sref.alt", parm1 }, + { 21, "sref.s.pri", parm1 }, + { 22, "sref.s.alt", parm1 }, + { 23, "stor.i", parm0 }, + { 24, "strb.i", parm1 }, + { 25, "lidx", parm0 }, + { 26, "lidx.b", parm1 }, + { 27, "idxaddr", parm0 }, + { 28, "idxaddr.b", parm1 }, + { 29, "align.pri", parm1 }, + { 30, "align.alt", parm1 }, + { 31, "lctrl", parm1 }, + { 32, "sctrl", parm1 }, + { 33, "move.pri", parm0 }, + { 34, "move.alt", parm0 }, + { 35, "xchg", parm0 }, + { 36, "push.pri", parm0 }, + { 37, "push.alt", parm0 }, + { 38, "push.r", parm1 }, /* obsolete (never generated) */ + { 39, "push.c", parm1 }, + { 40, "push", parm1 }, + { 41, "push.s", parm1 }, + { 42, "pop.pri", parm0 }, + { 43, "pop.alt", parm0 }, + { 44, "stack", parm1 }, + { 45, "heap", parm1 }, + { 46, "proc", do_proc }, + { 47, "ret", parm0 }, + { 48, "retn", parm0 }, + { 49, "call", do_call }, + { 50, "call.pri", parm0 }, + { 51, "jump", do_jump }, + { 52, "jrel", parm1 }, /* same as jump, since version 10 */ + { 53, "jzer", do_jump }, + { 54, "jnz", do_jump }, + { 55, "jeq", do_jump }, + { 56, "jneq", do_jump }, + { 57, "jless", do_jump }, + { 58, "jleq", do_jump }, + { 59, "jgrtr", do_jump }, + { 60, "jgeq", do_jump }, + { 61, "jsless", do_jump }, + { 62, "jsleq", do_jump }, + { 63, "jsgrtr", do_jump }, + { 64, "jsgeq", do_jump }, + { 65, "shl", parm0 }, + { 66, "shr", parm0 }, + { 67, "sshr", parm0 }, + { 68, "shl.c.pri", parm1 }, + { 69, "shl.c.alt", parm1 }, + { 70, "shr.c.pri", parm1 }, + { 71, "shr.c.alt", parm1 }, + { 72, "smul", parm0 }, + { 73, "sdiv", parm0 }, + { 74, "sdiv.alt", parm0 }, + { 75, "umul", parm0 }, + { 76, "udiv", parm0 }, + { 77, "udiv.alt", parm0 }, + { 78, "add", parm0 }, + { 79, "sub", parm0 }, + { 80, "sub.alt", parm0 }, + { 81, "and", parm0 }, + { 82, "or", parm0 }, + { 83, "xor", parm0 }, + { 84, "not", parm0 }, + { 85, "neg", parm0 }, + { 86, "invert", parm0 }, + { 87, "add.c", parm1 }, + { 88, "smul.c", parm1 }, + { 89, "zero.pri", parm0 }, + { 90, "zero.alt", parm0 }, + { 91, "zero", parm1 }, + { 92, "zero.s", parm1 }, + { 93, "sign.pri", parm0 }, + { 94, "sign.alt", parm0 }, + { 95, "eq", parm0 }, + { 96, "neq", parm0 }, + { 97, "less", parm0 }, + { 98, "leq", parm0 }, + { 99, "grtr", parm0 }, + {100, "geq", parm0 }, + {101, "sless", parm0 }, + {102, "sleq", parm0 }, + {103, "sgrtr", parm0 }, + {104, "sgeq", parm0 }, + {105, "eq.c.pri", parm1 }, + {106, "eq.c.alt", parm1 }, + {107, "inc.pri", parm0 }, + {108, "inc.alt", parm0 }, + {109, "inc", parm1 }, + {110, "inc.s", parm1 }, + {111, "inc.i", parm0 }, + {112, "dec.pri", parm0 }, + {113, "dec.alt", parm0 }, + {114, "dec", parm1 }, + {115, "dec.s", parm1 }, + {116, "dec.i", parm0 }, + {117, "movs", parm1 }, + {118, "cmps", parm1 }, + {119, "fill", parm1 }, + {120, "halt", parm1 }, + {121, "bounds", parm1 }, + {122, "sysreq.pri", parm0 }, + {123, "sysreq.c", parm1 }, + {124, "file", do_file }, + {125, "line", parm2 }, + {126, "symbol", do_symbol }, + {127, "srange", parm2 }, /* version 1 */ + {128, "jump.pri", parm0 }, /* version 1 */ + {129, "switch", do_switch }, /* version 1 */ + {130, "casetbl", casetbl }, /* version 1 */ + {131, "swap.pri", parm0 }, /* version 4 */ + {132, "swap.alt", parm0 }, /* version 4 */ + {133, "push.adr", parm1 }, /* version 4 */ + {134, "nop", parm0 }, /* version 6 */ + {135, "sysreq.n", parm2 }, /* version 9 (replaces SYSREQ.d from earlier version) */ + {136, "symtag", parm1 }, /* version 7 */ + {137, "break", parm0 }, /* version 8 */ + {138, "push2.c", parm2 }, /* version 9 */ + {139, "push2", parm2 }, /* version 9 */ + {140, "push2.s", parm2 }, /* version 9 */ + {141, "push2.adr", parm2 }, /* version 9 */ + {142, "push3.c", parm3 }, /* version 9 */ + {143, "push3", parm3 }, /* version 9 */ + {144, "push3.s", parm3 }, /* version 9 */ + {145, "push3.adr", parm3 }, /* version 9 */ + {146, "push4.c", parm4 }, /* version 9 */ + {147, "push4", parm4 }, /* version 9 */ + {148, "push4.s", parm4 }, /* version 9 */ + {149, "push4.adr", parm4 }, /* version 9 */ + {150, "push5.c", parm5 }, /* version 9 */ + {151, "push5", parm5 }, /* version 9 */ + {152, "push5.s", parm5 }, /* version 9 */ + {153, "push5.adr", parm5 }, /* version 9 */ + {154, "load.both", parm2 }, /* version 9 */ + {155, "load.s.both",parm2 }, /* version 9 */ + {156, "const", parm2 }, /* version 9 */ + {157, "const.s", parm2 }, /* version 9 */ + {158, "icall", parm1 }, /* version 10 */ + {159, "iretn", parm0 }, + {160, "iswitch", do_switch }, /* version 10 */ + {161, "icasetbl", icasetbl }, /* version 10 */ + {162, "load.p.pri", parm1_p }, + {163, "load.p.alt", parm1_p }, + {164, "load.p.s.pri",parm1_p }, + {165, "load.p.s.alt",parm1_p }, + {166, "lref.p.pri", parm1_p }, + {167, "lref.p.alt", parm1_p }, + {168, "lref.p.s.pri",parm1_p }, + {169, "lodb.p.i", parm1_p }, + {169, "lref.p.s.alt",parm1_p }, + {170, "sref.p.pri", parm1_p }, + {171, "const.p.pri",parm1_p }, + {172, "const.p.alt",parm1_p }, + {173, "addr.p.pri", parm1_p }, + {174, "addr.p.alt", parm1_p }, + {175, "stor.p.pri", parm1_p }, + {176, "stor.p.alt", parm1_p }, + {177, "stor.p.s.pri",parm1_p }, + {178, "stor.p.s.alt",parm1_p }, + {180, "sref.p.alt", parm1_p }, + {181, "sref.p.s.pri",parm1_p }, + {182, "sref.p.s.alt",parm1_p }, + {183, "strb.p.i", parm1_p }, + {184, "lidx.p.b", parm1_p }, + {185, "align.p.pri",parm1_p }, + {186, "idxaddr.p.b",parm1_p }, + {187, "align.p.alt",parm1_p }, + {188, "push.p.c", parm1_p }, + {189, "push.p", parm1_p }, + {190, "push.p.s", parm1_p }, + {191, "stack.p", parm1_p }, + {192, "heap.p", parm1_p }, + {193, "shl.p.c.pri",parm1_p }, + {194, "shl.p.c.alt",parm1_p }, + {195, "shr.p.c.pri",parm1_p }, + {196, "shr.p.c.alt",parm1_p }, + {197, "add.p.c", parm1_p }, + {198, "smul.p.c", parm1_p }, + {199, "zero.p", parm1_p }, + {200, "zero.p.s", parm1_p }, + {201, "eq.p.c.pri", parm1_p }, + {202, "eq.p.c.alt", parm1_p }, + {203, "inc.p", parm1_p }, + {204, "inc.p.s", parm1_p }, + {205, "dec.p", parm1_p }, + {206, "dec.p.s", parm1_p }, + {207, "movs.p", parm1_p }, + {208, "cmps.p", parm1_p }, + {209, "fill.p", parm1_p }, + {210, "halt.p", parm1_p }, + {211, "bounds.p", parm1_p }, + {212, "push.p.adr", parm1_p }, +}; + +void print_opcode(FILE *ftxt,cell opcode,cell cip) +{ + fprintf(ftxt,"%08lx %s ",cip,opcodelist[(int)(opcode &0x0000ffff)].name); +} + +cell parm0(FILE *ftxt,const cell *params,cell opcode,cell cip) +{ + print_opcode(ftxt,opcode,cip); + fprintf(ftxt,"\n"); + return 1; +} + +cell parm1(FILE *ftxt,const cell *params,cell opcode,cell cip) +{ + print_opcode(ftxt,opcode,cip); + fprintf(ftxt,"%08lx\n",*params); + return 2; +} + +cell parm2(FILE *ftxt,const cell *params,cell opcode,cell cip) +{ + print_opcode(ftxt,opcode,cip); + fprintf(ftxt,"%08lx %08lx\n",params[0],params[1]); + return 3; +} + +cell parm3(FILE *ftxt,const cell *params,cell opcode,cell cip) +{ + print_opcode(ftxt,opcode,cip); + fprintf(ftxt,"%08lx %08lx %08lx\n",params[0],params[1],params[2]); + return 4; +} + +cell parm4(FILE *ftxt,const cell *params,cell opcode,cell cip) +{ + print_opcode(ftxt,opcode,cip); + fprintf(ftxt,"%08lx %08lx %08lx %08lx\n",params[0],params[1],params[2],params[3]); + return 5; +} + +cell parm5(FILE *ftxt,const cell *params,cell opcode,cell cip) +{ + print_opcode(ftxt,opcode,cip); + fprintf(ftxt,"%08lx %08lx %08lx %08lx %08lx\n",params[0],params[1],params[2],params[3],params[4]); + return 6; +} + +cell parm1_p(FILE *ftxt,const cell *params,cell opcode,cell cip) +{ + print_opcode(ftxt,opcode,cip); + fprintf(ftxt,"%08lx\n",opcode>>16); + return 1; +} + +cell do_proc(FILE *ftxt,const cell *params,cell opcode,cell cip) +{ + int idx,numpublics,nameoffset; + AMX_FUNCSTUBNT func; + char name[sNAMEMAX+1]; + + fprintf(ftxt,"\n"); + + /* find the procedure in the table (only works for a public function) */ + nameoffset=-1; + name[0]='\0'; + /* find the address in the public function table */ + numpublics=(amxhdr.natives-amxhdr.publics)/sizeof(AMX_FUNCSTUBNT); + fseek(fpamx,amxhdr.publics,SEEK_SET); + for (idx=0; idx=0) { + fseek(fpamx,nameoffset,SEEK_SET); + fread(name,1,sNAMEMAX+1,fpamx); + } /* if */ + + print_opcode(ftxt,opcode,cip); + if (strlen(name)>0) + fprintf(ftxt,"\t; %s",name); + fprintf(ftxt,"\n"); + return 1; +} + +cell do_call(FILE *ftxt,const cell *params,cell opcode,cell cip) +{ + print_opcode(ftxt,opcode,cip); + fprintf(ftxt,"%08lx\n",*params+cip); + return 2; +} + +cell do_jump(FILE *ftxt,const cell *params,cell opcode,cell cip) +{ + print_opcode(ftxt,opcode,cip); + fprintf(ftxt,"%08lx\n",*params+cip); + return 2; +} + +cell do_switch(FILE *ftxt,const cell *params,cell opcode,cell cip) +{ + print_opcode(ftxt,opcode,cip); + fprintf(ftxt,"%08lx\n",*params+cip); + return 2; +} + +cell casetbl(FILE *ftxt,const cell *params,cell opcode,cell cip) +{ + cell num; + int idx; + + print_opcode(ftxt,opcode,cip); + num=params[0]+1; + fprintf(ftxt,"%08lx %08lx\n",params[0],params[1]+cip+sizeof(cell)); + for (idx=1; idx0) { + c=0; + shift=0; + do { + codesize--; + /* no input byte should be shifted out completely */ + assert(shift<8*sizeof(cell)); + /* we work from the end of a sequence backwards; the final code in + * a sequence may not have the continuation bit set */ + assert(shift>0 || (code[(size_t)codesize] & 0x80)==0); + c|=(ucell)(code[(size_t)codesize] & 0x7f) << shift; + shift+=7; + } while (codesize>0 && (code[(size_t)codesize-1] & 0x80)!=0); + /* sign expand */ + if ((code[(size_t)codesize] & 0x40)!=0) { + while (shift < (int)(8*sizeof(cell))) { + c|=(ucell)0xff << shift; + shift+=8; + } /* while */ + } /* if */ + /* store */ + while (sc && (spare[sh].memloc>codesize)) { + *(ucell *)(code+(int)spare[sh].memloc)=spare[sh].c; + sh=(sh+1)%AMX_COMPACTMARGIN; + sc--; + } /* while */ + memsize -= sizeof(cell); + assert(memsize>=0); + if ((memsize>codesize)||((memsize==codesize)&&(memsize==0))) { + *(ucell *)(code+(size_t)memsize)=c; + } else { + assert(sc> 8*(sizeof(cell)-1)) & 0xff; + value <<= 8; + *str++= (v>=32) ? (char)v : ' '; + } /* for */ + *str='\0'; +} + +int main(int argc,char *argv[]) +{ + char name[_MAX_PATH]; + FILE *fplist; + int codesize,count; + cell *code,*cip; + OPCODE_PROC func; + + if (argc<2 || argc>3) { + printf("Usage: pawndisasm [output]\n"); + return 1; + } /* if */ + if (argc==2) { + char *ptr; + strcpy(name,argv[1]); + if ((ptr=strrchr(name,'.'))!=NULL && strpbrk(ptr,"\\/:")==NULL) + *ptr='\0'; /* erase existing extension */ + strcat(name,".lst"); /* append new extension */ + } else { + strcpy(name,argv[2]); + } /* if */ + if ((fpamx=fopen(argv[1],"rb"))==NULL) { + printf("Unable to open input file \"%s\"\n",argv[1]); + return 1; + } /* if */ + if ((fplist=fopen(name,"wt"))==NULL) { + printf("Unable to create output file \"%s\"\n",name); + return 1; + } /* if */ + + /* load header */ + fread(&amxhdr,sizeof amxhdr,1,fpamx); + if (amxhdr.magic!=AMX_MAGIC) { + printf("Not a valid AMX file\n"); + return 1; + } /* if */ + codesize=amxhdr.hea-amxhdr.cod; /* size for both code and data */ + fprintf(fplist,";File version: %d\n",amxhdr.file_version); + fprintf(fplist,";Flags: "); + if ((amxhdr.flags & AMX_FLAG_COMPACT)!=0) + fprintf(fplist,"compact-encoding "); + if ((amxhdr.flags & AMX_FLAG_DEBUG)!=0) + fprintf(fplist,"debug-info "); + fprintf(fplist,"\n\n"); + /* load the code block */ + if ((code=malloc(codesize))==NULL) { + printf("Insufficient memory: need %d bytes\n",codesize); + return 1; + } /* if */ + + /* read and expand the file */ + fseek(fpamx,amxhdr.cod,SEEK_SET); + fread(code,1,codesize,fpamx); + if ((amxhdr.flags & AMX_FLAG_COMPACT)!=0) + expand((unsigned char *)code, amxhdr.size - amxhdr.cod, amxhdr.hea - amxhdr.cod); + + /* do a first run through the code to get jump targets (for labels) */ + //??? + + /* browse through the code */ + cip=code; + codesize=amxhdr.dat-amxhdr.cod; + while (((unsigned char*)cip-(unsigned char*)code)0) { + fprintf(fplist," %s",name); + name[0]='\0'; + } /* if */ + fprintf(fplist,"\n%08lx ",(cell)(cip-code)*sizeof(cell)-(amxhdr.dat-amxhdr.cod)); + } /* if */ + fprintf(fplist,"%08lx ",*cip); + addchars(name,*cip,count); + count=(count+1) % 4; + cip++; + } /* while */ + if (strlen(name)>0) { + fprintf(fplist," %s",name); + name[0]='\0'; + } /* if */ + + free(code); + fclose(fpamx); + fclose(fplist); + return 0; +}