diff --git a/sourcepawn/decompiler/Makefile b/sourcepawn/decompiler/Makefile new file mode 100644 index 00000000..c297b862 --- /dev/null +++ b/sourcepawn/decompiler/Makefile @@ -0,0 +1,98 @@ +# (C)2004-2008 SourceMod Development Team +# Makefile written by David "BAILOPAN" Anderson + +SMSDK = ../.. +SOURCEHOOK = ../../../sourcemm-1.6/sourcehook + +##################################### +### EDIT BELOW FOR OTHER PROJECTS ### +##################################### + +PROJECT = spdecomp + +OBJECTS = main.cpp \ + decompiler.cpp \ + code_analyzer.cpp \ + file_format.cpp \ + platform_util.cpp \ + zlib/adler32.c \ + zlib/compress.c \ + zlib/crc32.c \ + zlib/deflate.c \ + zlib/gzio.c \ + zlib/infback.c \ + zlib/inffast.c \ + zlib/inflate.c \ + zlib/inftrees.c \ + zlib/trees.c \ + zlib/uncompr.c \ + zlib/zutil.c + +############################################## +### CONFIGURE ANY OTHER FLAGS/OPTIONS HERE ### +############################################## + +C_OPT_FLAGS = -DNDEBUG -O3 -funroll-loops -pipe -fno-strict-aliasing +C_DEBUG_FLAGS = -D_DEBUG -DDEBUG -g -ggdb3 +C_GCC4_FLAGS = -fvisibility=hidden +CPP_GCC4_FLAGS = -fvisibility-inlines-hidden +CPP = gcc-4.1 + +LINK = -static-libgcc + +INCLUDE = -I. -I.. -I$(SMSDK)/public -I$(SMSDK)/public/jit -I$(SMSDK)/public/jit/x86 \ + -I$(SMSDK)/public/sourcepawn -I$(SOURCEHOOK) -I$(SMSDK)/knight/shared -Ix86 + +CFLAGS += -D_LINUX -Dstricmp=strcasecmp -D_stricmp=strcasecmp -D_strnicmp=strncasecmp -Dstrnicmp=strncasecmp \ + -D_snprintf=snprintf -D_vsnprintf=vsnprintf -D_alloca=alloca -Dstrcmpi=strcasecmp -Wall -DHAVE_STDINT_H \ + -m32 -Wno-uninitialized -Werror +CPPFLAGS += -Wno-non-virtual-dtor -fno-exceptions -fno-rtti + +################################################ +### DO NOT EDIT BELOW HERE FOR MOST PROJECTS ### +################################################ + +ifeq "$(DEBUG)" "true" + BIN_DIR = Debug + CFLAGS += $(C_DEBUG_FLAGS) +else + BIN_DIR = Release + CFLAGS += $(C_OPT_FLAGS) +endif + +GCC_VERSION := $(shell $(CPP) -dumpversion >&1 | cut -b1) +ifeq "$(GCC_VERSION)" "4" + CFLAGS += $(C_GCC4_FLAGS) + CPPFLAGS += $(CPP_GCC4_FLAGS) +endif + +BINARY = $(PROJECT) + +OBJ_LINUX := $(OBJECTS:%.cpp=$(BIN_DIR)/%.o) +OBJ_LINUX := $(OBJ_LINUX:%.c=$(BIN_DIR)/%.o) + +default: all + +$(BIN_DIR)/%.o: %.c + $(CPP) $(INCLUDE) $(CFLAGS) -o $@ -c $< + +$(BIN_DIR)/%.o: %.cpp + $(CPP) $(INCLUDE) $(CFLAGS) $(CPPFLAGS) -o $@ -c $< + +all: + mkdir -p $(BIN_DIR)/x86 + mkdir -p $(BIN_DIR)/zlib + mkdir -p $(BIN_DIR)/knight + $(MAKE) -f Makefile jit + +jit: $(OBJ_LINUX) + $(CPP) $(INCLUDE) $(OBJ_LINUX) $(LINK) -m32 -ldl -lm -o$(BIN_DIR)/$(BINARY) + +debug: + $(MAKE) -f Makefile all DEBUG=true + +clean: + rm -rf $(BIN_DIR)/zlib/*.o + rm -rf $(BIN_DIR)/*.o + rm -rf $(BIN_DIR)/$(BINARY) + diff --git a/sourcepawn/decompiler/code_analyzer.cpp b/sourcepawn/decompiler/code_analyzer.cpp index 6e41d159..6aba290f 100644 --- a/sourcepawn/decompiler/code_analyzer.cpp +++ b/sourcepawn/decompiler/code_analyzer.cpp @@ -146,6 +146,7 @@ static FunctionInfo *sp_InferFuncPrototype(sp_decomp_t *dc, uint32_t code_addr, } info->known_args[i].name = plugin->debug.stringbase + sym->name; + info->known_args[i].dimcount = sym->dimcount; if (sym->dimcount > 0) { info->known_args[i].dims = @@ -260,6 +261,7 @@ static void sp_CacheLocals(sp_decomp_t *dc, FunctionInfo *info) info->known_vars[num].name = plugin->debug.stringbase + sym->name; info->known_vars[num].tag = (sym->tagid == 0) ? NULL : Sp_FindTag(plugin, sym->tagid); + info->known_vars[num].dimcount = sym->dimcount; info->known_vars[num].dims = (sym->dimcount == 0) ? NULL @@ -633,35 +635,60 @@ int sp_AnalyzeGraph(sp_decomp_t *dc, ControlFlowGraph *graph) break; } case OP_CALL: + case OP_SYSREQ_N: { p1 = PCODE_PARAM(pcode, cip, 1); - tfunc = sp_GetFuncPrototype(dc, p1, false); + if (op == OP_CALL) + { + tfunc = sp_GetFuncPrototype(dc, p1, false); + } + else if (op == OP_SYSREQ_N) + { + assert(dc->natives); + assert(uint32_t(p1) < dc->plugin->num_natives); + tfunc = &dc->natives[p1]; + } CHECK_VALUE(tfunc); /* Sanity checks, :TODO: runtime checks later. */ assert(stack_entries >= 1); - ConstNode *cnode; - cnode = (ConstNode *)eval_stack[stack_entries-1].expr; - stack_entries--; + if (op == OP_SYSREQ_N) + { + p2 = PCODE_PARAM(pcode, cip, 2); + } + else + { + /* Try to read the value off the stack. */ + ConstNode *cnode; + cnode = (ConstNode *)eval_stack[stack_entries-1].expr; + /* Sanity checks, :TODO: runtime checks later. */ + assert(cnode->op == _OP_CONST); + assert(cnode->val >= 0); + assert(uint32_t(cnode->val) == tfunc->num_known_args); + p2 = cnode->val; + stack_entries--; + } - /* Sanity checks, :TODO: runtime checks later. */ - assert(cnode->op == _OP_CONST); - assert(cnode->val >= 0); - assert(cnode->val == tfunc->num_known_args); - assert(unsigned int(cnode->val) <= stack_entries); + assert(uint32_t(p2) <= stack_entries); - cell_t argc = cnode->val; - BaseNode **nodes = new (graph) BaseNode *[cnode->val]; - for (cell_t argno = 0; argno < cnode->val; argno++, stack_entries--) + /* Build arg SSA */ + BaseNode **nodes = new (graph) BaseNode *[p2]; + for (cell_t argno = 0; argno < p2; argno++, stack_entries--) { nodes[argno] = eval_stack[stack_entries-1].expr; } - sp += (cnode->val + 1) * sizeof(cell_t); + /* Get rid of any args we pushed. */ + sp += p2 * sizeof(cell_t); + if (op == OP_CALL) + { + sp += sizeof(cell_t); + } assert(sp <= 0); - pri = new (graph) CallNode(tfunc, nodes, cnode->val); + /* Build function call SSA */ + pri = new (graph) CallNode(tfunc, nodes, p2); pri = new (graph) DefineNode(pri, "call%03x", ++callnumber); rtemp = new (graph) StmtNode(_OP_STMT, pri, NULL); root_tail->next = rtemp; @@ -677,32 +704,38 @@ int sp_AnalyzeGraph(sp_decomp_t *dc, ControlFlowGraph *graph) break; } case OP_PUSH_C: + case OP_PUSH2_C: + case OP_PUSH3_C: + case OP_PUSH5_C: { - p1 = PCODE_PARAM(pcode, cip, 1); - - /* Adjust stack pointer. */ - sp -= sizeof(cell_t); - - if ((v1 = sp_FindGraphVar(func, cip, sp, sp)) == NULL) + for (int N = 1; N <= dc->opdef[op].params; N++) { - /* Add a new stack entry. */ - assert(stack_entries < MAX_STACK_ENTRIES); - eval_stack[stack_entries++] = StackEntry(sp, new ConstNode(p1)); - } - else - { - assert(v1->new_stmt == NULL); - if (v1->new_stmt == NULL) + p1 = PCODE_PARAM(pcode, cip, N); + + /* Adjust stack pointer. */ + sp -= sizeof(cell_t); + + if ((v1 = sp_FindGraphVar(func, cip, sp, sp)) == NULL) { - v1->new_stmt = new (graph) DeclNode( - new (graph) VarNode(v1), - new (graph) ConstNode(p1)); - rtemp = new (graph) StmtNode( - _OP_STMT, - v1->new_stmt, - NULL); - root_tail->next = rtemp; - root_tail = rtemp; + /* Add a new stack entry. */ + assert(stack_entries < MAX_STACK_ENTRIES); + eval_stack[stack_entries++] = StackEntry(sp, new ConstNode(p1)); + } + else + { + assert(v1->new_stmt == NULL); + if (v1->new_stmt == NULL) + { + v1->new_stmt = new (graph) DeclNode( + new (graph) VarNode(v1), + new (graph) ConstNode(p1)); + rtemp = new (graph) StmtNode( + _OP_STMT, + v1->new_stmt, + NULL); + root_tail->next = rtemp; + root_tail = rtemp; + } } } break; @@ -1160,7 +1193,7 @@ int Sp_DecompFunction(sp_decomp_t *dc, uint32_t code_addr, bool is_public) goto return_error; } - if ((err = sp_AnalyzeGraph(dc, &graph)) == NULL) + if ((err = sp_AnalyzeGraph(dc, &graph)) != SP_ERROR_NONE) { goto return_error; } diff --git a/sourcepawn/decompiler/code_analyzer.h b/sourcepawn/decompiler/code_analyzer.h index ebec22e4..2672a834 100644 --- a/sourcepawn/decompiler/code_analyzer.h +++ b/sourcepawn/decompiler/code_analyzer.h @@ -126,6 +126,7 @@ struct FuncVar sp_fdbg_arraydim_t *dims; sp_tag_t *tag; const char *name; + unsigned int dimcount; DeclNode *new_stmt; }; diff --git a/sourcepawn/decompiler/decompiler.cpp b/sourcepawn/decompiler/decompiler.cpp index e66a0e27..07dbd179 100644 --- a/sourcepawn/decompiler/decompiler.cpp +++ b/sourcepawn/decompiler/decompiler.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include "decompiler.h" #include "platform_util.h" @@ -27,6 +28,52 @@ sp_decomp_t *Sp_InitDecomp(const char *file, int *err) #include "opcodes.tbl" #undef OPDEF + if (plugin->debug.ntv != NULL) + { + assert(plugin->debug.ntv->num_entries == plugin->num_natives); + dc->natives = new FunctionInfo[plugin->num_natives]; + memset(dc->natives, 0, sizeof(FunctionInfo) * plugin->num_natives); + + /* Unfurl this mess. */ + uint8_t *cursor = (uint8_t *)plugin->debug.ntv; + + cursor += sizeof(sp_fdbg_ntvtab_t); + for (uint32_t i = 0; i < plugin->num_natives; i++) + { + sp_fdbg_native_t *native = (sp_fdbg_native_t *)cursor; + + uint32_t idx = native->index; + + assert(dc->natives[idx].name[0] == '\0'); + + Sp_Format(dc->natives[idx].name, + sizeof(dc->natives[idx].name), + "%s", + plugin->debug.stringbase + native->name); + dc->natives[idx].tag = Sp_FindTag(plugin, native->tagid); + dc->natives[idx].num_known_args = native->nargs; + + cursor += sizeof(sp_fdbg_native_t); + + for (uint32_t j = 0; j < dc->natives[idx].num_known_args; j++) + { + sp_fdbg_ntvarg_t *arg = (sp_fdbg_ntvarg_t *)cursor; + dc->natives[idx].known_args[j].name = + plugin->debug.stringbase + arg->name; + dc->natives[idx].known_args[j].tag = + Sp_FindTag(plugin, arg->tagid); + dc->natives[idx].known_args[j].dimcount = arg->dimcount; + + cursor += sizeof(sp_fdbg_ntvarg_t); + if (arg->dimcount != 0) + { + dc->natives[idx].known_args[j].dims = (sp_fdbg_arraydim_t *)cursor; + cursor += sizeof(sp_fdbg_arraydim_t) * arg->dimcount; + } + } + } + } + return dc; } @@ -44,6 +91,7 @@ void Sp_FreeDecomp(sp_decomp_t *decomp) Sp_FreePlugin(decomp->plugin); free(decomp->pcode_map); + delete [] decomp->natives; delete decomp; } @@ -84,9 +132,8 @@ void PrintBuffer::Append(const char *fmt, ...) len = Sp_FormatArgs(buffer, sizeof(buffer), fmt, ap); va_end(ap); - Grow(len); + Grow(len + 1); - printbuf = (char *)realloc(printbuf, printbuf_alloc); strcpy(&printbuf[printbuf_pos], buffer); printbuf_pos += len; } @@ -102,7 +149,7 @@ void PrintBuffer::Set(const char *fmt, ...) va_end(ap); Reset(); - Grow(len); + Grow(len + 1); printbuf = (char *)realloc(printbuf, printbuf_alloc); strcpy(&printbuf[printbuf_pos], buffer); diff --git a/sourcepawn/decompiler/decompiler.h b/sourcepawn/decompiler/decompiler.h index a533e295..59b0b7bb 100644 --- a/sourcepawn/decompiler/decompiler.h +++ b/sourcepawn/decompiler/decompiler.h @@ -30,6 +30,7 @@ struct sp_decomp_t sp_opdef_t opdef[OP_TOTAL+1]; FunctionInfo *funcs; cell_t *pcode_map; + FunctionInfo *natives; }; sp_decomp_t *Sp_InitDecomp(const char *file, int *err); diff --git a/sourcepawn/decompiler/file_format.cpp b/sourcepawn/decompiler/file_format.cpp index 2fc0fecd..37c2e324 100644 --- a/sourcepawn/decompiler/file_format.cpp +++ b/sourcepawn/decompiler/file_format.cpp @@ -246,6 +246,10 @@ sp_file_t *Sp_ReadPlugin(const char *file, int *err) plugin->debug.lines_num = inf->num_lines; plugin->debug.syms_num = inf->num_syms; } + else if (plugin->debug.ntv == NULL && !strcmp(nameptr, ".dbg.natives")) + { + plugin->debug.ntv = (sp_fdbg_ntvtab_s *)(base + secptr->dataoffs); + } else if (!(plugin->debug.stringbase) && !strcmp(nameptr, ".dbg.strings")) { plugin->debug.stringbase = (const char *)(base + secptr->dataoffs); diff --git a/sourcepawn/decompiler/file_format.h b/sourcepawn/decompiler/file_format.h index 571965b4..f3a4e776 100644 --- a/sourcepawn/decompiler/file_format.h +++ b/sourcepawn/decompiler/file_format.h @@ -12,6 +12,7 @@ struct sp_debug_t sp_fdbg_line_t *lines; /**< lines table */ uint32_t syms_num; /**< number of symbols */ sp_fdbg_symbol_t *symbols; /**< symbol table */ + sp_fdbg_ntvtab_s *ntv; /**< native table */ }; struct sp_tag_t diff --git a/sourcepawn/decompiler/main.cpp b/sourcepawn/decompiler/main.cpp index 23caf20f..fbdcd3ef 100644 --- a/sourcepawn/decompiler/main.cpp +++ b/sourcepawn/decompiler/main.cpp @@ -7,7 +7,7 @@ int main() int err; sp_decomp_t *dc; - const char *file = "R:\\sourcemod\\sourcemod-central\\plugins\\test.smx"; + const char *file = "../../plugins/test.smx"; if ((dc = Sp_InitDecomp(file, &err)) == NULL) { diff --git a/sourcepawn/decompiler/opcodes.tbl b/sourcepawn/decompiler/opcodes.tbl index 971dd20c..7bc8897a 100644 --- a/sourcepawn/decompiler/opcodes.tbl +++ b/sourcepawn/decompiler/opcodes.tbl @@ -23,6 +23,10 @@ OPDEF(80, SUB_ALT, "sub.alt", 0) OPDEF(87, ADD_C, "add.c", 1) OPDEF(88, SMUL_C, "smul.c", 1) OPDEF(89, ZERO_PRI, "zero.pri", 0) +OPDEF(135, SYSREQ_N, "sysreq.n", 2) OPDEF(137, BREAK, "break", 0) +OPDEF(138, PUSH2_C, "push2.c", 2) +OPDEF(142, PUSH3_C, "push3.c", 3) +OPDEF(150, PUSH5_C, "push5.c", 5) OPDEF(155, LOAD_S_BOTH, "load.s.both", 2) OPDEF(166, TOTAL, NULL, 0) diff --git a/sourcepawn/decompiler/platform_util.cpp b/sourcepawn/decompiler/platform_util.cpp index e0735775..3ddb8591 100644 --- a/sourcepawn/decompiler/platform_util.cpp +++ b/sourcepawn/decompiler/platform_util.cpp @@ -1,4 +1,6 @@ +#include #include +#include #include "platform_util.h" size_t Sp_Format(char *buffer, size_t maxlength, const char *fmt, ...) @@ -30,3 +32,29 @@ size_t Sp_FormatArgs(char *buffer, size_t maxlength, const char *fmt, va_list ap } } +/* Overload a few things to prevent libstdc++ linking */ +#if defined __linux__ +extern "C" void __cxa_pure_virtual(void) +{ +} + +void *operator new(size_t size) +{ + return malloc(size); +} + +void *operator new[](size_t size) +{ + return malloc(size); +} + +void operator delete(void *ptr) +{ + free(ptr); +} + +void operator delete[](void * ptr) +{ + free(ptr); +} +#endif