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 static FunctionInfo *sp_InferFuncPrototype(sp_decomp_t *dc, uint32_t code_addr, bool is_public)
51 sp_fdbg_symbol_t *sym;
54 info = new FunctionInfo;
55 memset(info, 0, sizeof(FunctionInfo));
57 info->code_addr = code_addr;
59 if ((sym = Sp_FindFunctionSym(plugin, code_addr)) != NULL)
61 Sp_Format(info->name, sizeof(info->name), "%s", plugin->debug.stringbase + sym->name);
64 info->tag = Sp_FindTag(plugin, sym->tagid);
69 Sp_Format(info->name, sizeof(info->name), "function_%x", code_addr);
70 for (uint32_t i = 0; i < plugin->num_publics; i++)
72 if (plugin->publics[i].code_offs == code_addr)
77 plugin->publics[i].name);
83 info->is_public = is_public;
86 /* Search for all locals */
91 cursor = (uint8_t *)plugin->debug.symbols;
92 for (i = 0; i < plugin->debug.syms_num; i++)
94 sym = (sp_fdbg_symbol_t *)cursor;
96 if (sym->ident == SP_SYM_VARIABLE
97 || sym->ident == SP_SYM_REFARRAY
98 || sym->ident == SP_SYM_REFERENCE
99 || sym->ident == SP_SYM_ARRAY)
101 if (code_addr >= sym->codestart
102 && code_addr < sym->codeend
104 && (sym->addr & 0x3) == 0
105 && ((sym->addr - 0xC) >> 2) < SP_MAX_EXEC_PARAMS
110 num = (sym->addr - 0xC) >> 2;
111 info->known_args[num].sym = sym;
112 if (num + 1 > info->num_known_args)
114 info->num_known_args = num + 1;
119 cursor += sizeof(sp_fdbg_symbol_t);
120 if (sym->dimcount > 0)
122 cursor += sizeof(sp_fdbg_arraydim_t) * sym->dimcount;
127 /* Map all arguments into place. */
128 for (unsigned int i = 0; i < info->num_known_args; i++)
130 if ((sym = info->known_args[i].sym) == NULL)
134 if (sym->tagid != 0 && (pTag = Sp_FindTag(plugin, sym->tagid)) != NULL)
136 info->known_args[i].tag = pTag;
138 info->known_args[i].name = plugin->debug.stringbase + sym->name;
140 if (sym->dimcount > 0)
142 info->known_args[i].dims =
143 (sp_fdbg_arraydim_t *)((char *)sym + sizeof(sp_fdbg_symbol_t));
150 static FunctionInfo *sp_GetFuncPrototype(sp_decomp_t *dc,
153 bool is_public = false);
154 static FunctionInfo *sp_GetFuncPrototype(sp_decomp_t *dc,
164 if (func->code_addr == code_addr)
171 /* See if this is public. */
175 for (unsigned int i = 0; i < dc->plugin->num_publics; i++)
177 if (dc->plugin->publics[i].code_offs == code_addr)
185 func = sp_InferFuncPrototype(dc, code_addr, is_public);
186 func->next = dc->funcs;
192 static void sp_CacheLocals(sp_decomp_t *dc, FunctionInfo *info)
195 sp_fdbg_symbol_t *sym;
199 /* Search for all locals */
204 cursor = (uint8_t *)plugin->debug.symbols;
205 for (i = 0; i < plugin->debug.syms_num; i++)
207 sym = (sp_fdbg_symbol_t *)cursor;
209 if ((sym->codestart >= info->code_addr && sym->codestart < info->code_end)
210 && (sym->codeend <= info->code_end && sym->codeend >= info->code_addr)
213 info->num_known_vars++;
216 cursor += sizeof(sp_fdbg_symbol_t);
217 if (sym->dimcount > 0)
219 cursor += sizeof(sp_fdbg_arraydim_t) * sym->dimcount;
224 /* Map all locals into place. */
225 if (info->num_known_vars)
231 info->known_vars = new FuncVar[info->num_known_vars];
232 memset(info->known_vars, 0, sizeof(FuncVar) * info->num_known_vars);
234 cursor = (uint8_t *)plugin->debug.symbols;
235 for (i = 0; i < plugin->debug.syms_num; i++)
237 sym = (sp_fdbg_symbol_t *)cursor;
239 if (sym->ident == SP_SYM_VARIABLE
240 || sym->ident == SP_SYM_REFARRAY
241 || sym->ident == SP_SYM_REFERENCE
242 || sym->ident == SP_SYM_ARRAY)
244 /* Detect all function variables. */
245 if ((sym->codestart >= info->code_addr && sym->codestart < info->code_end)
246 && (sym->codeend <= info->code_end && sym->codeend >= info->code_addr)
249 assert(num < info->num_known_vars);
250 info->known_vars[num].sym = sym;
251 info->known_vars[num].name = plugin->debug.stringbase + sym->name;
252 info->known_vars[num].tag =
253 (sym->tagid == 0) ? NULL : Sp_FindTag(plugin, sym->tagid);
254 info->known_vars[num].dims =
257 : (sp_fdbg_arraydim_t *)(cursor + sizeof(sp_fdbg_symbol_t));
262 cursor += sizeof(sp_fdbg_symbol_t);
263 if (sym->dimcount > 0)
265 cursor += sizeof(sp_fdbg_arraydim_t) * sym->dimcount;
269 assert(num == info->num_known_vars);
273 static void sp_PrintFunctionPrototype(PrintBuffer *printer, sp_decomp_t *dc, FunctionInfo *func)
279 printer->Append("public ");
281 if (func->tag != NULL)
283 printer->Append("%s:", func->tag->name);
285 printer->Append("%s(", func->name);
287 for (unsigned int i = 0; i < func->num_known_args; i++)
289 var = &func->known_args[i];
290 if (var->sym == NULL)
292 printer->Append("unknown_arg_%d%s, ", i, i == func->num_known_args - 1 ? "" : ",");
295 if (var->sym->ident == SP_SYM_REFERENCE)
297 printer->Append("&");
299 if (var->tag != NULL)
301 printer->Append("%s:", var->tag->name);
303 printer->Append("%s", var->name);
305 if (var->sym->dimcount > 0)
307 sp_fdbg_arraydim_t *dims =
308 (sp_fdbg_arraydim_t *)((char *)var->sym + sizeof(sp_fdbg_symbol_t));
310 for (uint16_t j = 0; j < var->sym->dimcount; j++)
312 if (dims[j].size == 0)
314 printer->Append("[]");
318 printer->Append("[%d]", dims[j].size);
323 if (i != func->num_known_args - 1)
325 printer->Append(", ");
329 printer->Append(")");
332 void sp_DebugExprTree(PrintBuffer *buffer, BaseNode *node, bool is_stmt=false)
338 CallNode *call = (CallNode *)node;
340 buffer->Append("%s(", call->func->name);
341 for (unsigned int i = 0; i < call->argc; i++)
343 sp_DebugExprTree(buffer, call->args[i], false);
350 VarNode *var_node = (VarNode *)node;
351 buffer->Append("%s", var_node->var->name);
356 DeclNode *d_node = (DeclNode *)node;
358 if (d_node->expr == NULL)
360 buffer->Append("decl ");
361 sp_DebugExprTree(buffer, d_node->var, true);
365 buffer->Append("new ");
366 sp_DebugExprTree(buffer, d_node->var, true);
367 buffer->Append(" = ");
368 sp_DebugExprTree(buffer, d_node->expr, true);
376 StmtNode *u_node = (StmtNode *)node;
378 while (u_node != NULL)
380 buffer->Append("\t");
381 if (u_node->op == OP_RETN)
383 buffer->Append("return ");
385 sp_DebugExprTree(buffer, u_node->node, true);
386 buffer->Append(";\n");
387 u_node = u_node->next;
393 ConstNode *c_node = (ConstNode *)node;
395 buffer->Append("%d", c_node->val);
408 BinOpNode *bin_node = (BinOpNode *)node;
414 sp_DebugExprTree(buffer, bin_node->left);
421 buffer->Append(" + ");
427 buffer->Append(" * ");
432 buffer->Append(" = ");
437 buffer->Append(" - ");
442 buffer->Append(" / ");
447 buffer->Append(" % ");
452 sp_DebugExprTree(buffer, bin_node->right, node->op == _OP_STORE);
463 void sp_DebugPrint(FunctionInfo *info, sp_decomp_t *dc, BaseNode *node)
467 sp_PrintFunctionPrototype(&buffer, dc, info);
468 buffer.Append("\n{\n");
469 sp_DebugExprTree(&buffer, node, true);
470 buffer.Append("}\n");
474 #define PCODE_VAL(pcode, offs) *(cell_t *)((char *)(pcode)+(offs))
475 #define PCODE_PARAM(pcode, offs, num) *(cell_t *)((char *)(pcode)+(offs)+((num)*sizeof(cell_t)))
477 FuncVar *sp_FindGraphVar(FunctionInfo *func, ucell_t cip, cell_t sp, cell_t stack)
481 if ((stack & 0x3) != 0)
487 if (stack >= SP_MAX_EXEC_PARAMS)
491 if (func->known_args[stack].sym == NULL)
495 return &func->known_args[stack];
506 for (unsigned int i = 0; i < func->num_known_vars; i++)
508 var = &func->known_vars[i];
510 if (cip >= var->sym->codestart
511 && cip <= var->sym->codeend
512 && stack == var->sym->addr)
526 #define CHECK_VALUE(v) \
529 err = SP_ERROR_INVALID_INSTRUCTION; \
533 void *operator new(size_t size, ControlFlowGraph *graph)
538 void *operator new[](size_t size, ControlFlowGraph *graph)
543 void operator delete(void *mem, ControlFlowGraph *graph)
548 void operator delete[](void *mem, ControlFlowGraph *graph)
553 #define MAX_STACK_ENTRIES 256
560 StackEntry(cell_t d, BaseNode *e) : depth(d), expr(e)
567 int sp_AnalyzeGraph(sp_decomp_t *dc, ControlFlowGraph *graph)
574 StmtNode *root, *rtemp;
577 FunctionInfo *func, *tfunc;
580 unsigned int stack_entries = 0;
581 StackEntry eval_stack[MAX_STACK_ENTRIES];
584 * Stack pointer starts off at 0.
591 block = graph->entry;
592 pcode = (cell_t *)dc->plugin->pcode;
594 cip = block->ip_start;
595 cip_end = block->ip_end;
597 root_tail = root = new (graph) StmtNode(_OP_STMT, NULL, NULL);
599 while (cip < cip_end)
601 op = PCODE_VAL(pcode, cip);
612 p1 = PCODE_PARAM(pcode, cip, 1);
613 tfunc = sp_GetFuncPrototype(dc, p1, false);
616 /* Sanity checks, :TODO: runtime checks later. */
617 assert(stack_entries >= 1);
620 cnode = (ConstNode *)eval_stack[stack_entries-1].expr;
623 /* Sanity checks, :TODO: runtime checks later. */
624 assert(cnode->op == _OP_CONST);
625 assert(cnode->val >= 0);
626 assert(cnode->val == tfunc->num_known_args);
627 assert(unsigned int(cnode->val) <= stack_entries);
629 cell_t argc = cnode->val;
630 BaseNode **nodes = new (graph) BaseNode *[cnode->val];
631 for (cell_t argno = 0; argno < cnode->val; argno++, stack_entries--)
633 nodes[argno] = eval_stack[stack_entries-1].expr;
636 sp += (cnode->val + 1) * sizeof(cell_t);
639 pri = new (graph) CallNode(tfunc, nodes, cnode->val);
645 p1 = PCODE_PARAM(pcode, cip, 1);
646 pri = new (graph) ConstNode(p1);
651 p1 = PCODE_PARAM(pcode, cip, 1);
653 /* Adjust stack pointer. */
654 sp -= sizeof(cell_t);
656 if ((v1 = sp_FindGraphVar(func, cip, sp, sp)) == NULL)
658 /* Add a new stack entry. */
659 assert(stack_entries < MAX_STACK_ENTRIES);
660 eval_stack[stack_entries++] = StackEntry(sp, new ConstNode(p1));
664 assert(v1->new_stmt == NULL);
665 if (v1->new_stmt == NULL)
667 v1->new_stmt = new (graph) DeclNode(
668 new (graph) VarNode(v1),
669 new (graph) ConstNode(p1));
670 rtemp = new (graph) StmtNode(
674 root_tail->next = rtemp;
682 p1 = PCODE_PARAM(pcode, cip, 1);
683 v1 = sp_FindGraphVar(func, cip, sp, p1);
686 /* Adjust stack pointer. */
687 sp -= sizeof(cell_t);
689 /* Right now, don't allow aliasing or overflows. */
690 assert(sp_FindGraphVar(func, cip, sp, sp) == NULL);
691 assert(stack_entries < MAX_STACK_ENTRIES);
693 /* Add a new stack entry. */
694 eval_stack[stack_entries++] = StackEntry(sp, new (graph) VarNode(v1));
701 /* Adjust stack pointer. */
702 sp -= sizeof(cell_t);
704 /* Right now, don't allow aliasing or overflows. */
705 assert(sp_FindGraphVar(func, cip, sp, sp) == NULL);
706 assert(stack_entries < MAX_STACK_ENTRIES);
708 /* Add a new stack entry. */
709 eval_stack[stack_entries++] = StackEntry(sp, pri);
714 assert(stack_entries > 0);
715 assert(eval_stack[stack_entries - 1].depth == sp);
717 alt = eval_stack[--stack_entries].expr;
718 sp += sizeof(cell_t);
724 p1 = PCODE_PARAM(pcode, cip, 1);
729 /* Find if we should track a new variable declaration. */
730 v1 = sp_FindGraphVar(func, cip, sp, sp);
732 assert(v1->new_stmt == NULL);
733 if (v1->new_stmt == NULL)
735 v1->new_stmt = new (graph) DeclNode(
736 new (graph) VarNode(v1),
738 rtemp = new (graph) StmtNode(
742 root_tail->next = rtemp;
745 assert(abs(p1) >> 2 == 1);
749 /* Erase anything left over on the evaluation stack. */
750 while (stack_entries > 0
751 && eval_stack[stack_entries - 1].depth < sp)
761 pri = new (graph) ConstNode(0);
772 p1 = PCODE_PARAM(pcode, cip, 1);
773 v1 = sp_FindGraphVar(func, cip, sp, p1);
775 pri = new (graph) VarNode(v1);
780 p1 = PCODE_PARAM(pcode, cip, 1);
781 v1 = sp_FindGraphVar(func, cip, sp, p1);
783 alt = new (graph) VarNode(v1);
788 p1 = PCODE_PARAM(pcode, cip, 1);
789 v1 = sp_FindGraphVar(func, cip, sp, p1);
792 rtemp = new (graph) StmtNode(
794 new (graph) BinOpNode(_OP_STORE, new (graph) VarNode(v1), pri),
796 root_tail->next = rtemp;
800 * We create a varnode to simulate a load here.
801 * This helps accidental duplication of the expression tree.
803 pri = new (graph) VarNode(v1);
808 p1 = PCODE_PARAM(pcode, cip, 1);
809 p2 = PCODE_PARAM(pcode, cip, 2);
810 v1 = sp_FindGraphVar(func, cip, sp, p1);
811 v2 = sp_FindGraphVar(func, cip, sp, p2);
814 pri = new (graph) VarNode(v1);
815 alt = new (graph) VarNode(v2);
823 pri = new (graph) BinOpNode(op, pri, alt);
830 pri = new (graph) BinOpNode(op, alt, pri);
837 pri = new (graph) BinOpNode(OP_SDIV, pri, alt);
838 alt = new (graph) BinOpNode(_OP_MODULO, pri, alt);
845 pri = new (graph) BinOpNode(OP_SDIV, alt, pri);
846 alt = new (graph) BinOpNode(_OP_MODULO, alt, pri);
852 p1 = PCODE_PARAM(pcode, cip, 1);
854 pri = new (graph) BinOpNode(op, pri, new (graph) ConstNode(p1));
860 rtemp = new (graph) StmtNode(op, pri, NULL);
861 root_tail->next = rtemp;
875 sp_DebugPrint(graph->func, dc, root->next);
877 return SP_ERROR_NONE;
885 inline Block *sp_BlockFromMap(sp_decomp_t *dc, ControlFlowGraph *graph, cell_t cip)
889 assert(PCODE_VAL(dc->pcode_map, cip) & PCM_HAS_BLOCK);
891 val = PCODE_VAL(dc->pcode_map, cip);
892 val >>= PCM_NUM_BITS;
894 assert(val >= 0 && val < (cell_t)graph->used_blocks);
896 return &graph->blocks[val];
899 void sp_InsertBlock(sp_decomp_t *dc, unsigned int index, cell_t cip)
903 val = PCODE_VAL(dc->pcode_map, cip);
905 assert(!(val & PCM_HAS_BLOCK));
906 assert(index < 0x20000000);
908 val |= PCM_HAS_BLOCK;
911 PCODE_VAL(dc->pcode_map, cip) = val;
914 static Block *sp_BuildBlocks(sp_decomp_t *dc, ControlFlowGraph *graph, cell_t cip)
926 cip_end = graph->func->code_end;
927 pcode = (cell_t *)dc->plugin->pcode;
929 if (PCODE_VAL(dc->pcode_map, cip) & PCM_HAS_BLOCK)
931 return sp_BlockFromMap(dc, graph, cip);
934 /* We can't add a new block if we hit our limit. */
935 assert(graph->used_blocks < graph->max_blocks);
936 if (graph->used_blocks >= graph->max_blocks)
943 /* Reserve a new block. */
944 block = &graph->blocks[graph->used_blocks++];
945 block->ip_start = cip;
947 /* Enter us into the map. */
948 sp_InsertBlock(dc, graph->used_blocks - 1, cip);
951 while (cip < cip_end)
953 /* Check whether this is the start of a new block. */
954 if (cip != block->ip_start
955 && (PCODE_VAL(dc->pcode_map, cip) & PCM_BRANCH_TARGET))
958 if ((outgoing = sp_BuildBlocks(dc, graph, cip)) == NULL)
962 /* :TODO: add edge */
967 op = PCODE_VAL(pcode, cip);
972 /* Check that branch offsets go to valid instructions. */
973 if (!(PCODE_VAL(dc->pcode_map, target) & PCM_OPCODE))
975 graph->err = SP_ERROR_INVALID_INSTRUCTION;
979 /* Get our target block. */
980 if ((outgoing = sp_BuildBlocks(dc, graph, target)) == NULL)
984 /* :TODO: add edge */
986 else if (op == OP_RETN /* :TODO: || op == OP_RET*/)
993 graph->err = SP_ERROR_INVALID_INSTRUCTION;
999 int Sp_DecompFunction(sp_decomp_t *dc, uint32_t code_addr, bool is_public)
1008 ControlFlowGraph graph;
1011 plugin = dc->plugin;
1012 memset(&graph, 0, sizeof(graph));
1014 if (code_addr >= plugin->pcode_size)
1016 err = SP_ERROR_INVALID_INSTRUCTION;
1020 pcode = (cell_t *)plugin->pcode;
1022 if (PCODE_VAL(pcode, code_addr) != OP_PROC)
1024 err = SP_ERROR_INVALID_INSTRUCTION;
1028 cip = code_addr + sizeof(cell_t);
1030 /* See if we have an existing function stored. */
1031 func = sp_GetFuncPrototype(dc, code_addr, true, is_public);
1033 while (cip < plugin->pcode_size)
1035 op = PCODE_VAL(pcode, cip);
1036 if (op >= OP_TOTAL || op < 0)
1038 err = SP_ERROR_INVALID_INSTRUCTION;
1040 if (dc->opdef[op].name == NULL)
1042 err = SP_ERROR_INVALID_INSTRUCTION;
1052 func->code_end = cip_end;
1054 /* Now we can cache all local vars. */
1055 sp_CacheLocals(dc, func);
1058 * Make the entry point as the first block.
1059 * It needs to be flagged as well so it doesn't get double counted.
1061 memset(&PCODE_VAL(dc->pcode_map, code_addr), 0, cip_end - code_addr);
1063 graph.max_blocks = 1;
1065 PCODE_VAL(dc->pcode_map, code_addr) |= PCM_BRANCH_TARGET;
1067 /* Walk the code. */
1074 while (cip < cip_end)
1077 op = PCODE_VAL(pcode, cip);
1078 /* Mark as not a branch */
1080 /* Make sure we know this is a valid target */
1081 PCODE_VAL(dc->pcode_map, cip) |= PCM_OPCODE;
1086 * Keep track of where branches are and how many blocks we need.
1088 if (!(PCODE_VAL(dc->pcode_map, target) & PCM_BRANCH_TARGET))
1090 PCODE_VAL(dc->pcode_map, target) |= PCM_BRANCH_TARGET;
1094 * If we're creating a new block, estimate that we need to create a new edge
1101 * In this algorithm, jumps do not terminate a block unless they are unconditional.
1102 * This reduces the number of blocks and edges.
1104 * A property of this is that jumps are edges, so the number of edges is identical
1105 * to the number of jumps.
1114 /* Initialize memory needed for the graph. */
1115 graph.blocks = new Block[graph.max_blocks];
1116 memset(graph.blocks, 0, sizeof(Block) * graph.max_blocks);
1118 if (graph.max_edges != 0)
1120 graph.edges = new Edge[graph.max_edges];
1121 memset(graph.edges, 0, sizeof(Edge) * graph.max_edges);
1124 if ((graph.entry = sp_BuildBlocks(dc, &graph, code_addr)) == NULL)
1126 if ((err = graph.err) == SP_ERROR_NONE)
1128 err = SP_ERROR_ABORTED;
1133 if ((err = sp_AnalyzeGraph(dc, &graph)) == NULL)
1138 return SP_ERROR_NONE;