Don't omit frame pointer on msvc builds.
4 #include "decompiler.h"
5 #include "code_analyzer.h"
6 #include "platform_util.h"
10 #define PCM_BRANCH_TARGET (1<<0)
11 #define PCM_OPCODE (1<<1)
12 #define PCM_HAS_BLOCK (1<<2)
13 #define PCM_NUM_BITS 3
15 #define NEXT_OP(cip, op) cip += (dc->opdef[op].params + 1) * sizeof(cell_t)
33 struct ControlFlowGraph
36 unsigned int max_blocks;
37 unsigned int max_edges;
38 unsigned int used_blocks;
39 unsigned int used_edges;
46 DefineNode::DefineNode(BaseNode *o, const char *fmt, ...) : BaseNode(_OP_DEFINE), other(o)
51 Sp_FormatArgs(name, sizeof(name), fmt, ap);
55 static FunctionInfo *sp_InferFuncPrototype(sp_decomp_t *dc, uint32_t code_addr, bool is_public)
60 sp_fdbg_symbol_t *sym;
63 info = new FunctionInfo;
64 memset(info, 0, sizeof(FunctionInfo));
66 info->code_addr = code_addr;
68 if ((sym = Sp_FindFunctionSym(plugin, code_addr)) != NULL)
70 Sp_Format(info->name, sizeof(info->name), "%s", plugin->debug.stringbase + sym->name);
73 info->tag = Sp_FindTag(plugin, sym->tagid);
78 Sp_Format(info->name, sizeof(info->name), "function_%x", code_addr);
79 for (uint32_t i = 0; i < plugin->num_publics; i++)
81 if (plugin->publics[i].code_offs == code_addr)
86 plugin->publics[i].name);
92 info->is_public = is_public;
95 /* Search for all locals */
100 cursor = (uint8_t *)plugin->debug.symbols;
101 for (i = 0; i < plugin->debug.syms_num; i++)
103 sym = (sp_fdbg_symbol_t *)cursor;
105 if (sym->ident == SP_SYM_VARIABLE
106 || sym->ident == SP_SYM_REFARRAY
107 || sym->ident == SP_SYM_REFERENCE
108 || sym->ident == SP_SYM_ARRAY)
110 if (code_addr >= sym->codestart
111 && code_addr < sym->codeend
113 && (sym->addr & 0x3) == 0
114 && ((sym->addr - 0xC) >> 2) < SP_MAX_EXEC_PARAMS
119 num = (sym->addr - 0xC) >> 2;
120 info->known_args[num].sym = sym;
121 if (num + 1 > info->num_known_args)
123 info->num_known_args = num + 1;
128 cursor += sizeof(sp_fdbg_symbol_t);
129 if (sym->dimcount > 0)
131 cursor += sizeof(sp_fdbg_arraydim_t) * sym->dimcount;
136 /* Map all arguments into place. */
137 for (unsigned int i = 0; i < info->num_known_args; i++)
139 if ((sym = info->known_args[i].sym) == NULL)
143 if (sym->tagid != 0 && (pTag = Sp_FindTag(plugin, sym->tagid)) != NULL)
145 info->known_args[i].tag = pTag;
147 info->known_args[i].name = plugin->debug.stringbase + sym->name;
149 info->known_args[i].dimcount = sym->dimcount;
150 if (sym->dimcount > 0)
152 info->known_args[i].dims =
153 (sp_fdbg_arraydim_t *)((char *)sym + sizeof(sp_fdbg_symbol_t));
160 static FunctionInfo *sp_GetFuncPrototype(sp_decomp_t *dc,
163 bool is_public = false);
164 static FunctionInfo *sp_GetFuncPrototype(sp_decomp_t *dc,
174 if (func->code_addr == code_addr)
181 /* See if this is public. */
185 for (unsigned int i = 0; i < dc->plugin->num_publics; i++)
187 if (dc->plugin->publics[i].code_offs == code_addr)
195 func = sp_InferFuncPrototype(dc, code_addr, is_public);
196 func->next = dc->funcs;
202 static void sp_CacheLocals(sp_decomp_t *dc, FunctionInfo *info)
205 sp_fdbg_symbol_t *sym;
209 /* Search for all locals */
214 cursor = (uint8_t *)plugin->debug.symbols;
215 for (i = 0; i < plugin->debug.syms_num; i++)
217 sym = (sp_fdbg_symbol_t *)cursor;
219 if ((sym->codestart >= info->code_addr && sym->codestart < info->code_end)
220 && (sym->codeend <= info->code_end && sym->codeend >= info->code_addr)
223 info->num_known_vars++;
226 cursor += sizeof(sp_fdbg_symbol_t);
227 if (sym->dimcount > 0)
229 cursor += sizeof(sp_fdbg_arraydim_t) * sym->dimcount;
234 /* Map all locals into place. */
235 if (info->num_known_vars)
241 info->known_vars = new FuncVar[info->num_known_vars];
242 memset(info->known_vars, 0, sizeof(FuncVar) * info->num_known_vars);
244 cursor = (uint8_t *)plugin->debug.symbols;
245 for (i = 0; i < plugin->debug.syms_num; i++)
247 sym = (sp_fdbg_symbol_t *)cursor;
249 if (sym->ident == SP_SYM_VARIABLE
250 || sym->ident == SP_SYM_REFARRAY
251 || sym->ident == SP_SYM_REFERENCE
252 || sym->ident == SP_SYM_ARRAY)
254 /* Detect all function variables. */
255 if ((sym->codestart >= info->code_addr && sym->codestart < info->code_end)
256 && (sym->codeend <= info->code_end && sym->codeend >= info->code_addr)
259 assert(num < info->num_known_vars);
260 info->known_vars[num].sym = sym;
261 info->known_vars[num].name = plugin->debug.stringbase + sym->name;
262 info->known_vars[num].tag =
263 (sym->tagid == 0) ? NULL : Sp_FindTag(plugin, sym->tagid);
264 info->known_vars[num].dimcount = sym->dimcount;
265 info->known_vars[num].dims =
268 : (sp_fdbg_arraydim_t *)(cursor + sizeof(sp_fdbg_symbol_t));
273 cursor += sizeof(sp_fdbg_symbol_t);
274 if (sym->dimcount > 0)
276 cursor += sizeof(sp_fdbg_arraydim_t) * sym->dimcount;
280 assert(num == info->num_known_vars);
284 static void sp_PrintFunctionPrototype(PrintBuffer *printer, sp_decomp_t *dc, FunctionInfo *func)
290 printer->Append("public ");
292 if (func->tag != NULL)
294 printer->Append("%s:", func->tag->name);
296 printer->Append("%s(", func->name);
298 for (unsigned int i = 0; i < func->num_known_args; i++)
300 var = &func->known_args[i];
301 if (var->sym == NULL)
303 printer->Append("unknown_arg_%d%s, ", i, i == func->num_known_args - 1 ? "" : ",");
306 if (var->sym->ident == SP_SYM_REFERENCE)
308 printer->Append("&");
310 if (var->tag != NULL)
312 printer->Append("%s:", var->tag->name);
314 printer->Append("%s", var->name);
316 if (var->sym->dimcount > 0)
318 sp_fdbg_arraydim_t *dims =
319 (sp_fdbg_arraydim_t *)((char *)var->sym + sizeof(sp_fdbg_symbol_t));
321 for (uint16_t j = 0; j < var->sym->dimcount; j++)
323 if (dims[j].size == 0)
325 printer->Append("[]");
329 printer->Append("[%d]", dims[j].size);
334 if (i != func->num_known_args - 1)
336 printer->Append(", ");
340 printer->Append(")");
343 void sp_DebugExprTree(PrintBuffer *buffer, BaseNode *node, bool is_stmt=false)
349 DefineNode *def = (DefineNode *)node;
351 buffer->Append("new %s = ", def->name);
352 sp_DebugExprTree(buffer, def->other, is_stmt);
357 CallNode *call = (CallNode *)node;
359 buffer->Append("%s(", call->func->name);
360 for (unsigned int i = 0; i < call->argc; i++)
362 sp_DebugExprTree(buffer, call->args[i], false);
369 UseNode *unode = (UseNode *)node;
371 buffer->Append("%s", unode->def->name);
376 VarNode *var_node = (VarNode *)node;
377 buffer->Append("%s", var_node->var->name);
382 DeclNode *d_node = (DeclNode *)node;
384 if (d_node->expr == NULL)
386 buffer->Append("decl ");
387 sp_DebugExprTree(buffer, d_node->var, true);
391 buffer->Append("new ");
392 sp_DebugExprTree(buffer, d_node->var, true);
393 buffer->Append(" = ");
394 sp_DebugExprTree(buffer, d_node->expr, true);
402 StmtNode *u_node = (StmtNode *)node;
404 while (u_node != NULL)
406 buffer->Append("\t");
407 if (u_node->op == OP_RETN)
409 buffer->Append("return ");
411 sp_DebugExprTree(buffer, u_node->node, true);
412 buffer->Append(";\n");
413 u_node = u_node->next;
419 ConstNode *c_node = (ConstNode *)node;
421 buffer->Append("%d", c_node->val);
434 BinOpNode *bin_node = (BinOpNode *)node;
440 sp_DebugExprTree(buffer, bin_node->left);
447 buffer->Append(" + ");
453 buffer->Append(" * ");
458 buffer->Append(" = ");
463 buffer->Append(" - ");
468 buffer->Append(" / ");
473 buffer->Append(" % ");
478 sp_DebugExprTree(buffer, bin_node->right, node->op == _OP_STORE);
489 void sp_DebugPrint(FunctionInfo *info, sp_decomp_t *dc, BaseNode *node)
493 sp_PrintFunctionPrototype(&buffer, dc, info);
494 buffer.Append("\n{\n");
495 sp_DebugExprTree(&buffer, node, true);
496 buffer.Append("}\n");
500 #define PCODE_VAL(pcode, offs) *(cell_t *)((char *)(pcode)+(offs))
501 #define PCODE_PARAM(pcode, offs, num) *(cell_t *)((char *)(pcode)+(offs)+((num)*sizeof(cell_t)))
503 FuncVar *sp_FindGraphVar(FunctionInfo *func, ucell_t cip, cell_t sp, cell_t stack)
507 if ((stack & 0x3) != 0)
513 if (stack >= SP_MAX_EXEC_PARAMS)
517 if (func->known_args[stack].sym == NULL)
521 return &func->known_args[stack];
532 for (unsigned int i = 0; i < func->num_known_vars; i++)
534 var = &func->known_vars[i];
536 if (cip >= var->sym->codestart
537 && cip <= var->sym->codeend
538 && stack == var->sym->addr)
552 #define CHECK_VALUE(v) \
555 err = SP_ERROR_INVALID_INSTRUCTION; \
559 void *operator new(size_t size, ControlFlowGraph *graph)
564 void *operator new[](size_t size, ControlFlowGraph *graph)
569 void operator delete(void *mem, ControlFlowGraph *graph)
574 void operator delete[](void *mem, ControlFlowGraph *graph)
579 #define MAX_STACK_ENTRIES 256
586 StackEntry(cell_t d, BaseNode *e) : depth(d), expr(e)
593 int sp_AnalyzeGraph(sp_decomp_t *dc, ControlFlowGraph *graph)
600 StmtNode *root, *rtemp;
603 FunctionInfo *func, *tfunc;
606 unsigned int callnumber = 0;
607 unsigned int stack_entries = 0;
608 StackEntry eval_stack[MAX_STACK_ENTRIES];
611 * Stack pointer starts off at 0.
618 block = graph->entry;
619 pcode = (cell_t *)dc->plugin->pcode;
621 cip = block->ip_start;
622 cip_end = block->ip_end;
624 root_tail = root = new (graph) StmtNode(_OP_STMT, NULL, NULL);
626 while (cip < cip_end)
628 op = PCODE_VAL(pcode, cip);
640 p1 = PCODE_PARAM(pcode, cip, 1);
643 tfunc = sp_GetFuncPrototype(dc, p1, false);
645 else if (op == OP_SYSREQ_N)
648 assert(uint32_t(p1) < dc->plugin->num_natives);
649 tfunc = &dc->natives[p1];
653 /* Sanity checks, :TODO: runtime checks later. */
654 assert(stack_entries >= 1);
656 if (op == OP_SYSREQ_N)
658 p2 = PCODE_PARAM(pcode, cip, 2);
662 /* Try to read the value off the stack. */
664 cnode = (ConstNode *)eval_stack[stack_entries-1].expr;
665 /* Sanity checks, :TODO: runtime checks later. */
666 assert(cnode->op == _OP_CONST);
667 assert(cnode->val >= 0);
668 assert(uint32_t(cnode->val) == tfunc->num_known_args);
673 assert(uint32_t(p2) <= stack_entries);
676 BaseNode **nodes = new (graph) BaseNode *[p2];
677 for (cell_t argno = 0; argno < p2; argno++, stack_entries--)
679 nodes[argno] = eval_stack[stack_entries-1].expr;
682 /* Get rid of any args we pushed. */
683 sp += p2 * sizeof(cell_t);
686 sp += sizeof(cell_t);
690 /* Build function call SSA */
691 pri = new (graph) CallNode(tfunc, nodes, p2);
692 pri = new (graph) DefineNode(pri, "call%03x", ++callnumber);
693 rtemp = new (graph) StmtNode(_OP_STMT, pri, NULL);
694 root_tail->next = rtemp;
696 pri = new (graph) UseNode((DefineNode *)pri);
702 p1 = PCODE_PARAM(pcode, cip, 1);
703 pri = new (graph) ConstNode(p1);
711 for (int N = 1; N <= dc->opdef[op].params; N++)
713 p1 = PCODE_PARAM(pcode, cip, N);
715 /* Adjust stack pointer. */
716 sp -= sizeof(cell_t);
718 if ((v1 = sp_FindGraphVar(func, cip, sp, sp)) == NULL)
720 /* Add a new stack entry. */
721 assert(stack_entries < MAX_STACK_ENTRIES);
722 eval_stack[stack_entries++] = StackEntry(sp, new ConstNode(p1));
726 assert(v1->new_stmt == NULL);
727 if (v1->new_stmt == NULL)
729 v1->new_stmt = new (graph) DeclNode(
730 new (graph) VarNode(v1),
731 new (graph) ConstNode(p1));
732 rtemp = new (graph) StmtNode(
736 root_tail->next = rtemp;
745 p1 = PCODE_PARAM(pcode, cip, 1);
746 v1 = sp_FindGraphVar(func, cip, sp, p1);
749 /* Adjust stack pointer. */
750 sp -= sizeof(cell_t);
752 /* Right now, don't allow aliasing or overflows. */
753 assert(sp_FindGraphVar(func, cip, sp, sp) == NULL);
754 assert(stack_entries < MAX_STACK_ENTRIES);
756 /* Add a new stack entry. */
757 eval_stack[stack_entries++] = StackEntry(sp, new (graph) VarNode(v1));
764 /* Adjust stack pointer. */
765 sp -= sizeof(cell_t);
767 /* Right now, don't allow aliasing or overflows. */
768 assert(sp_FindGraphVar(func, cip, sp, sp) == NULL);
769 assert(stack_entries < MAX_STACK_ENTRIES);
771 /* Add a new stack entry. */
772 eval_stack[stack_entries++] = StackEntry(sp, pri);
777 assert(stack_entries > 0);
778 assert(eval_stack[stack_entries - 1].depth == sp);
780 alt = eval_stack[--stack_entries].expr;
781 sp += sizeof(cell_t);
787 p1 = PCODE_PARAM(pcode, cip, 1);
792 /* Find if we should track a new variable declaration. */
793 v1 = sp_FindGraphVar(func, cip, sp, sp);
795 assert(v1->new_stmt == NULL);
796 if (v1->new_stmt == NULL)
798 v1->new_stmt = new (graph) DeclNode(
799 new (graph) VarNode(v1),
801 rtemp = new (graph) StmtNode(
805 root_tail->next = rtemp;
808 assert(abs(p1) >> 2 == 1);
812 /* Erase anything left over on the evaluation stack. */
813 while (stack_entries > 0
814 && eval_stack[stack_entries - 1].depth < sp)
824 pri = new (graph) ConstNode(0);
835 p1 = PCODE_PARAM(pcode, cip, 1);
836 v1 = sp_FindGraphVar(func, cip, sp, p1);
838 pri = new (graph) VarNode(v1);
843 p1 = PCODE_PARAM(pcode, cip, 1);
844 v1 = sp_FindGraphVar(func, cip, sp, p1);
846 alt = new (graph) VarNode(v1);
851 p1 = PCODE_PARAM(pcode, cip, 1);
852 v1 = sp_FindGraphVar(func, cip, sp, p1);
855 rtemp = new (graph) StmtNode(
857 new (graph) BinOpNode(_OP_STORE, new (graph) VarNode(v1), pri),
859 root_tail->next = rtemp;
863 * We create a varnode to simulate a load here.
864 * This helps accidental duplication of the expression tree.
866 pri = new (graph) VarNode(v1);
871 p1 = PCODE_PARAM(pcode, cip, 1);
872 p2 = PCODE_PARAM(pcode, cip, 2);
873 v1 = sp_FindGraphVar(func, cip, sp, p1);
874 v2 = sp_FindGraphVar(func, cip, sp, p2);
877 pri = new (graph) VarNode(v1);
878 alt = new (graph) VarNode(v2);
886 pri = new (graph) BinOpNode(op, pri, alt);
893 pri = new (graph) BinOpNode(op, alt, pri);
900 pri = new (graph) BinOpNode(OP_SDIV, pri, alt);
901 alt = new (graph) BinOpNode(_OP_MODULO, pri, alt);
908 pri = new (graph) BinOpNode(OP_SDIV, alt, pri);
909 alt = new (graph) BinOpNode(_OP_MODULO, alt, pri);
915 p1 = PCODE_PARAM(pcode, cip, 1);
917 pri = new (graph) BinOpNode(op, pri, new (graph) ConstNode(p1));
923 rtemp = new (graph) StmtNode(op, pri, NULL);
924 root_tail->next = rtemp;
938 sp_DebugPrint(graph->func, dc, root->next);
940 return SP_ERROR_NONE;
948 inline Block *sp_BlockFromMap(sp_decomp_t *dc, ControlFlowGraph *graph, cell_t cip)
952 assert(PCODE_VAL(dc->pcode_map, cip) & PCM_HAS_BLOCK);
954 val = PCODE_VAL(dc->pcode_map, cip);
955 val >>= PCM_NUM_BITS;
957 assert(val >= 0 && val < (cell_t)graph->used_blocks);
959 return &graph->blocks[val];
962 void sp_InsertBlock(sp_decomp_t *dc, unsigned int index, cell_t cip)
966 val = PCODE_VAL(dc->pcode_map, cip);
968 assert(!(val & PCM_HAS_BLOCK));
969 assert(index < 0x20000000);
971 val |= PCM_HAS_BLOCK;
974 PCODE_VAL(dc->pcode_map, cip) = val;
977 static Block *sp_BuildBlocks(sp_decomp_t *dc, ControlFlowGraph *graph, cell_t cip)
989 cip_end = graph->func->code_end;
990 pcode = (cell_t *)dc->plugin->pcode;
992 if (PCODE_VAL(dc->pcode_map, cip) & PCM_HAS_BLOCK)
994 return sp_BlockFromMap(dc, graph, cip);
997 /* We can't add a new block if we hit our limit. */
998 assert(graph->used_blocks < graph->max_blocks);
999 if (graph->used_blocks >= graph->max_blocks)
1006 /* Reserve a new block. */
1007 block = &graph->blocks[graph->used_blocks++];
1008 block->ip_start = cip;
1010 /* Enter us into the map. */
1011 sp_InsertBlock(dc, graph->used_blocks - 1, cip);
1013 /* Walk the code. */
1014 while (cip < cip_end)
1016 /* Check whether this is the start of a new block. */
1017 if (cip != block->ip_start
1018 && (PCODE_VAL(dc->pcode_map, cip) & PCM_BRANCH_TARGET))
1020 block->ip_end = cip;
1021 if ((outgoing = sp_BuildBlocks(dc, graph, cip)) == NULL)
1025 /* :TODO: add edge */
1030 op = PCODE_VAL(pcode, cip);
1035 /* Check that branch offsets go to valid instructions. */
1036 if (!(PCODE_VAL(dc->pcode_map, target) & PCM_OPCODE))
1038 graph->err = SP_ERROR_INVALID_INSTRUCTION;
1042 /* Get our target block. */
1043 if ((outgoing = sp_BuildBlocks(dc, graph, target)) == NULL)
1047 /* :TODO: add edge */
1049 else if (op == OP_RETN /* :TODO: || op == OP_RET*/)
1051 block->ip_end = cip;
1056 graph->err = SP_ERROR_INVALID_INSTRUCTION;
1062 int Sp_DecompFunction(sp_decomp_t *dc, uint32_t code_addr, bool is_public)
1071 ControlFlowGraph graph;
1074 plugin = dc->plugin;
1075 memset(&graph, 0, sizeof(graph));
1077 if (code_addr >= plugin->pcode_size)
1079 err = SP_ERROR_INVALID_INSTRUCTION;
1083 pcode = (cell_t *)plugin->pcode;
1085 if (PCODE_VAL(pcode, code_addr) != OP_PROC)
1087 err = SP_ERROR_INVALID_INSTRUCTION;
1091 cip = code_addr + sizeof(cell_t);
1093 /* See if we have an existing function stored. */
1094 func = sp_GetFuncPrototype(dc, code_addr, true, is_public);
1096 while (cip < plugin->pcode_size)
1098 op = PCODE_VAL(pcode, cip);
1099 if (op >= OP_TOTAL || op < 0)
1101 err = SP_ERROR_INVALID_INSTRUCTION;
1103 if (dc->opdef[op].name == NULL)
1105 err = SP_ERROR_INVALID_INSTRUCTION;
1115 func->code_end = cip_end;
1117 /* Now we can cache all local vars. */
1118 sp_CacheLocals(dc, func);
1121 * Make the entry point as the first block.
1122 * It needs to be flagged as well so it doesn't get double counted.
1124 memset(&PCODE_VAL(dc->pcode_map, code_addr), 0, cip_end - code_addr);
1126 graph.max_blocks = 1;
1128 PCODE_VAL(dc->pcode_map, code_addr) |= PCM_BRANCH_TARGET;
1130 /* Walk the code. */
1137 while (cip < cip_end)
1140 op = PCODE_VAL(pcode, cip);
1141 /* Mark as not a branch */
1143 /* Make sure we know this is a valid target */
1144 PCODE_VAL(dc->pcode_map, cip) |= PCM_OPCODE;
1149 * Keep track of where branches are and how many blocks we need.
1151 if (!(PCODE_VAL(dc->pcode_map, target) & PCM_BRANCH_TARGET))
1153 PCODE_VAL(dc->pcode_map, target) |= PCM_BRANCH_TARGET;
1157 * If we're creating a new block, estimate that we need to create a new edge
1164 * In this algorithm, jumps do not terminate a block unless they are unconditional.
1165 * This reduces the number of blocks and edges.
1167 * A property of this is that jumps are edges, so the number of edges is identical
1168 * to the number of jumps.
1177 /* Initialize memory needed for the graph. */
1178 graph.blocks = new Block[graph.max_blocks];
1179 memset(graph.blocks, 0, sizeof(Block) * graph.max_blocks);
1181 if (graph.max_edges != 0)
1183 graph.edges = new Edge[graph.max_edges];
1184 memset(graph.edges, 0, sizeof(Edge) * graph.max_edges);
1187 if ((graph.entry = sp_BuildBlocks(dc, &graph, code_addr)) == NULL)
1189 if ((err = graph.err) == SP_ERROR_NONE)
1191 err = SP_ERROR_ABORTED;
1196 if ((err = sp_AnalyzeGraph(dc, &graph)) != SP_ERROR_NONE)
1201 return SP_ERROR_NONE;