blob: a6831bd13227757def243b6e902175ec2da1545c [file] [log] [blame]
/* 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;
}