From cf4cbad2e74bbcec4f508026c4b5537c246ecf4e Mon Sep 17 00:00:00 2001 From: Humberto Date: Tue, 12 May 2009 07:18:38 -0300 Subject: [PATCH] Varias mudancas --- analyser.c | 20 +- cfg.c | 2 + code.h | 54 +++-- constants.c | 6 +- dataflow.c | 2 +- liveness.c | 8 +- main.c | 2 +- operations.c | 17 +- outcode.c | 205 +++++++++-------- outgraph.c | 41 ++-- output.c | 84 +++++-- output.h | 2 +- relocs.c | 4 +- structures.c | 694 +++++++++++++++++++++++++++++++--------------------------- subroutines.c | 6 +- 15 files changed, 644 insertions(+), 503 deletions(-) rewrite structures.c (62%) diff --git a/analyser.c b/analyser.c index 445c90a..e1108ed 100644 --- a/analyser.c +++ b/analyser.c @@ -49,22 +49,22 @@ struct code* code_analyse (struct prx *p) if (!sub->import && !sub->haserror) { cfg_traverse (sub, FALSE); if (!sub->haserror) { - sub->status |= SUBROUTINE_CFG_TRAVERSE; + sub->status |= SUB_STAT_CFG_TRAVERSE; cfg_traverse (sub, TRUE); } if (!sub->haserror) { - sub->status |= SUBROUTINE_CFG_TRAVERSE_REV; + sub->status |= SUB_STAT_CFG_TRAVERSE_REV; fixup_call_arguments (sub); } if (!sub->haserror) { - sub->status |= SUBROUTINE_FIXUP_CALL_ARGS; + sub->status |= SUB_STAT_FIXUP_CALL_ARGS; build_ssa (sub); } if (!sub->haserror) { - sub->status |= SUBROUTINE_SSA; + sub->status |= SUB_STAT_SSA; } } el = element_next (el); @@ -76,31 +76,31 @@ struct code* code_analyse (struct prx *p) while (el) { sub = element_getvalue (el); if (!sub->import && !sub->haserror) { - if (!(sub->status & SUBROUTINE_FIXUP_CALL_ARGS)) { + if (!(sub->status & SUB_STAT_FIXUP_CALL_ARGS)) { fixup_call_arguments (sub); if (!sub->haserror) { - sub->status |= SUBROUTINE_FIXUP_CALL_ARGS; + sub->status |= SUB_STAT_FIXUP_CALL_ARGS; build_ssa (sub); } } if (!sub->haserror) { - sub->status |= SUBROUTINE_SSA; + sub->status |= SUB_STAT_SSA; propagate_constants (sub); } if (!sub->haserror) { - sub->status |= SUBROUTINE_CONSTANTS_EXTRACTED; + sub->status |= SUB_STAT_CONSTANTS_EXTRACTED; extract_variables (sub); } if (!sub->haserror) { - sub->status |= SUBROUTINE_VARIABLES_EXTRACTED; + sub->status |= SUB_STAT_VARIABLES_EXTRACTED; extract_structures (sub); } if (!sub->haserror) { - sub->status |= SUBROUTINE_STRUCTURES_EXTRACTED; + sub->status |= SUB_STAT_STRUCTURES_EXTRACTED; } } el = element_next (el); diff --git a/cfg.c b/cfg.c index 9036147..42b4dce 100644 --- a/cfg.c +++ b/cfg.c @@ -207,10 +207,12 @@ void link_blocks (struct subroutine *sub) } else { element ref; if (loc->cswitch && loc->cswitch->jumplocation == loc) { + block->status |= BLOCK_STAT_ISSWITCH; ref = list_head (loc->cswitch->references); while (ref) { struct location *switchtarget = element_getvalue (ref); make_link (block, switchtarget->block); + switchtarget->block->status |= BLOCK_STAT_ISSWITCHTARGET; ref = element_next (ref); } } else diff --git a/code.h b/code.h index b59bd7f..d7ddfa2 100644 --- a/code.h +++ b/code.h @@ -16,20 +16,28 @@ #define IMMU(op) ((unsigned short) (op & 0xFFFF)) /* Subroutine decompilation status */ -#define SUBROUTINE_EXTRACTED 1 -#define SUBROUTINE_CFG_EXTRACTED 2 -#define SUBROUTINE_OPERATIONS_EXTRACTED 4 -#define SUBROUTINE_LIVE_REGISTERS 8 -#define SUBROUTINE_CFG_TRAVERSE 16 -#define SUBROUTINE_CFG_TRAVERSE_REV 32 -#define SUBROUTINE_FIXUP_CALL_ARGS 64 -#define SUBROUTINE_SSA 128 -#define SUBROUTINE_CONSTANTS_EXTRACTED 256 -#define SUBROUTINE_VARIABLES_EXTRACTED 512 -#define SUBROUTINE_STRUCTURES_EXTRACTED 1024 +#define SUB_STAT_EXTRACTED 1 +#define SUB_STAT_CFG_EXTRACTED 2 +#define SUB_STAT_OPERATIONS_EXTRACTED 4 +#define SUB_STAT_LIVE_REGISTERS 8 +#define SUB_STAT_CFG_TRAVERSE 16 +#define SUB_STAT_CFG_TRAVERSE_REV 32 +#define SUB_STAT_FIXUP_CALL_ARGS 64 +#define SUB_STAT_SSA 128 +#define SUB_STAT_CONSTANTS_EXTRACTED 256 +#define SUB_STAT_VARIABLES_EXTRACTED 512 +#define SUB_STAT_STRUCTURES_EXTRACTED 1024 /* Operation status */ -#define OPERATION_DEFERRED 1 +#define OP_STAT_DEFERRED 1 +#define OP_STAT_HASRELOC 2 + +/* Block status */ +#define BLOCK_STAT_HASLABEL 1 +#define BLOCK_STAT_ISSWITCH 2 +#define BLOCK_STAT_ISSWITCHTARGET 4 +#define BLOCK_STAT_REVCOND 8 +#define BLOCK_STAT_HASELSE 16 /* Register values */ @@ -73,10 +81,10 @@ #define MAX_SUB_ARGS 8 - #define IS_BIT_SET(flags, bit) ((1 << ((bit) & 31)) & ((flags)[(bit) >> 5])) #define BIT_SET(flags, bit) ((flags)[(bit) >> 5]) |= 1 << ((bit) & 31) + extern const uint32 regmask_call_gen[NUM_REGMASK]; extern const uint32 regmask_call_kill[NUM_REGMASK]; extern const uint32 regmask_subend_gen[NUM_REGMASK]; @@ -197,7 +205,9 @@ struct basicblock { uint32 reg_gen[NUM_REGMASK], reg_kill[NUM_REGMASK]; uint32 reg_live_in[NUM_REGMASK], reg_live_out[NUM_REGMASK]; + list operations; + struct subroutine *sub; /* The owner subroutine */ struct basicblocknode node; /* Node info for DFS and DOM trees */ @@ -205,8 +215,8 @@ struct basicblock { list inrefs, outrefs; /* A list of in- and out-edges of this block */ - struct ctrlstruct *st, *loopst; - int haslabel, identsize; + struct ctrlstruct *st, *ifst, *loopst; + int blockcond, status; int mark1, mark2; }; @@ -214,9 +224,12 @@ struct basicblock { enum edgetype { EDGE_UNKNOWN = 0, EDGE_GOTO, + EDGE_INVALID, EDGE_CONTINUE, EDGE_BREAK, - EDGE_FOLLOW, + EDGE_CASE, + EDGE_NEXT, + EDGE_IFENTER, EDGE_IFEXIT }; @@ -300,7 +313,8 @@ struct operation { enum ctrltype { CONTROL_LOOP, CONTROL_SWITCH, - CONTROL_IF + CONTROL_IF, + CONTROL_MAIN }; enum looptype { @@ -313,13 +327,15 @@ struct ctrlstruct { enum ctrltype type; struct basicblock *start; struct basicblock *end; + struct ctrlstruct *parent; int hasendgoto; + int identsize; + union { struct { - int isoutermost; + int endfollow; } ifctrl; struct { - enum looptype type; list edges; } loopctrl; } info; diff --git a/constants.c b/constants.c index 3bc0ba1..1a1ef61 100644 --- a/constants.c +++ b/constants.c @@ -99,7 +99,7 @@ void propagate_constants (struct subroutine *sub) if (var->def->type == OP_MOVE) { val = list_headvalue (var->def->operands); temp.info = get_constant_value (val); - var->def->status |= OPERATION_DEFERRED; + var->def->status |= OP_STAT_DEFERRED; } else if (var->def->type == OP_INSTRUCTION) { uint32 val1, val2; switch (var->def->info.iop.insn) { @@ -108,13 +108,13 @@ void propagate_constants (struct subroutine *sub) val1 = get_constant_value (list_headvalue (var->def->operands)); val2 = get_constant_value (list_tailvalue (var->def->operands)); temp.info = val1 + val2; - var->def->status |= OPERATION_DEFERRED; + var->def->status |= OP_STAT_DEFERRED; break; case I_OR: val1 = get_constant_value (list_headvalue (var->def->operands)); val2 = get_constant_value (list_tailvalue (var->def->operands)); temp.info = val1 | val2; - var->def->status |= OPERATION_DEFERRED; + var->def->status |= OP_STAT_DEFERRED; break; default: temp.type = SSAVAR_UNK; diff --git a/dataflow.c b/dataflow.c index 3381d17..3fffaaf 100644 --- a/dataflow.c +++ b/dataflow.c @@ -81,7 +81,7 @@ void extract_variables (struct subroutine *sub) } if (istemp) { - var->def->status |= OPERATION_DEFERRED; + var->def->status |= OP_STAT_DEFERRED; var->type = SSAVAR_TEMP; var->info = 0; } else { diff --git a/liveness.c b/liveness.c index f223f7c..5816ae7 100644 --- a/liveness.c +++ b/liveness.c @@ -47,7 +47,7 @@ void live_analysis (list worklist) } } - if (sub->status & SUBROUTINE_OPERATIONS_EXTRACTED) { + if (sub->status & SUB_STAT_OPERATIONS_EXTRACTED) { changed = FALSE; for (regno = REGISTER_GPR_V0; regno <= REGISTER_GPR_V1; regno++) { if (IS_BIT_SET (block->reg_live_in, regno)) { @@ -100,7 +100,7 @@ void live_registers (struct code *c) struct subroutine *sub = element_getvalue (el); if (!sub->import && !sub->haserror) { reset_marks (sub); - sub->status |= SUBROUTINE_LIVE_REGISTERS; + sub->status |= SUB_STAT_LIVE_REGISTERS; sub->endblock->mark1 = 1; list_inserthead (worklist, sub->endblock); } @@ -151,7 +151,7 @@ void live_registers_imports (struct code *c) struct basicblock *block = element_getvalue (ref); struct subroutine *target = block->sub; - target->status &= ~(SUBROUTINE_SSA | SUBROUTINE_FIXUP_CALL_ARGS); + target->status &= ~(SUB_STAT_SSA | SUB_STAT_FIXUP_CALL_ARGS); ref = element_next (ref); } } @@ -163,7 +163,7 @@ void live_registers_imports (struct code *c) while (el) { struct subroutine *sub = element_getvalue (el); if (!sub->import && !sub->haserror && - !(sub->status & SUBROUTINE_SSA)) { + !(sub->status & SUB_STAT_SSA)) { unbuild_ssa (sub); remove_call_arguments (sub); } diff --git a/main.c b/main.c index 52e9e4e..519d361 100644 --- a/main.c +++ b/main.c @@ -114,7 +114,7 @@ int main (int argc, char **argv) print_graph (c, prxfilename, graphoptions); if (printcode) - print_code (c, prxfilename, verbosity); + print_code (c, prxfilename); code_free (c); diff --git a/operations.c b/operations.c index 8c31f84..0721509 100644 --- a/operations.c +++ b/operations.c @@ -195,10 +195,12 @@ void extract_operations (struct subroutine *sub) struct operation *op; struct basicblock *block; struct location *loc; + struct prx *file; uint32 asm_gen[NUM_REGMASK], asm_kill[NUM_REGMASK]; - int i, regno, lastasm; + int i, regno, lastasm, relocnum; element el; + file = sub->code->file; el = list_head (sub->blocks); while (el) { block = element_getvalue (el); @@ -210,10 +212,21 @@ void extract_operations (struct subroutine *sub) switch (block->type) { case BLOCK_SIMPLE: lastasm = FALSE; + relocnum = prx_findrelocbyaddr (file, block->info.simple.begin->address); + for (i = 0; i < NUM_REGMASK; i++) asm_gen[i] = asm_kill[i] = 0; for (loc = block->info.simple.begin; ; loc++) { + int hasreloc = FALSE; + + if (relocnum < file->relocnum) { + if (file->relocsbyaddr[relocnum].vaddr == loc->address) { + hasreloc = TRUE; + relocnum++; + } + } + if (INSN_TYPE (loc->insn->flags) == INSN_ALLEGREX) { enum allegrex_insn insn; @@ -223,6 +236,8 @@ void extract_operations (struct subroutine *sub) op = operation_alloc (block); op->type = OP_INSTRUCTION; + if (hasreloc) + op->status |= OP_STAT_HASRELOC; op->info.iop.loc = loc; if (loc->insn->flags & INSN_READ_GPR_S) { diff --git a/outcode.c b/outcode.c index df79c58..131ee45 100644 --- a/outcode.c +++ b/outcode.c @@ -7,7 +7,7 @@ static -void print_block (FILE *out, struct basicblock *block, int reversecond) +void print_block (FILE *out, struct basicblock *block, int identsize, int reversecond) { element opel; struct operation *jumpop = NULL; @@ -17,152 +17,147 @@ void print_block (FILE *out, struct basicblock *block, int reversecond) opel = list_head (block->operations); while (opel) { struct operation *op = element_getvalue (opel); - if (!(op->status & OPERATION_DEFERRED)) { + if (!(op->status & OP_STAT_DEFERRED)) { if (op->type == OP_INSTRUCTION) { if (op->info.iop.loc->insn->flags & (INSN_JUMP | INSN_BRANCH)) jumpop = op; } if (op != jumpop) - print_operation (out, op, block->identsize + 1, options); + print_operation (out, op, identsize, options); } opel = element_next (opel); } if (jumpop) - print_operation (out, jumpop, block->identsize + 1, options); + print_operation (out, jumpop, identsize, options); } static -void print_block_recursive (FILE *out, struct basicblock *block, int verbosity) +void print_block_recursive (FILE *out, struct basicblock *block) { - struct basicedge *edge; - int reversecond = FALSE, haselse = FALSE; element ref; + struct basicedge *edge; + int identsize = block->st->identsize; + int revcond = block->status & BLOCK_STAT_REVCOND; + int first = TRUE, isloop = FALSE; + + if (block->status & BLOCK_STAT_ISSWITCHTARGET) { + ref = list_head (block->inrefs); + while (ref) { + edge = element_getvalue (ref); + if (edge->from->status & BLOCK_STAT_ISSWITCH) { + ident_line (out, identsize); + fprintf (out, "case %d:\n", edge->fromnum); + } + ref = element_next (ref); + } + } - block->mark1 = 1; - - if (block->haslabel) { + if (block->status & BLOCK_STAT_HASLABEL) { fprintf (out, "\n"); - ident_line (out, block->identsize); + ident_line (out, identsize); fprintf (out, "label%d:\n", block->node.dfsnum); } - if (block->loopst) { - if (block->loopst->start == block) { - ident_line (out, block->identsize); - fprintf (out, "loop {\n"); - } - } - - if (verbosity > 2) { - ident_line (out, block->identsize + 1); - fprintf (out, "/* Block %d ", block->node.dfsnum); - if (block->type == BLOCK_SIMPLE) { - fprintf (out, "Address 0x%08X ", block->info.simple.begin->address); - } - fprintf (out, "*/\n"); + if (block->st->start == block && block->st->type == CONTROL_LOOP) { + isloop = TRUE; + ident_line (out, identsize); + fprintf (out, "while (1) {\n"); } - if (block->st) { - struct basicedge *edge1, *edge2; - - edge1 = list_headvalue (block->outrefs); - edge2 = list_tailvalue (block->outrefs); + block->mark1 = 1; + print_block (out, block, identsize + 1, revcond); - if (edge1->type != EDGE_IFEXIT && - edge2->type != EDGE_IFEXIT) { - haselse = TRUE; - } else { - if (edge2->type == EDGE_IFEXIT) - reversecond = TRUE; - } + if (block->status & BLOCK_STAT_ISSWITCH) { + revcond = TRUE; + ident_line (out, identsize + 1); + fprintf (out, "switch () {\n"); } - print_block (out, block, reversecond); - - - if (reversecond) - ref = list_tail (block->outrefs); - else - ref = list_head (block->outrefs); + if (revcond) ref = list_head (block->outrefs); + else ref = list_tail (block->outrefs); while (ref) { edge = element_getvalue (ref); + if (edge->type != EDGE_CASE && edge->type != EDGE_NEXT && + edge->type != EDGE_IFEXIT && edge->type != EDGE_UNKNOWN) { + ident_line (out, identsize + 1); + if (first && list_size (block->outrefs) == 2 && + !(block->status & BLOCK_STAT_ISSWITCH) && edge->type != EDGE_IFENTER) + ident_line (out, 1); + } - if (edge->type == EDGE_FOLLOW) { - if (block->st) { - ident_line (out, block->identsize + 1); - fprintf (out, "{\n"); - } - print_block_recursive (out, edge->to, verbosity); - if (block->st) { - ident_line (out, block->identsize + 1); - fprintf (out, "}\n"); - } - } else if (edge->type != EDGE_IFEXIT) { - int identsize = block->identsize + 1; - if (block->st) identsize++; - ident_line (out, identsize); - switch (edge->type) { - case EDGE_GOTO: fprintf (out, "goto label%d;\n", edge->to->node.dfsnum); break; - case EDGE_BREAK: fprintf (out, "break;\n"); break; - case EDGE_CONTINUE: fprintf (out, "continue;\n"); break; - default: - break; - } + switch (edge->type) { + case EDGE_BREAK: + fprintf (out, "break;\n"); + break; + case EDGE_CONTINUE: + fprintf (out, "continue;\n"); + break; + case EDGE_INVALID: + case EDGE_GOTO: + fprintf (out, "goto label%d;\n", edge->to->node.dfsnum); + break; + case EDGE_UNKNOWN: + case EDGE_IFEXIT: + break; + case EDGE_CASE: + if (!edge->to->mark1) + print_block_recursive (out, edge->to); + break; + case EDGE_NEXT: + print_block_recursive (out, edge->to); + break; + case EDGE_IFENTER: + fprintf (out, "{\n"); + print_block_recursive (out, edge->to); + ident_line (out, identsize + 1); + fprintf (out, "}\n"); + break; } - if (reversecond) - ref = element_previous (ref); - else - ref = element_next (ref); + if (revcond) ref = element_next (ref); + else ref = element_previous (ref); - if (ref && haselse) { - ident_line (out, block->identsize + 1); + if ((block->status & BLOCK_STAT_HASELSE) && ref) { + ident_line (out, identsize + 1); fprintf (out, "else\n"); } + first = FALSE; } - - if (block->st) { - if (block->st->end && block->st->info.ifctrl.isoutermost) { - if (block->st->hasendgoto) { - ident_line (out, block->identsize + 1); - fprintf (out, "goto label%d;\n", block->st->end->node.dfsnum); - } else { - print_block_recursive (out, block->st->end, verbosity); - } + if (block->ifst) { + if (block->ifst->hasendgoto) { + ident_line (out, identsize + 1); + fprintf (out, "goto label%d;\n", block->ifst->end->node.dfsnum); + } else if (block->ifst->info.ifctrl.endfollow) { + print_block_recursive (out, block->ifst->end); } } - if (block->loopst) { - if (block->loopst->start == block) { - ident_line (out, block->identsize); - fprintf (out, "}\n"); - if (block->loopst->end) { - if (block->loopst->hasendgoto) { - ident_line (out, block->identsize); - fprintf (out, "goto label%d;\n", block->loopst->end->node.dfsnum); - } else { - print_block_recursive (out, block->loopst->end, verbosity); - } - } + if (block->status & BLOCK_STAT_ISSWITCH) { + ident_line (out, identsize + 1); + fprintf (out, "}\n"); + } + + if (block->st->start == block && block->st->type == CONTROL_LOOP) { + ident_line (out, identsize); + fprintf (out, "}\n"); + if (block->st->hasendgoto) { + ident_line (out, identsize); + fprintf (out, "goto label%d;\n", block->st->end->node.dfsnum); + } else { + print_block_recursive (out, block->st->end); } } + } static -void print_subroutine (FILE *out, struct subroutine *sub, int verbosity) +void print_subroutine (FILE *out, struct subroutine *sub) { if (sub->import) { return; } fprintf (out, "/**\n * Subroutine at address 0x%08X\n", sub->begin->address); - if (verbosity > 1 && !sub->haserror) { - struct location *loc = sub->begin; - for (loc = sub->begin; ; loc++) { - fprintf (out, " * %s\n", allegrex_disassemble (loc->opc, loc->address, TRUE)); - if (loc == sub->end) break; - } - } fprintf (out, " */\n"); print_subroutine_declaration (out, sub); fprintf (out, "\n{\n"); @@ -181,7 +176,7 @@ void print_subroutine (FILE *out, struct subroutine *sub, int verbosity) while (el) { struct basicblock *block = element_getvalue (el); if (!block->mark1) - print_block_recursive (out, block, verbosity); + print_block_recursive (out, block); el = element_next (el); } } @@ -189,7 +184,7 @@ void print_subroutine (FILE *out, struct subroutine *sub, int verbosity) } static -void print_source (FILE *out, struct code *c, char *headerfilename, int verbosity) +void print_source (FILE *out, struct code *c, char *headerfilename) { uint32 i, j; element el; @@ -217,7 +212,7 @@ void print_source (FILE *out, struct code *c, char *headerfilename, int verbosit struct subroutine *sub; sub = element_getvalue (el); - print_subroutine (out, sub, verbosity); + print_subroutine (out, sub); el = element_next (el); } @@ -261,7 +256,7 @@ void print_header (FILE *out, struct code *c, char *headerfilename) } -int print_code (struct code *c, char *prxname, int verbosity) +int print_code (struct code *c, char *prxname) { char buffer[64]; char basename[32]; @@ -286,7 +281,7 @@ int print_code (struct code *c, char *prxname, int verbosity) print_header (hout, c, buffer); - print_source (cout, c, buffer, verbosity); + print_source (cout, c, buffer); fclose (cout); fclose (hout); diff --git a/outgraph.c b/outgraph.c index 9a62193..b77fdfb 100644 --- a/outgraph.c +++ b/outgraph.c @@ -7,18 +7,28 @@ static void print_structures (FILE *out, struct basicblock *block) { - if (block->loopst) { - fprintf (out, "LOOP start %d", block->loopst->start->node.dfsnum); - if (block->loopst->end) - fprintf (out, " end %d", block->loopst->end->node.dfsnum); - fprintf (out, "\\l"); - } - - if (block->st) { - fprintf (out, "IF"); - if (block->st->end) - fprintf (out, " end %d", block->st->end->node.dfsnum); - fprintf (out, "\\l"); + struct ctrlstruct *st = block->st; + int count = 0; + + while (st) { + switch (st->type) { + case CONTROL_IF: + fprintf (out, "IF start %d end %d %s\\l", st->start->node.dfsnum, + st->end->node.dfsnum, block->blockcond ? "TRUE" : "FALSE"); + break; + case CONTROL_MAIN: + fprintf (out, "MAIN\\l"); + break; + case CONTROL_LOOP: + fprintf (out, "LOOP start %d\\l", st->start->node.dfsnum); + break; + case CONTROL_SWITCH: + fprintf (out, "SWITCH start %d end %d %d\\l", st->start->node.dfsnum, + st->end->node.dfsnum, block->blockcond); + break; + } + st = st->parent; + if (++count > 100) break; } } @@ -147,7 +157,7 @@ void print_subroutine_graph (FILE *out, struct code *c, struct subroutine *sub, case BLOCK_SIMPLE: fprintf (out, "0x%08X-0x%08X", block->info.simple.begin->address, block->info.simple.end->address); } - if (block->haslabel) fprintf (out, "(*)"); + if (block->status & BLOCK_STAT_HASLABEL) fprintf (out, "(*)"); fprintf (out, "\\l"); if (options & OUT_PRINT_PHIS) @@ -194,8 +204,11 @@ void print_subroutine_graph (FILE *out, struct code *c, struct subroutine *sub, case EDGE_UNKNOWN: fprintf (out, "UNK"); break; case EDGE_CONTINUE: fprintf (out, "CONTINUE"); break; case EDGE_BREAK: fprintf (out, "BREAK"); break; - case EDGE_FOLLOW: fprintf (out, "FOLLOW"); break; + case EDGE_NEXT: fprintf (out, "NEXT"); break; + case EDGE_INVALID: fprintf (out, "INVALID"); break; case EDGE_GOTO: fprintf (out, "GOTO"); break; + case EDGE_CASE: fprintf (out, "CASE"); break; + case EDGE_IFENTER: fprintf (out, "IFENTER"); break; case EDGE_IFEXIT: fprintf (out, "IFEXIT"); break; } fprintf (out, "\"]"); diff --git a/output.c b/output.c index ce30b7c..da623a7 100644 --- a/output.c +++ b/output.c @@ -64,38 +64,96 @@ void print_subroutine_declaration (FILE *out, struct subroutine *sub) fprintf (out, ")"); } +#define ISSPACE(x) ((x) == '\t' || (x) == '\r' || (x) == '\n' || (x) == '\v' || (x) == '\f') + +static +int valid_string (struct prx *file, uint32 vaddr) +{ + uint32 off = prx_translate (file, vaddr); + int len = 0; + if (off) { + for (; off < file->size; off++) { + uint8 ch = file->data[off]; + if (ch == '\t' || ch == '\r' || ch == '\n' || ch == '\v' || + ch == '\f' || (ch >= 32 && ch < 127)) + len++; + else + break; + } + } + return len > 3; +} + +static +void print_string (FILE *out, struct prx *file, uint32 vaddr) +{ + uint32 off = prx_translate (file, vaddr); + + fprintf (out, "\""); + for (; off < file->size; off++) { + uint8 ch = file->data[off]; + if (ch >= 32 && ch < 127) { + fprintf (out, "%c", ch); + } else { + switch (ch) { + case '\t': fprintf (out, "\\t"); break; + case '\r': fprintf (out, "\\r"); break; + case '\n': fprintf (out, "\\n"); break; + case '\v': fprintf (out, "\\v"); break; + case '\f': fprintf (out, "\\f"); break; + default: + fprintf (out, "\""); + return; + } + } + } +} + + void print_value (FILE *out, struct value *val) { + struct ssavar *var; + struct prx *file; + int isstring = FALSE; + switch (val->type) { case VAL_CONSTANT: fprintf (out, "0x%08X", val->val.intval); break; case VAL_SSAVAR: - switch (val->val.variable->type) { + var = val->val.variable; + switch (var->type) { case SSAVAR_ARGUMENT: - if (val->val.variable->name.val.intval >= REGISTER_GPR_A0 && - val->val.variable->name.val.intval <= REGISTER_GPR_T3) { - fprintf (out, "arg%d", val->val.variable->name.val.intval - REGISTER_GPR_A0 + 1); + if (var->name.val.intval >= REGISTER_GPR_A0 && + var->name.val.intval <= REGISTER_GPR_T3) { + fprintf (out, "arg%d", var->name.val.intval - REGISTER_GPR_A0 + 1); } else { - print_value (out, &val->val.variable->name); + print_value (out, &var->name); } break; case SSAVAR_LOCAL: - fprintf (out, "local%d", val->val.variable->info); + fprintf (out, "var%d", var->info); break; case SSAVAR_CONSTANT: - fprintf (out, "0x%08X", val->val.variable->info); + file = var->def->block->sub->code->file; + if (var->def->status & OP_STAT_HASRELOC) { + isstring = valid_string (file, var->info); + } + if (isstring) + print_string (out, file, var->info); + else + fprintf (out, "0x%08X", var->info); break; case SSAVAR_TEMP: - if (val->val.variable->def->type != OP_MOVE) + if (var->def->type != OP_MOVE) fprintf (out, "("); - print_operation (out, val->val.variable->def, 0, TRUE); - if (val->val.variable->def->type != OP_MOVE) + print_operation (out, var->def, 0, TRUE); + if (var->def->type != OP_MOVE) fprintf (out, ")"); break; default: - print_value (out, &val->val.variable->name); + print_value (out, &var->name); fprintf (out, "/* Invalid block %d %d */", - val->val.variable->def->block->node.dfsnum, - val->val.variable->def->type); + var->def->block->node.dfsnum, + var->def->type); break; } break; diff --git a/output.h b/output.h index 0fd2df7..8b31c65 100644 --- a/output.h +++ b/output.h @@ -28,7 +28,7 @@ void print_complexop (FILE *out, struct operation *op, const char *opsymbol, int void print_subroutine_name (FILE *out, struct subroutine *sub); void print_subroutine_declaration (FILE *out, struct subroutine *sub); -int print_code (struct code *c, char *filename, int verbosity); +int print_code (struct code *c, char *filename); int print_graph (struct code *c, char *prxname, int options); #endif /* __OUTPUT_H */ diff --git a/relocs.c b/relocs.c index b2892c3..8cff25d 100644 --- a/relocs.c +++ b/relocs.c @@ -559,7 +559,7 @@ uint32 prx_findreloc (struct prx *p, uint32 target) uint32 first, last, i; first = 0; - last = p->relocnum - 1; + last = p->relocnum; while (first < last) { i = (first + last) / 2; if (p->relocs[i].target < target) { @@ -577,7 +577,7 @@ uint32 prx_findrelocbyaddr (struct prx *p, uint32 vaddr) uint32 first, last, i; first = 0; - last = p->relocnum - 1; + last = p->relocnum; while (first < last) { i = (first + last) / 2; if (p->relocsbyaddr[i].vaddr < vaddr) { diff --git a/structures.c b/structures.c dissimilarity index 62% index af8f51f..8e63352 100644 --- a/structures.c +++ b/structures.c @@ -1,326 +1,368 @@ - -#include "code.h" -#include "utils.h" - - -static -void mark_backward (struct subroutine *sub, struct basicblock *start, - struct basicblock *block, int num, int *count) -{ - element el, ref; - int remaining = 1; - - block->mark1 = num; - el = block->node.blockel; - while (el && remaining) { - struct basicblock *block = element_getvalue (el); - if (block == start) break; - if (block->mark1 == num) { - remaining--; - ref = list_head (block->inrefs); - while (ref) { - struct basicedge *edge = element_getvalue (ref); - struct basicblock *next = edge->from; - ref = element_next (ref); - - if (next->node.dfsnum >= block->node.dfsnum) - if (!dom_isancestor (&block->node, &next->node) || - !dom_isancestor (&block->revnode, &next->revnode)) - continue; - if (next->mark1 != num) { - remaining++; - (*count)++; - } - next->mark1 = num; - } - } - - el = element_previous (el); - } -} - -static -void mark_forward (struct subroutine *sub, struct basicblock *start, - struct ctrlstruct *loop, int num, int count) -{ - element el, ref; - - el = start->node.blockel; - while (el && count) { - struct basicblock *block = element_getvalue (el); - if (block->mark1 == num) { - block->loopst = loop; count--; - ref = list_head (block->outrefs); - while (ref) { - struct basicedge *edge = element_getvalue (ref); - struct basicblock *next = edge->to; - if (next->mark1 != num) { - edge->type = EDGE_GOTO; - next->haslabel = TRUE; - if (!loop->end) loop->end = next; - if (list_size (loop->end->inrefs) < list_size (next->inrefs)) - loop->end = next; - } - ref = element_next (ref); - } - } - - el = element_next (el); - } -} - - -static -void mark_loop (struct subroutine *sub, struct ctrlstruct *loop) -{ - element el; - int num = ++sub->temp; - int count = 0; - - el = list_head (loop->info.loopctrl.edges); - while (el) { - struct basicedge *edge = element_getvalue (el); - struct basicblock *block = edge->from; - - if (block->mark1 != num) { - mark_backward (sub, loop->start, block, num, &count); - } - el = element_next (el); - } - - mark_forward (sub, loop->start, loop, num, count); - - if (loop->end) { - loop->end->haslabel = FALSE; - el = list_head (loop->end->inrefs); - while (el) { - struct basicedge *edge = element_getvalue (el); - struct basicblock *block = edge->from; - if (block->loopst == loop) edge->type = EDGE_BREAK; - el = element_next (el); - } - } -} - -static -void extract_loops (struct subroutine *sub) -{ - struct basicblock *block; - struct basicedge *edge; - struct ctrlstruct *loop; - element el, ref; - - el = list_head (sub->dfsblocks); - while (el) { - block = element_getvalue (el); - - loop = NULL; - ref = list_head (block->inrefs); - while (ref) { - edge = element_getvalue (ref); - if (edge->from->node.dfsnum >= block->node.dfsnum) { - edge->type = EDGE_CONTINUE; - if (!dom_isancestor (&block->node, &edge->from->node)) { - error (__FILE__ ": graph of sub 0x%08X is not reducible (using goto)", sub->begin->address); - edge->type = EDGE_GOTO; - edge->to->haslabel = TRUE; - } else if (block->loopst == edge->from->loopst) { - if (!loop) { - loop = fixedpool_alloc (sub->code->ctrlspool); - loop->start = block; - loop->type = CONTROL_LOOP; - loop->info.loopctrl.edges = list_alloc (sub->code->lstpool); - } - list_inserttail (loop->info.loopctrl.edges, edge); - } else { - edge->type = EDGE_GOTO; - edge->to->haslabel = TRUE; - } - } - ref = element_next (ref); - } - if (loop) mark_loop (sub, loop); - el = element_next (el); - } -} - -static -void extract_branches (struct subroutine *sub) -{ - struct basicblock *block; - struct ctrlstruct *st; - list unresolvedifs; - element el; - - unresolvedifs = list_alloc (sub->code->lstpool); - - el = list_tail (sub->dfsblocks); - while (el) { - int hasswitch = FALSE; - block = element_getvalue (el); - - if (block->type == BLOCK_SIMPLE) - if (block->info.simple.jumploc) - if (block->info.simple.jumploc->cswitch) - hasswitch = TRUE; - - if (hasswitch) { - st = fixedpool_alloc (sub->code->ctrlspool); - st->type = CONTROL_SWITCH; - block->st = st; - - } else if (list_size (block->outrefs) == 2) { - struct basicedge *edge1, *edge2; - - st = fixedpool_alloc (sub->code->ctrlspool); - st->type = CONTROL_IF; - block->st = st; - - edge1 = list_headvalue (block->outrefs); - edge2 = list_tailvalue (block->outrefs); - if (edge1->type == EDGE_UNKNOWN && edge2->type == EDGE_UNKNOWN) { - element domel; - - list_inserthead (unresolvedifs, block); - domel = list_head (block->node.domchildren); - while (domel) { - struct basicblocknode *dom = element_getvalue (domel); - struct basicblock *domblock = element_getvalue (dom->blockel); - - if (list_size (domblock->inrefs) > 1) { - block->st->info.ifctrl.isoutermost = TRUE; - while (list_size (unresolvedifs) != 0) { - struct basicblock *ifblock = list_removehead (unresolvedifs); - ifblock->st->end = domblock; - } - break; - } - domel = element_next (domel); - } - } else if (edge1->type == EDGE_UNKNOWN || edge2->type == EDGE_UNKNOWN) { - if (edge1->type == EDGE_UNKNOWN) { - edge1->type = EDGE_IFEXIT; - st->end = edge1->to; - } else { - edge2->type = EDGE_IFEXIT; - st->end = edge2->to; - } - - } - } - - el = element_previous (el); - } - - list_free (unresolvedifs); -} - -static -void structure_search (struct basicblock *block, int identsize, struct ctrlstruct *ifst) -{ - struct basicedge *edge; - struct basicblock *ifend = NULL; - element ref; - - if (ifst) - ifend = ifst->end; - - if (block->st) - if (block->st->end) - ifend = block->st->end; - - block->mark1 = 1; - - if (block->loopst) { - if (block->loopst->start == block) { - identsize++; - if (block->loopst->end) { - if (!block->loopst->end->mark1) - structure_search (block->loopst->end, identsize - 1, ifst); - else { - block->loopst->end->haslabel = TRUE; - block->loopst->hasendgoto = TRUE; - } - } - } - } - - if (block->st) { - if (block->st->end && block->st->info.ifctrl.isoutermost) { - if (!block->st->end->mark1) - structure_search (block->st->end, identsize, ifst); - else { - block->st->end->haslabel = TRUE; - block->st->hasendgoto = TRUE; - } - } - } - - block->identsize = identsize; - - ref = list_head (block->outrefs); - while (ref) { - edge = element_getvalue (ref); - if (edge->type == EDGE_UNKNOWN) { - if (edge->to->loopst != block->loopst) { - if (edge->to->loopst) { - if (edge->to->loopst->start != edge->to) { - edge->type = EDGE_GOTO; - edge->to->haslabel = TRUE; - } - } else { - edge->type = EDGE_GOTO; - edge->to->haslabel = TRUE; - } - } - } - - if (edge->type == EDGE_UNKNOWN) { - if (edge->to == ifend) { - edge->type = EDGE_IFEXIT; - } else { - if (edge->to->mark1) { - edge->type = EDGE_GOTO; - edge->to->haslabel = TRUE; - } else { - edge->type = EDGE_FOLLOW; - if (block->st) { - structure_search (edge->to, identsize + 1, block->st); - } else { - structure_search (edge->to, identsize, ifst); - } - } - } - } - ref = element_next (ref); - } -} - -void reset_marks (struct subroutine *sub) -{ - element el = list_head (sub->blocks); - while (el) { - struct basicblock *block = element_getvalue (el); - block->mark1 = block->mark2 = 0; - el = element_next (el); - } -} - -void extract_structures (struct subroutine *sub) -{ - element el; - sub->temp = 0; - reset_marks (sub); - - extract_loops (sub); - extract_branches (sub); - - reset_marks (sub); - el = list_head (sub->blocks); - while (el) { - struct basicblock *block = element_getvalue (el); - if (!block->mark1) - structure_search (block, 0, NULL); - el = element_next (el); - } -} + +#include "code.h" +#include "utils.h" + +static +struct ctrlstruct *alloc_ctrlstruct (struct basicblock *block, enum ctrltype type) +{ + struct ctrlstruct *st = fixedpool_alloc (block->sub->code->ctrlspool); + st->start = block; + st->type = type; + return st; +} + +static +int mark_backward (struct basicblock *start, list worklist, int num) +{ + struct basicblock *block; + element ref; + int count = 0; + + while (list_size (worklist) != 0) { + block = list_removetail (worklist); + if (block->mark1 == num) continue; + block->mark1 = num; + count++; + + ref = list_head (block->inrefs); + while (ref) { + struct basicedge *edge = element_getvalue (ref); + struct basicblock *next = edge->from; + ref = element_next (ref); + + if (next->node.dfsnum < start->node.dfsnum) + continue; + + if (next->node.dfsnum >= block->node.dfsnum) + if (!dom_isancestor (&block->node, &next->node) || + !dom_isancestor (&block->revnode, &next->revnode)) + continue; + + if (next->mark1 != num) { + list_inserthead (worklist, next); + } + } + } + + return count; +} + +static +void mark_forward (struct basicblock *start, struct ctrlstruct *loop, int num, int count) +{ + element el, ref; + + el = start->node.blockel; + while (el && count) { + struct basicblock *block = element_getvalue (el); + if (block->mark1 == num) { + block->loopst = loop; count--; + ref = list_head (block->outrefs); + while (ref) { + struct basicedge *edge = element_getvalue (ref); + struct basicblock *next = edge->to; + if (next->mark1 != num) { + /* edge->type = EDGE_GOTO; + next->status |= BLOCK_STAT_HASLABEL; */ + if (!loop->end) loop->end = next; + if (list_size (loop->end->inrefs) < list_size (next->inrefs)) + loop->end = next; + } + ref = element_next (ref); + } + } + + el = element_next (el); + } +} + +static +void mark_loop (struct ctrlstruct *loop, int num) +{ + element el; + list worklist; + int count; + + worklist = list_alloc (loop->start->sub->code->lstpool); + el = list_head (loop->info.loopctrl.edges); + while (el) { + struct basicedge *edge = element_getvalue (el); + struct basicblock *block = edge->from; + + list_inserttail (worklist, block); + el = element_next (el); + } + count = mark_backward (loop->start, worklist, num); + + mark_forward (loop->start, loop, num, count); + if (loop->end) { + /* loop->end->status &= ~BLOCK_STAT_HASLABEL; */ + el = list_head (loop->end->inrefs); + while (el) { + struct basicedge *edge = element_getvalue (el); + if (edge->from->loopst == loop) + edge->type = EDGE_BREAK; + el = element_next (el); + } + } + + list_free (worklist); +} + +static +void extract_loops (struct subroutine *sub) +{ + struct basicblock *block; + struct basicedge *edge; + struct ctrlstruct *loop; + element el, ref; + int num = 0; + + el = list_head (sub->dfsblocks); + while (el) { + block = element_getvalue (el); + + loop = NULL; + ref = list_head (block->inrefs); + while (ref) { + edge = element_getvalue (ref); + if (edge->from->node.dfsnum >= block->node.dfsnum) { + edge->type = EDGE_CONTINUE; + if (!dom_isancestor (&block->node, &edge->from->node)) { + error (__FILE__ ": graph of sub 0x%08X is not reducible (using goto)", sub->begin->address); + edge->type = EDGE_INVALID; + edge->to->status |= BLOCK_STAT_HASLABEL; + } else if (block->loopst == edge->from->loopst) { + if (!loop) { + loop = alloc_ctrlstruct (block, CONTROL_LOOP); + loop->info.loopctrl.edges = list_alloc (sub->code->lstpool); + } + list_inserttail (loop->info.loopctrl.edges, edge); + }/* else { + edge->type = EDGE_GOTO; + edge->to->status |= BLOCK_STAT_HASLABEL; + }*/ + } + ref = element_next (ref); + } + if (loop) + mark_loop (loop, ++num); + el = element_next (el); + } +} + +static +void extract_returns (struct subroutine *sub) +{ + +} + +static +int struct_isancestor (struct ctrlstruct *ancestor, struct ctrlstruct *st) +{ + while (st) { + if (st == ancestor) return TRUE; + st = st->parent; + } + return FALSE; +} + +static +void structure_search (struct basicblock *block, struct ctrlstruct *parentst, int blockcond) +{ + block->st = parentst; + block->mark1 = 1; + block->blockcond = blockcond; + + if (block->loopst) { + if (block->loopst->start == block) { + block->st = block->loopst; + block->st->parent = parentst; + block->st->identsize = parentst->identsize + 1; + } + } + + if (block->status & BLOCK_STAT_ISSWITCH) { + struct ctrlstruct *nst; + element ref; + + nst = alloc_ctrlstruct (block, CONTROL_SWITCH); + nst->end = element_getvalue (block->revnode.dominator->blockel); + nst->parent = block->st; + nst->identsize = block->st->identsize + 1; + block->ifst = nst; + + ref = list_head (block->outrefs); + while (ref) { + struct basicedge *edge = element_getvalue (ref); + + if (edge->type == EDGE_UNKNOWN) { + edge->type = EDGE_CASE; + if (!edge->to->mark1) { + structure_search (edge->to, nst, edge->fromnum); + } else { + if (edge->to->st != nst) { + edge->type = EDGE_GOTO; + edge->to->status |= BLOCK_STAT_HASLABEL; + } + } + } + ref = element_next (ref); + } + } else if (list_size (block->outrefs) == 2) { + struct basicblock *end; + struct basicedge *edge1, *edge2; + + end = element_getvalue (block->revnode.dominator->blockel); + edge1 = list_tailvalue (block->outrefs); + edge2 = list_headvalue (block->outrefs); + + if (edge1->to != end) { + if (edge1->to->mark1) { + edge1->type = EDGE_GOTO; + edge1->to->status |= BLOCK_STAT_HASLABEL; + } + } + + if (edge2->to != end) { + if (edge2->to->mark1) { + edge2->type = EDGE_GOTO; + edge2->to->status |= BLOCK_STAT_HASLABEL; + } + } + + if (edge1->type == EDGE_UNKNOWN && edge2->type == EDGE_UNKNOWN) { + struct ctrlstruct *nst = alloc_ctrlstruct (block, CONTROL_IF); + nst->end = end; + nst->parent = block->st; + nst->identsize = block->st->identsize + 1; + block->ifst = nst; + + if (!end->mark1) { + nst->info.ifctrl.endfollow = TRUE; + end->mark1 = TRUE; + } else { + if (!struct_isancestor (end->st, block->st)) { + nst->hasendgoto = TRUE; + end->status |= BLOCK_STAT_HASLABEL; + } + } + + if (edge1->to == end) { + edge1->type = EDGE_IFEXIT; + } else { + edge1->type = EDGE_IFENTER; + structure_search (edge1->to, nst, TRUE); + } + + if (edge2->to == end) { + edge2->type = EDGE_IFEXIT; + } else { + if (edge2->to->mark1) { + edge2->type = EDGE_GOTO; + edge2->to->status |= BLOCK_STAT_HASLABEL; + } else { + edge2->type = EDGE_IFENTER; + structure_search (edge2->to, nst, FALSE); + } + } + + if (edge2->type != EDGE_IFEXIT) { + if (edge1->type == EDGE_IFEXIT) + block->status |= BLOCK_STAT_REVCOND; + else + block->status |= BLOCK_STAT_HASELSE; + } + + if (nst->info.ifctrl.endfollow) { + end->mark1 = 0; + structure_search (end, block->st, blockcond); + } + + } else if (edge1->type == EDGE_UNKNOWN || edge2->type == EDGE_UNKNOWN) { + struct basicedge *edge; + + if (edge1->type == EDGE_UNKNOWN) { + block->status |= BLOCK_STAT_REVCOND; + edge = edge1; + } else { + edge = edge2; + } + + if (edge->to == block->st->end && block->st->type == CONTROL_IF) { + edge->type = EDGE_IFEXIT; + } else { + if (edge->to->mark1) { + edge->type = EDGE_GOTO; + edge->to->status |= BLOCK_STAT_HASLABEL; + } else { + edge->type = EDGE_NEXT; + structure_search (edge->to, block->st, blockcond); + } + } + } + } else { + struct basicedge *edge; + edge = list_headvalue (block->outrefs); + if (edge) { + if (edge->type == EDGE_UNKNOWN) { + if (edge->to == block->st->end && block->st->type == CONTROL_IF) { + edge->type = EDGE_IFEXIT; + } else { + if (edge->to->mark1) { + edge->type = EDGE_GOTO; + edge->to->status |= BLOCK_STAT_HASLABEL; + } else { + edge->type = EDGE_NEXT; + structure_search (edge->to, block->st, blockcond); + } + } + } + } + } + + if (block->loopst) { + if (block->loopst->start == block && block->loopst->end) { + if (block->loopst->end->mark1) { + block->loopst->hasendgoto = TRUE; + block->loopst->end->status |= BLOCK_STAT_HASLABEL; + } else { + structure_search (block->loopst->end, parentst, blockcond); + } + } + } +} + +void reset_marks (struct subroutine *sub) +{ + element el = list_head (sub->blocks); + while (el) { + struct basicblock *block = element_getvalue (el); + block->mark1 = block->mark2 = 0; + el = element_next (el); + } +} + +void extract_structures (struct subroutine *sub) +{ + element el; + struct ctrlstruct *st = fixedpool_alloc (sub->code->ctrlspool); + + st->type = CONTROL_MAIN; + st->start = sub->startblock; + st->end = sub->endblock; + + reset_marks (sub); + extract_loops (sub); + + extract_returns (sub); + + reset_marks (sub); + el = list_head (sub->blocks); + while (el) { + struct basicblock *block = element_getvalue (el); + if (!block->mark1) + structure_search (block, st, 0); + el = element_next (el); + } +} diff --git a/subroutines.c b/subroutines.c index cba26c1..ed5cd2b 100644 --- a/subroutines.c +++ b/subroutines.c @@ -380,17 +380,17 @@ void extract_subroutines (struct code *c) check_subroutine (sub); if (!sub->haserror) { - sub->status |= SUBROUTINE_EXTRACTED; + sub->status |= SUB_STAT_EXTRACTED; extract_cfg (sub); } if (!sub->haserror) { - sub->status |= SUBROUTINE_CFG_EXTRACTED; + sub->status |= SUB_STAT_CFG_EXTRACTED; extract_operations (sub); } if (!sub->haserror) { - sub->status |= SUBROUTINE_OPERATIONS_EXTRACTED; + sub->status |= SUB_STAT_OPERATIONS_EXTRACTED; } } el = element_next (el); -- 2.11.4.GIT