| /* decomp.cpp */ |
| /* |
| Java Decompiler |
| Copyright (c) 1994-2003, Pete Ryland. |
| Distributed under the GNU GPL Version 2. |
| This package is available from http://pdr.cx/hbd/ |
| */ |
| |
| #include <stdio.h> |
| #include <string.h> |
| #include <stdlib.h> |
| #include "general.h" |
| #include "options.h" |
| #include "version.h" |
| #include "cp.h" |
| #include "access.h" |
| #include "field.h" |
| #include "exp.h" |
| #include "method.h" |
| #include "consts.h" |
| #include "class.h" |
| #include "file.h" |
| #include "sig.h" |
| #include "decomp.h" |
| |
| void printintlist(intlist *t) { |
| fprintf(stderr, "["); |
| intnode *n = t->head; |
| while (n) { |
| fprintf(stderr, "%d", n->node); |
| n = n->next; |
| if (!n) |
| break; |
| fprintf(stderr, ", "); |
| } |
| fprintf(stderr, "]\n"); |
| } |
| |
| int ch; |
| unsigned char *inbuff; |
| int bufflength; |
| unsigned currpc; |
| int lastaction; |
| method_info *miptr; |
| |
| Exp *stack[8]; |
| Exp **stkptr; |
| Exp *donestack[256]; |
| Exp **donestkptr; |
| |
| //Block *blocks[16]; |
| //int numblocks; |
| //int currblock; |
| |
| int indentlevel; |
| |
| /* |
| char pass1size[] = { |
| 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
| 2, 3, 2, 3, 3, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, |
| 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, |
| 0, 0, 1, 0, 0, 0, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, |
| 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, |
| 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
| 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
| 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
| |
| 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
| */// 1,1,1,1,/*C*/1,1,1,1,1,/*.*/-1,-1,-1,-1,-1,-1,-1, // cmps |
| // -1,-1,-1,-1,-1,-1,-1,-2,-3,-4,-5,-6,/*R*/1,1,1,1, // returns |
| // 1,1/*.*/,3,3,3,3, 3, 3, 5, 3, 3, 3, 0, 3, 1, 1, |
| /* 3, 0, 0, 0, 0, 3,-1,-1, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| }; |
| |
| int addifblock(void) |
| { |
| unsigned pcval = currpc - 1; |
| Block *b = blocks[currblock++] = new Block; |
| b->tag = IF; |
| b->start_pc = pcval + 3; |
| b->end_pc = pcval + (signed)(((unsigned)JDNEXT8() << 8) + (unsigned)JDNEXT8()); |
| b->else_pc = 0; |
| b->exp = 0; |
| fprintf(stderr, "if(?) goto %d else %d\n", b->end_pc, b->start_pc); |
| return 0; |
| } |
| |
| int addgotoblock(void) |
| { |
| unsigned pcval = currpc - 1; |
| Block *b = blocks[currblock++] = new Block; |
| b->tag = GOTOLABEL; |
| b->start_pc = pcval + 3; |
| b->end_pc = pcval + (signed)(((unsigned)JDNEXT8() << 8) + (unsigned)JDNEXT8()); |
| b->else_pc = 0; |
| b->exp = 0; |
| fprintf(stderr, "goto %d instead of %d\n", b->end_pc, b->start_pc); |
| return 0; |
| } |
| |
| int (*pass1actions[])(void) = { |
| 0, addifblock, addgotoblock, 0, 0, 0, 0, 0, |
| 0, 0, 0 |
| }; |
| */ |
| char actions[] = { |
| 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
| 2, 2, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, |
| 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,15, 0, |
| 0, 0,15, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, |
| 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, |
| 0, 0, 0,18, 0, 0, 0,21, 0,13,25, 0, 0, 0, 0, 0, |
| 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, |
| 6, 6, 6, 6, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, |
| |
| 6, 6, 6, 6,16, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, |
| 7, 7, 7, 0,22,22,22,22, 22,12,12,12,12,12,12,23, |
| 23,23,23,23,23,23,23, 7, 0, 0,27,24,10,10,10,10, |
| 10,10, 8, 9, 8, 9,11,11, 11,11, 7, 7, 0,19,14, 7, |
| 17,26, 0, 0, 0,20/*?(multianewarray)*/,12,12, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| }; |
| |
| int (*actiontable[])(Classfile *c) = { |
| 0, pushimp, pushimm, pushconst, pushlocal, storelocal, pushbinop, pushunop, |
| doget, doput, doreturn, invokefunc, doif1, dodup, doarraylength, doarrayget, |
| iinclocal, docheckcast, doarrayput, anewarray, multianewarray, dopop, docmp, doif2, |
| doluswitch, dodup_x1, doinstanceof, dotableswitch |
| }; |
| |
| int decompileblock(Classfile *c, method_info_ptr mi) { |
| char *str; |
| // int i; |
| miptr = mi; |
| cond_pcend = -1; |
| char *strptr; |
| int dodecompile = ((int)(c->options)) ^ 2; |
| |
| if (mi->name == "<init>") { |
| } |
| |
| strptr = new char[mi->access_flags.strlen() + 1]; |
| fprintf(c->outfile, "\n %s", mi->access_flags.toString(strptr)); |
| delete strptr; |
| char *tmp = mi->sig; |
| if (printsigname(c, c->outfile, tmp, mi->name, mi)) return 1; |
| for (int m = 0; m != mi->num_throws;) { |
| fprintf(c->outfile, " throws %s", c->cp(mi->throws[m++])->chp); |
| } |
| if ((mi->access_flags & (ACC_NATIVE | ACC_ABSTRACT))) dodecompile = 0; |
| if (dodecompile) { |
| |
| /**********************************************************************/ |
| /** PASS1 - input stage, analyse opcodes, create stack of statements **/ |
| /**********************************************************************/ |
| int action = 0; |
| inbuff = mi->code; |
| bufflength = mi->code_length; |
| currpc = 0; |
| stkptr = stack; |
| donestkptr = donestack; |
| |
| indentlevel = 0; |
| // indents_end = indents_begin = (intlist *)0; |
| |
| while (bufflength > 0) { |
| if (((int)currpc == cond_pcend)) if (finishconditional(c)) return 1; |
| ch = JDNEXT8U(); |
| lastaction = action; |
| action = actions[ch]; |
| if (action) { |
| if(actiontable[action](c)) return 1; |
| } else { |
| fprintf(c->outfile, "// unknown opcode 0x%02X\n", ch); |
| } |
| } |
| |
| fprintf(c->outfile, " {\n"); |
| |
| /**********************************************************************/ |
| /** PASS2 - lazy conditionals (&& and ||), note backward jump refs **/ |
| /**********************************************************************/ |
| looplist *branchbacklist = new looplist(); |
| Exp **p = donestack; |
| for (;p < (donestkptr-1);p++) { |
| Exp *pptr = *p, *pptr1 = *(p+1), *pptr2 = *(p+2); |
| if (pptr->e->op == GOTO) |
| goto here; |
| if (pptr->e->et == BRANCH) { |
| if (pptr1->e->et == BRANCH || pptr1->e->op == COND) { |
| unsigned minpc = min(pptr->minpc, pptr1->minpc); |
| Exp *e; |
| if (pptr->branch_pc == pptr1->branch_pc) { |
| e = new Exp(minpc, BINARY, BOOLEAN, OR_BOOL, |
| pptr->exp1, pptr1->exp1); |
| } else { |
| if (pptr->branch_pc == pptr2->minpc) { |
| e = new Exp(minpc, BINARY, BOOLEAN, AND_BOOL, |
| pptr->exp1, pptr1->exp1); |
| if (notexp(&(e->exp1))) return 1; |
| } else { |
| goto here; |
| } |
| } |
| killexp(pptr); |
| pptr1->exp1 = e; |
| pptr1->minpc = minpc; |
| *p = pptr1; *(++p) = 0; |
| pptr = pptr1; pptr1 = pptr2; |
| } |
| here: |
| if (pptr->minpc >= pptr->branch_pc) { |
| branchbacklist->add(new Loop(pptr->minpc, pptr->branch_pc, |
| pptr1->minpc, pptr->exp1, LOOP_DOWHILE)); |
| } |
| } |
| } |
| |
| /**********************************************************************/ |
| /** PASS3 - analyse control flow, recursively print statement stack **/ |
| /**********************************************************************/ |
| intlist *iflist = new intlist(); |
| intlist *elselist = new intlist(); |
| looplist *branchbacklist2 = new looplist(); |
| |
| p = donestack; |
| while (p != donestkptr) { |
| Exp *pptr = *p++; |
| if (pptr) { |
| if (!branchbacklist->isempty()) { |
| Loop *l = branchbacklist->top(); |
| if (l->jumpto_pc == pptr->minpc) { |
| l->type = LOOP_DOWHILE; |
| fprintf(c->outfile, " do {\n", str); |
| indentlevel++; |
| for (int i=indentlevel; i--;) fprintf(c->outfile, " "); |
| branchbacklist2->push(branchbacklist->pop()); |
| } |
| } |
| if (!branchbacklist->isempty()) { |
| Loop *l = branchbacklist->top(); |
| if (pptr->e->op == GOTO && pptr->branch_pc == l->jumpfrom_pc) { |
| l->type = LOOP_WHILE; |
| str = l->condition->toString(0); |
| fprintf(c->outfile, " while (%s) {\n", str); |
| delete str; |
| indentlevel++; |
| for (int i=indentlevel; i--;) fprintf(c->outfile, " "); |
| branchbacklist2->push(branchbacklist->pop()); |
| continue; |
| } |
| } |
| if (!iflist->isempty() && iflist->top() == pptr->minpc) { |
| iflist->pop(); |
| fprintf(c->outfile, " }\n"); |
| indentlevel--; |
| for (int i=indentlevel; i--;) fprintf(c->outfile, " "); |
| } |
| if (pptr->e->op == GOTO || pptr->e->et == BRANCH) { |
| if (!branchbacklist2->isempty()) { |
| Loop *l = branchbacklist2->top(); |
| if (l->jumpfrom_pc == pptr->minpc) { |
| if (l->type == LOOP_DOWHILE) { |
| if (pptr->e->op == GOTO) { |
| fprintf(c->outfile, " } while(true);\t/*%d*/\n", pptr->minpc); |
| } else { |
| char *str = l->condition->toString(0); |
| fprintf(c->outfile, " } while(%s);\t/*%d*/\n", str, |
| pptr->minpc); |
| delete str; |
| } |
| } else { |
| fprintf(c->outfile, " }\t/*%d*/\n", pptr->minpc); |
| } |
| branchbacklist2->pop(); |
| indentlevel--; |
| for (int i=indentlevel; i--;) fprintf(c->outfile, " "); |
| continue; |
| } |
| if (branchbacklist2->containsPast(pptr->branch_pc)) { |
| fprintf(c->outfile, " break;\t/*%d*/\n", (*(p-1))->minpc); |
| for (int i=indentlevel; i--;) fprintf(c->outfile, " "); |
| continue; |
| } |
| } |
| if (!iflist->isempty() && iflist->top() == ((*p)?(*p)->minpc:0)) { |
| elselist->push(pptr->branch_pc); |
| iflist->pop(); |
| fprintf(c->outfile, " } else {\t/*%d*/\n", (*(p-1))->minpc); |
| for (int i=indentlevel; i--;) fprintf(c->outfile, " "); |
| continue; |
| } |
| if (pptr->e->et == BRANCH && pptr->branch_pc > pptr->minpc) { |
| iflist->push(pptr->branch_pc); |
| indentlevel++; |
| } |
| } else { |
| if (pptr->e->op == RETURN && !iflist->isempty() |
| && iflist->top() == ((*p)?(*p)->minpc:0)) { |
| iflist->pop(); |
| str = pptr->toString(0); |
| if (str) { |
| fprintf(c->outfile, " %s;\t/*%d*/\n", str, (*(p-1))->minpc); |
| for (int i=indentlevel; i--;) fprintf(c->outfile, " "); |
| } |
| delete str; |
| fprintf(c->outfile, " }\n"); |
| indentlevel--; |
| for (int i=indentlevel; i--;) fprintf(c->outfile, " "); |
| continue; |
| } else { |
| if (!elselist->isempty() && elselist->top() == pptr->minpc) { |
| elselist->pop(); |
| fprintf(c->outfile, " }\n"); |
| indentlevel--; |
| for (int i=indentlevel; i--;) fprintf(c->outfile, " "); |
| } |
| } |
| } |
| str = pptr->toString(0); |
| if (str) { |
| fprintf(c->outfile, strrchr(str,'{')?" %s":" %s;", str); |
| fprintf(c->outfile, "\t/*%d*/",(*(p-1))->minpc); |
| fprintf(c->outfile, "\n"); |
| for (int i=indentlevel; i--;) fprintf(c->outfile, " "); |
| } |
| delete str; |
| } |
| } |
| fprintf(c->outfile, " }"); |
| } else { |
| fprintf(c->outfile, ";"); |
| } |
| return 0; |
| } |