sourcepawn/decompiler/code_analyzer.cpp
author David Anderson <dvander@alliedmods.net>
Tue Sep 23 21:20:40 2008 -0700 (2008-09-23)
changeset 2320 88550c031d23
child 2322 2125ced692ac
permissions -rw-r--r--
Initial import/sketch of opcode analyzer (bug 3279).
Uses single static assignment to recover expression trees from straight-line byte code.
     1 #include <assert.h>
     2 #include <string.h>
     3 #include <stdlib.h>
     4 #include "decompiler.h"
     5 #include "code_analyzer.h"
     6 #include "platform_util.h"
     7 
     8 struct Block;
     9 
    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
    14 
    15 #define NEXT_OP(cip, op)		cip += (dc->opdef[op].params + 1) * sizeof(cell_t)
    16 
    17 struct Edge
    18 {
    19 	Edge *next;
    20 	Block *target;
    21 	uint32_t ip;
    22 };
    23 
    24 struct Block
    25 {
    26 	cell_t ip_start;
    27 	cell_t ip_end;
    28 	Edge *edge_list;
    29 	Edge *final_edge;
    30 	Block *next_in_table;
    31 };
    32 
    33 struct ControlFlowGraph
    34 {
    35 	int err;
    36 	unsigned int max_blocks;
    37 	unsigned int max_edges;
    38 	unsigned int used_blocks;
    39 	unsigned int used_edges;
    40 	Block *blocks;
    41 	Edge *edges;
    42 	Block *entry;
    43 	FunctionInfo *func;
    44 };
    45 
    46 static FunctionInfo *sp_InferFuncPrototype(sp_decomp_t *dc, uint32_t code_addr, bool is_public)
    47 {
    48 	sp_tag_t *pTag;
    49 	sp_file_t *plugin;
    50 	FunctionInfo *info;
    51 	sp_fdbg_symbol_t *sym;
    52 
    53 	plugin = dc->plugin;
    54 	info = new FunctionInfo;
    55 	memset(info, 0, sizeof(FunctionInfo));
    56 
    57 	info->code_addr = code_addr;
    58 	
    59 	if ((sym = Sp_FindFunctionSym(plugin, code_addr)) != NULL)
    60 	{
    61 		Sp_Format(info->name, sizeof(info->name), "%s", plugin->debug.stringbase + sym->name);
    62 		if (sym->tagid != 0)
    63 		{
    64 			info->tag = Sp_FindTag(plugin, sym->tagid);
    65 		}
    66 	}
    67 	else
    68 	{
    69 		Sp_Format(info->name, sizeof(info->name), "function_%x", code_addr);
    70 		for (uint32_t i = 0; i < plugin->num_publics; i++)
    71 		{
    72 			if (plugin->publics[i].code_offs == code_addr)
    73 			{
    74 				Sp_Format(info->name,
    75 					sizeof(info->name),
    76 					"%s",
    77 					plugin->publics[i].name);
    78 				break;
    79 			}
    80 		}
    81 	}
    82 	info->sym = sym;
    83 	info->is_public = is_public;
    84 	
    85 
    86 	/* Search for all locals */
    87 	{
    88 		uint32_t i;
    89 		uint8_t *cursor;
    90 
    91 		cursor = (uint8_t *)plugin->debug.symbols;
    92 		for (i = 0; i < plugin->debug.syms_num; i++)
    93 		{
    94 			sym = (sp_fdbg_symbol_t *)cursor;
    95 
    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)
   100 			{
   101 				if (code_addr >= sym->codestart
   102 					&& code_addr < sym->codeend
   103 					&& sym->addr >= 0xC
   104 					&& (sym->addr & 0x3) == 0
   105 					&& ((sym->addr - 0xC) >> 2) < SP_MAX_EXEC_PARAMS
   106 					&& sym->vclass == 1)
   107 				{
   108 					unsigned int num;
   109 
   110 					num = (sym->addr - 0xC) >> 2;
   111 					info->known_args[num].sym = sym;
   112 					if (num + 1 > info->num_known_args)
   113 					{
   114 						info->num_known_args = num + 1;
   115 					}
   116 				}
   117 			}
   118 
   119 			cursor += sizeof(sp_fdbg_symbol_t);
   120 			if (sym->dimcount > 0)
   121 			{
   122 				cursor += sizeof(sp_fdbg_arraydim_t) * sym->dimcount;
   123 			}
   124 		}
   125 	}
   126 
   127 	/* Map all arguments into place. */
   128 	for (unsigned int i = 0; i < info->num_known_args; i++)
   129 	{
   130 		if ((sym = info->known_args[i].sym) == NULL)
   131 		{
   132 			continue;
   133 		}
   134 		if (sym->tagid != 0 && (pTag = Sp_FindTag(plugin, sym->tagid)) != NULL)
   135 		{
   136 			info->known_args[i].tag = pTag;
   137 		}
   138 		info->known_args[i].name = plugin->debug.stringbase + sym->name;
   139 		
   140 		if (sym->dimcount > 0)
   141 		{
   142 			info->known_args[i].dims = 
   143 				(sp_fdbg_arraydim_t *)((char *)sym + sizeof(sp_fdbg_symbol_t));
   144 		}
   145 	}
   146 
   147 	return info;
   148 }
   149 
   150 static FunctionInfo *sp_GetFuncPrototype(sp_decomp_t *dc,
   151 										 uint32_t code_addr,
   152 										 bool known,
   153 										 bool is_public = false);
   154 static FunctionInfo *sp_GetFuncPrototype(sp_decomp_t *dc,
   155 										 uint32_t code_addr,
   156 										 bool known,
   157 										 bool is_public)
   158 {
   159 	FunctionInfo *func;
   160 
   161 	func = dc->funcs;
   162 	while (func != NULL)
   163 	{
   164 		if (func->code_addr == code_addr)
   165 		{
   166 			return func;
   167 		}
   168 		func = func->next;
   169 	}
   170 
   171 	/* See if this is public. */
   172 	if (!known)
   173 	{
   174 		is_public = false;
   175 		for (unsigned int i = 0; i < dc->plugin->num_publics; i++)
   176 		{
   177 			if (dc->plugin->publics[i].code_offs == code_addr)
   178 			{
   179 				is_public = true;
   180 				break;
   181 			}
   182 		}
   183 	}
   184 
   185 	func = sp_InferFuncPrototype(dc, code_addr, is_public);
   186 	func->next = dc->funcs;
   187 	dc->funcs = func;
   188 
   189 	return func;
   190 }
   191 
   192 static void sp_CacheLocals(sp_decomp_t *dc, FunctionInfo *info)
   193 {
   194 	sp_file_t *plugin;
   195 	sp_fdbg_symbol_t *sym;
   196 
   197 	plugin = dc->plugin;
   198 
   199 	/* Search for all locals */
   200 	{
   201 		uint32_t i;
   202 		uint8_t *cursor;
   203 
   204 		cursor = (uint8_t *)plugin->debug.symbols;
   205 		for (i = 0; i < plugin->debug.syms_num; i++)
   206 		{
   207 			sym = (sp_fdbg_symbol_t *)cursor;
   208 
   209 			if ((sym->codestart >= info->code_addr && sym->codestart < info->code_end)
   210 				&& (sym->codeend <= info->code_end && sym->codeend >= info->code_addr)
   211 				&& sym->vclass == 1)
   212 			{
   213 				info->num_known_vars++;
   214 			}
   215 
   216 			cursor += sizeof(sp_fdbg_symbol_t);
   217 			if (sym->dimcount > 0)
   218 			{
   219 				cursor += sizeof(sp_fdbg_arraydim_t) * sym->dimcount;
   220 			}
   221 		}
   222 	}
   223 
   224 	/* Map all locals into place. */
   225 	if (info->num_known_vars)
   226 	{
   227 		uint32_t i, num;
   228 		uint8_t *cursor;
   229 
   230 		num = 0;
   231 		info->known_vars = new FuncVar[info->num_known_vars];
   232 		memset(info->known_vars, 0, sizeof(FuncVar) * info->num_known_vars);
   233 
   234 		cursor = (uint8_t *)plugin->debug.symbols;
   235 		for (i = 0; i < plugin->debug.syms_num; i++)
   236 		{
   237 			sym = (sp_fdbg_symbol_t *)cursor;
   238 
   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)
   243 			{
   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)
   247 					&& sym->vclass == 1)
   248 				{
   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 = 
   255 						(sym->dimcount == 0)
   256 						? NULL
   257 						: (sp_fdbg_arraydim_t *)(cursor + sizeof(sp_fdbg_symbol_t));
   258 					num++;
   259 				}
   260 			}
   261 
   262 			cursor += sizeof(sp_fdbg_symbol_t);
   263 			if (sym->dimcount > 0)
   264 			{
   265 				cursor += sizeof(sp_fdbg_arraydim_t) * sym->dimcount;
   266 			}
   267 		}
   268 
   269 		assert(num == info->num_known_vars);
   270 	}
   271 }
   272 
   273 static void sp_PrintFunctionPrototype(PrintBuffer *printer, sp_decomp_t *dc, FunctionInfo *func)
   274 {
   275 	FuncVar *var;
   276 	
   277 	if (func->is_public)
   278 	{
   279 		printer->Append("public ");
   280 	}
   281 	if (func->tag != NULL)
   282 	{
   283 		printer->Append("%s:", func->tag->name);
   284 	}
   285 	printer->Append("%s(", func->name);
   286 
   287 	for (unsigned int i = 0; i < func->num_known_args; i++)
   288 	{
   289 		var = &func->known_args[i];
   290 		if (var->sym == NULL)
   291 		{
   292 			printer->Append("unknown_arg_%d%s, ", i, i == func->num_known_args - 1 ? "" : ",");
   293 			continue;
   294 		}
   295 		if (var->sym->ident == SP_SYM_REFERENCE)
   296 		{
   297 			printer->Append("&");
   298 		}
   299 		if (var->tag != NULL)
   300 		{
   301 			printer->Append("%s:", var->tag->name);
   302 		}
   303 		printer->Append("%s", var->name);
   304 
   305 		if (var->sym->dimcount > 0)
   306 		{
   307 			sp_fdbg_arraydim_t *dims = 
   308 				(sp_fdbg_arraydim_t *)((char *)var->sym + sizeof(sp_fdbg_symbol_t));
   309 
   310 			for (uint16_t j = 0; j < var->sym->dimcount; j++)
   311 			{
   312 				if (dims[j].size == 0)
   313 				{
   314 					printer->Append("[]");
   315 				}
   316 				else
   317 				{
   318 					printer->Append("[%d]", dims[j].size);
   319 				}
   320 			}
   321 		}
   322 
   323 		if (i != func->num_known_args - 1)
   324 		{
   325 			printer->Append(", ");
   326 		}
   327 	}
   328 
   329 	printer->Append(")");
   330 }
   331 
   332 void sp_DebugExprTree(PrintBuffer *buffer, BaseNode *node, bool is_stmt=false)
   333 {
   334 	switch (node->op)
   335 	{
   336 	case OP_CALL:
   337 		{
   338 			CallNode *call = (CallNode *)node;
   339 
   340 			buffer->Append("%s(", call->func->name);
   341 			for (unsigned int i = 0; i < call->argc; i++)
   342 			{
   343 				sp_DebugExprTree(buffer, call->args[i], false);
   344 			}
   345 			buffer->Append(")");
   346 			break;
   347 		}
   348 	case _OP_VAR:
   349 		{
   350 			VarNode *var_node = (VarNode *)node;
   351 			buffer->Append("%s", var_node->var->name);
   352 			break;
   353 		}
   354 	case _OP_NEW:
   355 		{
   356 			DeclNode *d_node = (DeclNode *)node;
   357 
   358 			if (d_node->expr == NULL)
   359 			{
   360 				buffer->Append("decl ");
   361 				sp_DebugExprTree(buffer, d_node->var, true);
   362 			}
   363 			else
   364 			{
   365 				buffer->Append("new ");
   366 				sp_DebugExprTree(buffer, d_node->var, true);
   367 				buffer->Append(" = ");
   368 				sp_DebugExprTree(buffer, d_node->expr, true);
   369 			}
   370 
   371 			break;
   372 		}
   373 	case _OP_STMT:
   374 	case OP_RETN:
   375 		{
   376 			StmtNode *u_node = (StmtNode *)node;
   377 
   378 			while (u_node != NULL)
   379 			{
   380 				buffer->Append("\t");
   381 				if (u_node->op == OP_RETN)
   382 				{
   383 					buffer->Append("return ");
   384 				}
   385 				sp_DebugExprTree(buffer, u_node->node, true);
   386 				buffer->Append(";\n");
   387 				u_node = u_node->next;
   388 			}
   389 			break;
   390 		}
   391 	case _OP_CONST:
   392 		{
   393 			ConstNode *c_node = (ConstNode *)node;
   394 
   395 			buffer->Append("%d", c_node->val);
   396 
   397 			break;
   398 		}
   399 	case OP_ADD:
   400 	case OP_ADD_C:
   401 	case OP_SMUL:
   402 	case OP_SMUL_C:
   403 	case OP_SDIV:
   404 	case OP_SUB_ALT:
   405 	case _OP_STORE:
   406 	case _OP_MODULO:
   407 		{
   408 			BinOpNode *bin_node = (BinOpNode *)node;
   409 
   410 			if (!is_stmt)
   411 			{
   412 				buffer->Append("(");
   413 			}
   414 			sp_DebugExprTree(buffer, bin_node->left);
   415 
   416 			switch (node->op)
   417 			{
   418 			case OP_ADD:
   419 			case OP_ADD_C:
   420 				{
   421 					buffer->Append(" + ");
   422 					break;
   423 				}
   424 			case OP_SMUL:
   425 			case OP_SMUL_C:
   426 				{
   427 					buffer->Append(" * ");
   428 					break;
   429 				}
   430 			case _OP_STORE:
   431 				{
   432 					buffer->Append(" = ");
   433 					break;
   434 				}
   435 			case OP_SUB_ALT:
   436 				{
   437 					buffer->Append(" - ");
   438 					break;
   439 				}
   440 			case OP_SDIV:
   441 				{
   442 					buffer->Append(" / ");
   443 					break;
   444 				}
   445 			case _OP_MODULO:
   446 				{
   447 					buffer->Append(" % ");
   448 					break;
   449 				}
   450 			}
   451 
   452 			sp_DebugExprTree(buffer, bin_node->right, node->op == _OP_STORE);
   453 			if (!is_stmt)
   454 			{
   455 				buffer->Append(")");
   456 			}
   457 
   458 			break;
   459 		}
   460 	}
   461 }
   462 
   463 void sp_DebugPrint(FunctionInfo *info, sp_decomp_t *dc, BaseNode *node)
   464 {
   465 	PrintBuffer buffer;
   466 
   467 	sp_PrintFunctionPrototype(&buffer, dc, info);
   468 	buffer.Append("\n{\n");
   469 	sp_DebugExprTree(&buffer, node, true);
   470 	buffer.Append("}\n");
   471 	buffer.Dump(stdout);
   472 }
   473 
   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)))
   476 
   477 FuncVar *sp_FindGraphVar(FunctionInfo *func, ucell_t cip, cell_t sp, cell_t stack)
   478 {
   479 	if (stack >= 0xC)
   480 	{
   481 		if ((stack & 0x3) != 0)
   482 		{
   483 			return NULL;
   484 		}
   485 		stack -= 0xC;
   486 		stack >>= 2;
   487 		if (stack >= SP_MAX_EXEC_PARAMS)
   488 		{
   489 			return NULL;
   490 		}
   491 		if (func->known_args[stack].sym == NULL)
   492 		{
   493 			return NULL;
   494 		}
   495 		return &func->known_args[stack];
   496 	}
   497 	else if (stack < 0)
   498 	{
   499 		FuncVar *var;
   500 
   501 		if (stack < sp)
   502 		{
   503 			return NULL;
   504 		}
   505 
   506 		for (unsigned int i = 0; i < func->num_known_vars; i++)
   507 		{
   508 			var = &func->known_vars[i];
   509 
   510 			if (cip >= var->sym->codestart
   511 				&& cip <= var->sym->codeend
   512 				&& stack == var->sym->addr)
   513 			{
   514 				return var;
   515 			}
   516 		}
   517 
   518 		return NULL;
   519 	}
   520 	else
   521 	{
   522 		return NULL;
   523 	}
   524 }
   525 
   526 #define CHECK_VALUE(v)							\
   527 	assert(v != NULL);							\
   528 	if (v == NULL) {							\
   529 		err = SP_ERROR_INVALID_INSTRUCTION;		\
   530 		goto return_error;						\
   531 	}
   532 
   533 void *operator new(size_t size, ControlFlowGraph *graph)
   534 {
   535 	return malloc(size);
   536 }
   537 
   538 void *operator new[](size_t size, ControlFlowGraph *graph)
   539 {
   540 	return malloc(size);
   541 }
   542 
   543 void operator delete(void *mem, ControlFlowGraph *graph)
   544 {
   545 	free(mem);
   546 }
   547 
   548 void operator delete[](void *mem, ControlFlowGraph *graph)
   549 {
   550 	free(mem);
   551 }
   552 
   553 #define MAX_STACK_ENTRIES		256
   554 
   555 struct StackEntry
   556 {
   557 	StackEntry()
   558 	{
   559 	}
   560 	StackEntry(cell_t d, BaseNode *e) : depth(d), expr(e)
   561 	{
   562 	}
   563 	cell_t depth;
   564 	BaseNode *expr;
   565 };
   566 
   567 int sp_AnalyzeGraph(sp_decomp_t *dc, ControlFlowGraph *graph)
   568 {
   569 	int err;
   570 	cell_t sp;
   571 	Block *block;
   572 	cell_t *pcode;
   573 	cell_t cip, cip_end;
   574 	StmtNode *root, *rtemp;
   575 	StmtNode *root_tail;
   576 	BaseNode *pri, *alt;
   577 	FunctionInfo *func, *tfunc;
   578 	cell_t p1, p2, op;
   579 	FuncVar *v1, *v2;
   580 	unsigned int stack_entries = 0;
   581 	StackEntry eval_stack[MAX_STACK_ENTRIES];
   582 
   583 	/* Init everything.
   584 	 * Stack pointer starts off at 0.
   585 	 */
   586 	sp = 0;
   587 	pri = NULL;
   588 	alt = NULL;
   589 	root = NULL;
   590 	func = graph->func;
   591 	block = graph->entry;
   592 	pcode = (cell_t *)dc->plugin->pcode;
   593 
   594 	cip = block->ip_start;
   595 	cip_end = block->ip_end;
   596 
   597 	root_tail = root = new (graph) StmtNode(_OP_STMT, NULL, NULL);
   598 
   599 	while (cip < cip_end)
   600 	{
   601 		op = PCODE_VAL(pcode, cip);
   602 
   603 		switch (op)
   604 		{
   605 		case OP_PROC:
   606 		case OP_BREAK:
   607 			{
   608 				break;
   609 			}
   610 		case OP_CALL:
   611 			{
   612 				p1 = PCODE_PARAM(pcode, cip, 1);
   613 				tfunc = sp_GetFuncPrototype(dc, p1, false);
   614 				CHECK_VALUE(tfunc);
   615 
   616 				/* Sanity checks, :TODO: runtime checks later. */
   617 				assert(stack_entries >= 1);
   618 
   619 				ConstNode *cnode;
   620 				cnode = (ConstNode *)eval_stack[stack_entries-1].expr;
   621 				stack_entries--;
   622 
   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);
   628 				
   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--)
   632 				{
   633 					nodes[argno] = eval_stack[stack_entries-1].expr;
   634 				}
   635 
   636 				sp += (cnode->val + 1) * sizeof(cell_t);
   637 				assert(sp <= 0);
   638 
   639 				pri = new (graph) CallNode(tfunc, nodes, cnode->val);
   640 				
   641 				break;
   642 			}
   643 		case OP_CONST_PRI:
   644 			{
   645 				p1 = PCODE_PARAM(pcode, cip, 1);
   646 				pri = new (graph) ConstNode(p1);
   647 				break;
   648 			}
   649 		case OP_PUSH_C:
   650 			{
   651 				p1 = PCODE_PARAM(pcode, cip, 1);
   652 
   653 				/* Adjust stack pointer. */
   654 				sp -= sizeof(cell_t);
   655 
   656 				if ((v1 = sp_FindGraphVar(func, cip, sp, sp)) == NULL)
   657 				{
   658 					/* Add a new stack entry. */
   659 					assert(stack_entries < MAX_STACK_ENTRIES);
   660 					eval_stack[stack_entries++] = StackEntry(sp, new ConstNode(p1));
   661 				}
   662 				else
   663 				{
   664 					assert(v1->new_stmt == NULL);
   665 					if (v1->new_stmt == NULL)
   666 					{
   667 						v1->new_stmt = new (graph) DeclNode(
   668 							new (graph) VarNode(v1),
   669 							new (graph) ConstNode(p1));
   670 						rtemp = new (graph) StmtNode(
   671 							_OP_STMT,
   672 							v1->new_stmt,
   673 							NULL);
   674 						root_tail->next = rtemp;
   675 						root_tail = rtemp;
   676 					}
   677 				}
   678 				break;
   679 			}
   680 		case OP_PUSH_S:
   681 			{
   682 				p1 = PCODE_PARAM(pcode, cip, 1);
   683 				v1 = sp_FindGraphVar(func, cip, sp, p1);
   684 				CHECK_VALUE(v1);
   685 
   686 				/* Adjust stack pointer. */
   687 				sp -= sizeof(cell_t);
   688 
   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);
   692 
   693 				/* Add a new stack entry. */
   694 				eval_stack[stack_entries++] = StackEntry(sp, new (graph) VarNode(v1));
   695 				break;
   696 			}
   697 		case OP_PUSH_PRI:
   698 			{
   699 				CHECK_VALUE(pri);
   700 
   701 				/* Adjust stack pointer. */
   702 				sp -= sizeof(cell_t);
   703 				
   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);
   707 
   708 				/* Add a new stack entry. */
   709 				eval_stack[stack_entries++] = StackEntry(sp, pri);
   710 				break;
   711 			}
   712 		case OP_POP_ALT:
   713 			{
   714 				assert(stack_entries > 0);
   715 				assert(eval_stack[stack_entries - 1].depth == sp);
   716 
   717 				alt = eval_stack[--stack_entries].expr;
   718 				sp += sizeof(cell_t);
   719 				assert(sp <= 0);
   720 				break;
   721 			}
   722 		case OP_STACK:
   723 			{
   724 				p1 = PCODE_PARAM(pcode, cip, 1);
   725 				sp += p1;
   726 				assert(sp <= 0);
   727 				if (p1 < 0)
   728 				{
   729 					/* Find if we should track a new variable declaration. */
   730 					v1 = sp_FindGraphVar(func, cip, sp, sp);
   731 					CHECK_VALUE(v1);
   732 					assert(v1->new_stmt == NULL);
   733 					if (v1->new_stmt == NULL)
   734 					{
   735 						v1->new_stmt = new (graph) DeclNode(
   736 							new (graph) VarNode(v1),
   737 							NULL);
   738 						rtemp = new (graph) StmtNode(
   739 							_OP_STMT,
   740 							v1->new_stmt,
   741 							NULL);
   742 						root_tail->next = rtemp;
   743 						root_tail = rtemp;
   744 					}
   745 					assert(abs(p1) >> 2 == 1);
   746 				}
   747 				else
   748 				{
   749 					/* Erase anything left over on the evaluation stack. */
   750 					while (stack_entries > 0
   751 						   && eval_stack[stack_entries - 1].depth < sp)
   752 					{
   753 						assert(0);
   754 						stack_entries--;
   755 					}
   756 				}
   757 				break;
   758 			}
   759 		case OP_ZERO_PRI:
   760 			{
   761 				pri = new (graph) ConstNode(0);
   762 				break;
   763 			}
   764 		case OP_MOVE_ALT:
   765 			{
   766 				CHECK_VALUE(pri);
   767 				alt = pri;
   768 				break;
   769 			}
   770 		case OP_LOAD_S_PRI:
   771 			{
   772 				p1 = PCODE_PARAM(pcode, cip, 1);
   773 				v1 = sp_FindGraphVar(func, cip, sp, p1);
   774 				CHECK_VALUE(v1);
   775 				pri = new (graph) VarNode(v1);
   776 				break;
   777 			}
   778 		case OP_LOAD_S_ALT:
   779 			{
   780 				p1 = PCODE_PARAM(pcode, cip, 1);
   781 				v1 = sp_FindGraphVar(func, cip, sp, p1);
   782 				CHECK_VALUE(v1);
   783 				alt = new (graph) VarNode(v1);
   784 				break;
   785 			}
   786 		case OP_STOR_S_PRI:
   787 			{
   788 				p1 = PCODE_PARAM(pcode, cip, 1);
   789 				v1 = sp_FindGraphVar(func, cip, sp, p1);
   790 				CHECK_VALUE(v1);
   791 				CHECK_VALUE(pri);
   792 				rtemp = new (graph) StmtNode(
   793 					_OP_STMT,
   794 					new (graph) BinOpNode(_OP_STORE, new (graph) VarNode(v1), pri),
   795 					NULL);
   796 				root_tail->next = rtemp;
   797 				root_tail = rtemp;
   798 
   799 				/** 
   800 				 * We create a varnode to simulate a load here.
   801 				 * This helps accidental duplication of the expression tree.
   802 				 */
   803 				pri = new (graph) VarNode(v1);	
   804 				break;
   805 			}
   806 		case OP_LOAD_S_BOTH:
   807 			{
   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);
   812 				CHECK_VALUE(v1);
   813 				CHECK_VALUE(v2);
   814 				pri = new (graph) VarNode(v1);
   815 				alt = new (graph) VarNode(v2);
   816 				break;
   817 			}
   818 		case OP_ADD:
   819 		case OP_SMUL:
   820 			{
   821 				CHECK_VALUE(pri);
   822 				CHECK_VALUE(alt);
   823 				pri = new (graph) BinOpNode(op, pri, alt);
   824 				break;
   825 			}
   826 		case OP_SUB_ALT:
   827 			{
   828 				CHECK_VALUE(pri);
   829 				CHECK_VALUE(alt);
   830 				pri = new (graph) BinOpNode(op, alt, pri);
   831 				break;
   832 			}
   833 		case OP_SDIV:
   834 			{
   835 				CHECK_VALUE(pri);
   836 				CHECK_VALUE(alt);
   837 				pri = new (graph) BinOpNode(OP_SDIV, pri, alt);
   838 				alt = new (graph) BinOpNode(_OP_MODULO, pri, alt);
   839 				break;
   840 			}
   841 		case OP_SDIV_ALT:
   842 			{
   843 				CHECK_VALUE(pri);
   844 				CHECK_VALUE(alt);
   845 				pri = new (graph) BinOpNode(OP_SDIV, alt, pri);
   846 				alt = new (graph) BinOpNode(_OP_MODULO, alt, pri);
   847 				break;
   848 			}
   849 		case OP_ADD_C:
   850 		case OP_SMUL_C:
   851 			{
   852 				p1 = PCODE_PARAM(pcode, cip, 1);
   853 				CHECK_VALUE(pri);
   854 				pri = new (graph) BinOpNode(op, pri, new (graph) ConstNode(p1));
   855 				break;
   856 			}
   857 		case OP_RETN:
   858 			{
   859 				CHECK_VALUE(pri);
   860 				rtemp = new (graph) StmtNode(op, pri, NULL);
   861 				root_tail->next = rtemp;
   862 				root_tail = rtemp;
   863 				break;
   864 			}
   865 		default:
   866 			{
   867 				assert(0);
   868 				break;
   869 			}
   870 		}
   871 
   872 		NEXT_OP(cip, op);
   873 	}
   874 
   875 	sp_DebugPrint(graph->func, dc, root->next);
   876 
   877 	return SP_ERROR_NONE;
   878 
   879 return_error:
   880 	return err;
   881 }
   882 
   883 #undef CHECK_FUNCVAR
   884 
   885 inline Block *sp_BlockFromMap(sp_decomp_t *dc, ControlFlowGraph *graph, cell_t cip)
   886 {
   887 	cell_t val;
   888 
   889 	assert(PCODE_VAL(dc->pcode_map, cip) & PCM_HAS_BLOCK);
   890 
   891 	val = PCODE_VAL(dc->pcode_map, cip);
   892 	val >>= PCM_NUM_BITS;
   893 
   894 	assert(val >= 0 && val < (cell_t)graph->used_blocks);
   895 
   896 	return &graph->blocks[val];
   897 }
   898 
   899 void sp_InsertBlock(sp_decomp_t *dc, unsigned int index, cell_t cip)
   900 {
   901 	cell_t val;
   902 
   903 	val = PCODE_VAL(dc->pcode_map, cip);
   904 
   905 	assert(!(val & PCM_HAS_BLOCK));
   906 	assert(index < 0x20000000);
   907 
   908 	val |= PCM_HAS_BLOCK;
   909 	val |= index << 3;
   910 
   911 	PCODE_VAL(dc->pcode_map, cip) = val;
   912 }
   913 
   914 static Block *sp_BuildBlocks(sp_decomp_t *dc, ControlFlowGraph *graph, cell_t cip)
   915 {
   916 	cell_t op;
   917 	bool is_branch;
   918 	cell_t target;
   919 	Block *block;
   920 	Edge *edge_tail;
   921 	Block *outgoing;
   922 	cell_t cip_end;
   923 	cell_t *pcode;
   924 
   925 	target = 0;
   926 	cip_end = graph->func->code_end;
   927 	pcode = (cell_t *)dc->plugin->pcode;
   928 
   929 	if (PCODE_VAL(dc->pcode_map, cip) & PCM_HAS_BLOCK)
   930 	{
   931 		return sp_BlockFromMap(dc, graph, cip);
   932 	}
   933 
   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)
   937 	{
   938 		return NULL;
   939 	}
   940 
   941 	edge_tail = NULL;
   942 
   943 	/* Reserve a new block. */
   944 	block = &graph->blocks[graph->used_blocks++];
   945 	block->ip_start = cip;
   946 	
   947 	/* Enter us into the map. */
   948 	sp_InsertBlock(dc, graph->used_blocks - 1, cip);
   949 
   950 	/* Walk the code. */
   951 	while (cip < cip_end)
   952 	{
   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))
   956 		{
   957 			block->ip_end = cip;
   958 			if ((outgoing = sp_BuildBlocks(dc, graph, cip)) == NULL)
   959 			{
   960 				return NULL;
   961 			}
   962 			/* :TODO: add edge */
   963 			return block;
   964 		}
   965 
   966 		is_branch = false;
   967 		op = PCODE_VAL(pcode, cip);
   968 		NEXT_OP(cip, op);
   969 
   970 		if (is_branch)
   971 		{
   972 			/* Check that branch offsets go to valid instructions. */
   973 			if (!(PCODE_VAL(dc->pcode_map, target) & PCM_OPCODE))
   974 			{
   975 				graph->err = SP_ERROR_INVALID_INSTRUCTION;
   976 				return NULL;
   977 			}
   978 
   979 			/* Get our target block. */
   980 			if ((outgoing = sp_BuildBlocks(dc, graph, target)) == NULL)
   981 			{
   982 				return NULL;
   983 			}
   984 			/* :TODO: add edge */
   985 		}
   986 		else if (op == OP_RETN /* :TODO: || op == OP_RET*/)
   987 		{
   988 			block->ip_end = cip;
   989 			return block;
   990 		}
   991 	}
   992 
   993 	graph->err = SP_ERROR_INVALID_INSTRUCTION;
   994 
   995 	return NULL;
   996 }
   997 
   998 
   999 int Sp_DecompFunction(sp_decomp_t *dc, uint32_t code_addr, bool is_public)
  1000 {
  1001 	int err;
  1002 	cell_t op;
  1003 	ucell_t cip;
  1004 	cell_t *pcode;
  1005 	ucell_t cip_end;
  1006 	sp_file_t *plugin;
  1007 	FunctionInfo *func;
  1008 	ControlFlowGraph graph;
  1009 	
  1010 	func = NULL;
  1011 	plugin = dc->plugin;
  1012 	memset(&graph, 0, sizeof(graph));
  1013 
  1014 	if (code_addr >= plugin->pcode_size)
  1015 	{
  1016 		err = SP_ERROR_INVALID_INSTRUCTION;
  1017 		goto return_error;
  1018 	}
  1019 
  1020 	pcode = (cell_t *)plugin->pcode;
  1021 
  1022 	if (PCODE_VAL(pcode, code_addr) != OP_PROC)
  1023 	{
  1024 		err = SP_ERROR_INVALID_INSTRUCTION;
  1025 		goto return_error;
  1026 	}
  1027 
  1028 	cip = code_addr + sizeof(cell_t);
  1029 
  1030 	/* See if we have an existing function stored. */
  1031 	func = sp_GetFuncPrototype(dc, code_addr, true, is_public);
  1032 
  1033 	while (cip < plugin->pcode_size)
  1034 	{
  1035 		op = PCODE_VAL(pcode, cip);
  1036 		if (op >= OP_TOTAL || op < 0)
  1037 		{
  1038 			err = SP_ERROR_INVALID_INSTRUCTION;
  1039 		}
  1040 		if (dc->opdef[op].name == NULL)
  1041 		{
  1042 			err = SP_ERROR_INVALID_INSTRUCTION;
  1043 		}
  1044 		if (op == OP_PROC)
  1045 		{
  1046 			break;
  1047 		}
  1048 		NEXT_OP(cip, op);
  1049 	}
  1050 	cip_end = cip;
  1051 
  1052 	func->code_end = cip_end;
  1053 
  1054 	/* Now we can cache all local vars. */
  1055 	sp_CacheLocals(dc, func);
  1056 
  1057 	/** 
  1058 	 * Make the entry point as the first block.
  1059 	 * It needs to be flagged as well so it doesn't get double counted.
  1060 	 */
  1061 	memset(&PCODE_VAL(dc->pcode_map, code_addr), 0, cip_end - code_addr);
  1062 		   
  1063 	graph.max_blocks = 1;
  1064 	graph.func = func;
  1065 	PCODE_VAL(dc->pcode_map, code_addr) |= PCM_BRANCH_TARGET;
  1066 
  1067 	/* Walk the code. */
  1068 	{
  1069 		cell_t target;
  1070 		bool is_branch;
  1071 
  1072 		target = 0;
  1073 		cip = code_addr;
  1074 		while (cip < cip_end)
  1075 		{
  1076 			/* Get opcode */
  1077 			op = PCODE_VAL(pcode, cip);
  1078 			/* Mark as not a branch */
  1079 			is_branch = false;
  1080 			/* Make sure we know this is a valid target */
  1081 			PCODE_VAL(dc->pcode_map, cip) |= PCM_OPCODE;
  1082 
  1083 			if (is_branch)
  1084 			{
  1085 				/**
  1086 				 * Keep track of where branches are and how many blocks we need.
  1087 				 */
  1088 				if (!(PCODE_VAL(dc->pcode_map, target) & PCM_BRANCH_TARGET))
  1089 				{
  1090 					PCODE_VAL(dc->pcode_map, target) |= PCM_BRANCH_TARGET;
  1091 					graph.max_blocks++;
  1092 
  1093 					/**
  1094 					 * If we're creating a new block, estimate that we need to create a new edge 
  1095 					 * as well.
  1096 					 */
  1097 					graph.max_edges++;
  1098 				}
  1099 
  1100                 /**
  1101                  * In this algorithm, jumps do not terminate a block unless they are unconditional.
  1102                  * This reduces the number of blocks and edges.
  1103                  *
  1104                  * A property of this is that jumps are edges, so the number of edges is identical 
  1105 				 * to the number of jumps.
  1106                  */
  1107 				graph.max_edges++;
  1108 			}
  1109 
  1110 			NEXT_OP(cip, op);
  1111 		}
  1112 	}
  1113 
  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);
  1117 	
  1118 	if (graph.max_edges != 0)
  1119 	{
  1120 		graph.edges = new Edge[graph.max_edges];
  1121 		memset(graph.edges, 0, sizeof(Edge) * graph.max_edges);
  1122 	}
  1123 
  1124 	if ((graph.entry = sp_BuildBlocks(dc, &graph, code_addr)) == NULL)
  1125 	{
  1126 		if ((err = graph.err) == SP_ERROR_NONE)
  1127 		{
  1128 			err = SP_ERROR_ABORTED;
  1129 		}
  1130 		goto return_error;
  1131 	}
  1132 
  1133 	if ((err = sp_AnalyzeGraph(dc, &graph)) == NULL)
  1134 	{
  1135 		goto return_error;
  1136 	}
  1137 
  1138 	return SP_ERROR_NONE;
  1139 
  1140 return_error:
  1141 	return err;
  1142 }