module lang::flybytes::Decompiler
rascal-0.40.17
flybytes-0.2.8
Usage
import lang::flybytes::Decompiler;
Source code
http://github.com/usethesource/flybytes/blob/main/src/lang/flybytes/Decompiler.rsc
Dependencies
extend lang::flybytes::Disassembler;
import Exception;
import String;
import List;
function decompile
Decompile a JVM classfile to Flybytes ASTs, recovering statement and expression structures.
Class decompile(loc classFile, bool cleanup=true) throws IO
Method decompile(loc classFile, str methodName, bool cleanup=true)
Method decompile(Method m:procedure(Signature d, list[Formal] f, list[Instruction] instrs, modifiers=set[Modifier] ms), bool cleanup=true)
Method decompile(Method m:method(_, _, [asm(list[Instruction] instrs)]), bool cleanup=true)
Method decompile(Method m:static([asm(list[Instruction] instrs)]), bool cleanup=true)
default Method decompile(Method m, bool cleanup=true)
data Instruction
data Instruction (int LINE = -1)
data Exp
data Exp (int LINE = -1)
data Stat
data Stat (int LINE = -1)
function lines
Set the information from LINENUMBER instructions to all following instructions as a field, and removes the instruction.
list[Instruction] lines([*Instruction pre, LINENUMBER(lin, lab), Instruction next, *Instruction post])
list[Instruction] lines([*Instruction pre, LINENUMBER(_, _), Instruction next:LINENUMBER(_,_), *Instruction post])
list[Instruction] lines([*Instruction pre, LINENUMBER(_, _)])
default list[Instruction] lines(list[Instruction] l)
data Instruction
data Instruction (bool jumpTarget = false)
function jumps
Marks jump targets with the jumpTarget=true field, for later use by label removal and detection of structured statements.
list[Instruction] jumps([*Instruction pre, Instruction jump:/IF|GOTO|IFNULL|IFNONNULL|JSR/(str l1), *Instruction mid, LABEL(l1, jumpTarget=false), *Instruction post])
list[Instruction] jumps([*Instruction pre, LABEL(str l1, jumpTarget=false), *Instruction mid, Instruction jump:/IF|GOTO|IFNULL|IFNONNULL|JSR/(l1), *Instruction post])
list[Instruction] jumps([*Instruction pre, Instruction s:TABLESWITCH(_,_,str def,_), *Instruction mid, LABEL(def, jumpTarget=false), *Instruction post])
list[Instruction] jumps([*Instruction pre, Instruction s:TABLESWITCH(_,_,_,[*_, cl, *_]), *Instruction mid, LABEL(str cl, jumpTarget=false), *Instruction post])
list[Instruction] jumps([*Instruction pre, LABEL(str \start), *Instruction block, LABEL(str \end), *Instruction mid1, LABEL(str handler), *Instruction mid2, TRYCATCH(Type typ, \start, end, handler), *Instruction post])
default list[Instruction] jumps(list[Instruction] l)
function labels
Removes all labels which are not jump targets.
list[Instruction] labels([*Instruction pre, LABEL(_, jumpTarget=false), *Instruction post])
default list[Instruction] labels(list[Instruction] l)
function decls
list[Instruction] decls([*Instruction pre, LOCALVARIABLE("this", _, _, _, _), *Instruction post], list[Formal] formals)
list[Instruction] decls([*Instruction pre, LOCALVARIABLE(str name, Type typ, _, _, _), *Instruction post], [*pref, var(\typ, name), *postf])
list[Instruction] decls([*Instruction pre, LOCALVARIABLE(str name, Type typ, _, _, _), *Instruction post], [])
list[Instruction] decls([*Instruction pre, stat(decl(typ, name)), *Instruction mid, stat(store(name, e)), *Instruction post], [])
default list[Instruction] decls(list[Instruction] l, list[Formal] _)
function stmts
Recovers structured statements.
list[Instruction] stmts([*Instruction pre, exp(a), exp(b), /IF_[IA]CMP<op:EQ|NE|LT|GE|LE>/(str l1), *Instruction thenPart, LABEL(l1), *Instruction post])
list[Instruction] stmts([*Instruction pre, exp(a), IFNULL(l1), *Instruction thenPart, LABEL(l1), *Instruction post])
list[Instruction] stmts([*Instruction pre, exp(a), IFNONNULL(l1), *Instruction thenPart, LABEL(l1), *Instruction post])
list[Instruction] stmts([*Instruction pre, exp(a), /IF<op:EQ|NE|LT|GT|LE>/(l1), *Instruction thenPart, LABEL(l1), *Instruction post])
list[Instruction] stmts([*Instruction pre, stat(\if(c ,[asm([*Instruction thenPart, GOTO(l1)])])), LABEL(_), *Instruction elsePart, LABEL(l1), *Instruction post])
list[Instruction] stmts([*Instruction pre, stat(\return(Exp e)), NOP(), *Instruction post])
list[Instruction] stmts([*Instruction pre, stat(\return(Exp e)), ATHROW(), *Instruction post])
data Instruction
data Instruction (lrel[Case, str] cases = [])
function stmts
list[Instruction] stmts([*Instruction pre, TABLESWITCH(int from, int to, str def, list[str] keys, cases=cl), LABEL(str c1), *Instruction case1, LABEL(str c2), *Instruction post])
list[Instruction] stmts([*Instruction pre, TABLESWITCH(int from, int to, str def, list[str] keys, cases=cl), LABEL(str c1), *Instruction case1, LABEL(def), *Instruction post])
list[Instruction] stmts([*Instruction pre, exp(a), TABLESWITCH(int from, _, str def, list[str] keys, cases=lrel[Case, str] cl), LABEL(def), *Instruction defCase, LABEL(str brk), *Instruction post])
list[Instruction] stmts([*Instruction pre, exp(a), TABLESWITCH(int from, _, str def, list[str] keys, cases=cl), LABEL(def), *Instruction post])
function sharedCases
list[Case] sharedCases(int key, str lab, list[str] keys, int offset)
function sharedDefaults
list[Case] sharedDefaults(str lab, list[str] keys, int offset)
data Instruction
data Instruction (list[Handler] handlers=[])
function stmts
list[Instruction] stmts(
[
*Instruction pre,
TRYCATCH(Type \typ1, str from, str to, str handler1, handlers=hs),
TRYCATCH(Type \typ2, from, to, str handler2),
*Instruction block,
LABEL(to),
Instruction jump, // RETURN GOTO OR BREAK
LABEL(handler1),
exp(load(str var)), // This was rewritten from a ASTORE(ind) earlier by the `jump` function
*Instruction catch1,
LABEL(handler2),
*Instruction post
])
data Stat
data Stat
= multiCatchHandler()
;
function stmts
list[Instruction] stmts(
[
*Instruction pre,
TRYCATCH(Type \typ1, str from, str to, str handler1, handlers=hs),
TRYCATCH(Type \typ2, from, to, handler1),
*Instruction block,
LABEL(to),
Instruction jump,
LABEL(handler1),
exp(load(str var)), // This was rewritten from a ASTORE(ind) earlier by the `jump` function
*Instruction post
])
list[Instruction] stmts(
[*Instruction pre,
TRYCATCH(Type \typ1, str from, str to, str handler1, handlers=hs),
LABEL(from),
*Instruction block,
LABEL(to),
GOTO(\join), // jump to after the final handler
LABEL(handler1),
exp(load(str var)), // This was rewritten from a ASTORE(ind) earlier by the `jump` function
*Instruction catch1,
LABEL(\join),
*Instruction post
])
list[Instruction] stmts(
[*Instruction pre,
TRYCATCH(Type \typ1, str from, str to, str handler1, handlers=hs),
LABEL(from),
*Instruction block,
LABEL(to),
Instruction jump, // no jump to after the final handler, look elsewhere
LABEL(handler1),
exp(load(str var)),
*Instruction catch1,
LABEL(str \join),
*Instruction post
])
list[Instruction] stmts(
[
*Instruction pre,
TRYCATCH(Type \typ1, str from, str to, str handler1, handlers=hs),
LABEL(from),
*Instruction block,
LABEL(to),
Instruction jump, // RETURN OR BREAK
LABEL(handler1),
exp(load(str var)),
*Instruction post
])
list[Instruction] stmts(
[ *Instruction pre,
TRYCATCH(Type typ, str from, str to, str handler, handlers=hs),
TRYCATCH(_, from, to, str finallyHandler),
LABEL(from),
*Instruction tryBlock,
LABEL(to),
*Instruction finallyHandlerBlock, // the boundary with endTryBlock is implicit, but guarded by the exact re-occurrence of the finallyHandlerBlock block later
*Instruction endTryBlock,
TRYCATCH(_, handler, str endHandler, finallyHandler),
LABEL(handler),
exp(load(str var)),
*Instruction handlerBlock,
LABEL(endHandler),
*finallyHandlerBlock, // guarded duplicate helps to identify the width of the finally handler before
*Instruction endHandlerBlock,
LABEL(finallyHandler),
ASTORE(int eTmp),
*finallyHandlerBlock, // this is the piece which identifies the finally handler (due to the ASTORE, ALOAD, ATHROW "brackets")
ALOAD(eTmp),
ATHROW(),
*Instruction post
])
list[Instruction] stmts([*Instruction pre, /[IFLDA]STORE/(int tmp), /[IFLDA]LOAD/(tmp), *Instruction post])
list[Instruction] stmts([*Instruction pre, stat(\try(list[Stat] block, [*Handler preh, \catch(Type typ1, str var, [multiCatchHandler()]), \catch(Type typ2, var, list[Stat] catch1), *Handler posth])), *Instruction post])
list[Instruction] stmts([*Instruction pre, stat(\if(eq(Exp a, const(Type _, 0)), thenPart, elsePart)), *Instruction post])
list[Instruction] stmts([*Instruction pre, stat(\if(eq(Exp a, const(Type _, 0)), thenPart)), *Instruction post])
list[Instruction] stmts([*Instruction pre, stat(\for(init, eq(Exp a, const(Type _, 0)), next, block)), *Instruction post])
list[Instruction] stmts([*Instruction pre, stat(\if(ne(Exp a, const(Type _, 0)), thenPart, elsePart)), *Instruction post])
list[Instruction] stmts([*Instruction pre, stat(\if(ne(Exp a, const(Type _, 0)), thenPart)), *Instruction post])
list[Instruction] stmts([*Instruction pre, stat(\for(init, ne(Exp a, const(Type _, 0)), next, block)), *Instruction post])
list[Instruction] stmts([*Instruction pre, exp(e), stat(s), *Instruction post])
list[Instruction] stmts([*Instruction pre, exp(e)])
list[Instruction] stmts([*Instruction pre, exp(a), exp(b), /IF_[IA]CMP<op:EQ|NE|LT|GE|LE>/(label), *Instruction post])
list[Instruction] stmts([*Instruction pre, exp(a), exp(b), /IF<op:EQ|NE|LT|GE|LE>/(label), *Instruction post])
list[Instruction] stmts([*Instruction pre, GOTO(str cond), LABEL(str body), *Instruction b, LABEL(cond), stat(\if(Exp c, [asm([GOTO(body)])])), *Instruction post])
list[Instruction] stmts([*Instruction pre, LABEL(str body), *Instruction c, stat(\if(Exp co, [asm([GOTO(body)])])), *Instruction post])
list[Instruction] stmts([*Instruction pre, stat(first:store(str name,_)), stat(\while(c, [asm([*Instruction b, stat(Stat next)])])), *Instruction post])
list[Instruction] stmts([*Instruction pre, stat(first:store(str name, _)), stat(\for(firsts, c, nexts, [asm([*Instruction b, stat(Stat next)])])), *Instruction post])
default list[Instruction] stmts(list[Instruction] st)
function exprs
Recovers the structure of expressions and very basic statements.
list[Instruction] exprs([*Instruction pre, exp(e), /[AIFLD]STORE/(int var), *Instruction mid, Instruction lv:LOCALVARIABLE(str name, Type t, _, _, var), *Instruction post])
list[Instruction] exprs([*Instruction pre, exp(arr), exp(ind), exp(arg), /[AIFLDCSB]ASTORE/(), *Instruction mid, Instruction lv:LOCALVARIABLE(str name, _, _, _, var), *Instruction post])
list[Instruction] exprs([*Instruction pre, exp(e), DUP(), *Instruction post])
list[Instruction] exprs([*Instruction pre, tc:TRYCATCH(_, _, _, handler), *Instruction other, LABEL(str handler), ASTORE(int var), *Instruction mid, Instruction lv:LOCALVARIABLE(str name, _, _, _, var), *Instruction post])
list[Instruction] exprs([*Instruction pre, IINC(int var, int i), *Instruction mid, Instruction lv:LOCALVARIABLE(str name, _, _, _, var), *Instruction post])
list[Instruction] exprs([*Instruction pre, /[AIFLD]LOAD/(int var), *Instruction mid, Instruction lv:LOCALVARIABLE(str name, _, _, _, var), *Instruction post])
list[Instruction] exprs([*Instruction pre, exp(arr), exp(idx), /[AIFLDBCS]ALOAD/(), *Instruction mid, Instruction lv:LOCALVARIABLE(str name, _, _, _, var), *Instruction post])
list[Instruction] exprs([*Instruction pre, exp(a), /[ILFDA]RETURN/(), *Instruction post])
list[Instruction] exprs([*Instruction pre, exp(a), ATHROW(), *Instruction post])
list[Instruction] exprs([*Instruction pre, exp(rec), exp(arg), PUTFIELD(cls, name, typ), *Instruction post])
list[Instruction] exprs([*Instruction pre, RETURN(), *Instruction post])
list[Instruction] exprs([*Instruction pre, NOP(), *Instruction post])
list[Instruction] exprs([*Instruction pre, ACONST_NULL(), *Instruction post])
list[Instruction] exprs([*Instruction pre, /<t:[IFLD]>CONST_<i:[0-5]>/(), *Instruction post])
list[Instruction] exprs([*Instruction pre, exp(a), ARRAYLENGTH(), *Instruction post])
list[Instruction] exprs([*Instruction pre, exp(a), /[IFLD]NEG/(), *Instruction post])
list[Instruction] exprs([*Instruction pre, exp(Exp a), exp(Exp b), /[LFDI]<op:(ADD|SUB|MUL|DIV|REM|SHL|SHR|AND|OR|XOR|ALOAD)>/(), *Instruction post])
list[Instruction] exprs([*Instruction pre, *Instruction args, INVOKEDYNAMIC(methodDesc(ret, name, formals), BootstrapCall handle), *Instruction post])
list[Instruction] exprs([*Instruction pre, exp(Exp r), *Instruction args, INVOKEVIRTUAL(cls, methodDesc(ret, name, formals), _), *Instruction post])
list[Instruction] exprs([*Instruction pre, exp(Exp r), *Instruction args, INVOKEINTERFACE(cls, methodDesc(ret, name, formals), _), *Instruction post])
list[Instruction] exprs([*Instruction pre, exp(Exp r), *Instruction args, INVOKESPECIAL(cls, methodDesc(ret, name, formals), _), *Instruction post])
list[Instruction] exprs([*Instruction pre, NEW(typ), DUP(), *Instruction args, INVOKESPECIAL(cls, constructorDesc(formals), _), *Instruction post])
list[Instruction] exprs([*Instruction pre, exp(load("this")), *Instruction args, INVOKESPECIAL(cls, constructorDesc(formals), _), *Instruction post])
list[Instruction] exprs([*Instruction pre, *Instruction args, INVOKESTATIC(cls, methodDesc(ret, name, formals), _), *Instruction post])
list[Instruction] exprs([*Instruction pre, exp(const(Type intType, int arraySize)), ANEWARRAY(typ), *Instruction elems, *Instruction post])
default list[Instruction] exprs([*Instruction pre, exp(Exp sizeExp:const(Type intType, int arraySize)), ANEWARRAY(typ), *Instruction post])
list[Instruction] exprs([*Instruction pre, exp(const(integer(), int len)), NEWARRAY(typ), DUP(), exp(const(integer(), _)), exp(Exp elem), IASTORE(), *Instruction post])
list[Instruction] exprs([*Instruction pre, exp(newInitArray(typ, elems)), DUP(), exp(const(integer(), _)), exp(Exp elem), IASTORE(), *Instruction post])
list[Instruction] exprs([*Instruction pre, GETSTATIC(cls, name, typ), *Instruction post])
list[Instruction] exprs([*Instruction pre, exp(e), PUTSTATIC(cls, name, typ), *Instruction post])
list[Instruction] exprs([*Instruction pre, exp(a), GETFIELD(cls, name, typ), *Instruction post])
list[Instruction] exprs([*Instruction pre, exp(a), CHECKCAST(typ), *Instruction post])
list[Instruction] exprs([*Instruction pre, LDC(typ, constant), *Instruction post])
list[Instruction] exprs([*Instruction pre, BIPUSH(int i), *Instruction post])
list[Instruction] exprs([*Instruction pre, exp(a), exp(b), /IF_[IA]CMP<op:EQ|NE|LT|GE|LE>/(str l1), exp(ifBranch), GOTO(str l2), LABEL(l1), exp(elseBranch), LABEL(l2), *Instruction post])
list[Instruction] exprs([*Instruction pre, exp(a), /IF<op:EQ|NE|LT|GT|LE>/(str l1), exp(ifBranch), GOTO(str l2), LABEL(l1), exp(elseBranch), LABEL(l2), *Instruction post])
list[Instruction] exprs([*Instruction pre, exp(a), IFNULL(str l1), exp(ifBranch), GOTO(str l2), LABEL(l1), exp(elseBranch), LABEL(l2), *Instruction post])
list[Instruction] exprs([*Instruction pre, exp(a), IFNONNULL(str l1), exp(ifBranch), GOTO(str l2), LABEL(l1), exp(elseBranch), LABEL(l2), *Instruction post])
list[Instruction] exprs(
[*Instruction pre,
exp(a),
exp(b),
/IF_<op1:[IA]CMP(EQ|NE|LT|GE|LE)>/(str short),
exp(c),
exp(d),
/IF_<op2:[IA]CMP(EQ|NE|LT|GE|LE)>/(str long),
LABEL(short),
*Instruction post
])
list[Instruction] exprs(
[*Instruction pre,
exp(a),
exp(b),
/IF_<op1:[IA]CMP(EQ|NE|LT|GE|LE)>/(str long),
exp(c),
exp(d),
/IF_<op2:[IA]CMP(EQ|NE|LT|GE|LE)>/(long),
*Instruction post
])
default list[Instruction] exprs(list[Instruction] instr)
function typ
Type typ("I")
Type typ("F")
Type typ("L")
Type typ("D")
Type typ("S")
Type typ("B")
Type typ("Z")
alias BinOp
Exp (Exp, Exp)
function invertedCond
BinOp invertedCond("EQ")
BinOp invertedCond("NE")
BinOp invertedCond("LT")
BinOp invertedCond("GE")
BinOp invertedCond("GT")
BinOp invertedCond("LE")
BinOp invertedCond("ICMPEQ")
BinOp invertedCond("ICMPNE")
BinOp invertedCond("ICMPLT")
BinOp invertedCond("ICMPGE")
BinOp invertedCond("ICMPLE")
BinOp invertedCond("ACMPEQ")
BinOp invertedCond("ACMPNE")
function condOp
BinOp condOp("EQ")
BinOp condOp("NE")
BinOp condOp("LT")
BinOp condOp("GE")
BinOp condOp("GT")
BinOp condOp("LE")
BinOp condOp("ICMPEQ")
BinOp condOp("ICMPNE")
BinOp condOp("ICMPLT")
BinOp condOp("ICMPGE")
BinOp condOp("ICMPLE")
BinOp condOp("ACMPEQ")
BinOp condOp("ACMPNE")
function binOp
BinOp binOp("ADD")
BinOp binOp("SUB")
BinOp binOp("MUL")
BinOp binOp("DIV")
BinOp binOp("REM")
BinOp binOp("SHL")
BinOp binOp("SHR")
BinOp binOp("AND")
BinOp binOp("OR")
BinOp binOp("XOR")
BinOp binOp("ALOAD")
alias UnOp
Exp (Exp)
function invertedUnaryCond
UnOp invertedUnaryCond("NULL")
UnOp invertedUnaryCond("NONNULL")
function nonnull
Exp nonnull(Exp e)
function null
Exp null(Exp e)
function clean
Removes left-over labels, embedded assembly blocks which only contain statements, and lifts left-over expressions to expression-statements.
list[Stat] clean([*Stat pre, asm([*Instruction preI, LABEL(_), *Instruction postI]), *Stat post])
list[Stat] clean([*Stat pre, asm([*Instruction preI, stat(s), *Instruction postI]), *Stat post])
list[Stat] clean([*Stat pre, asm([*Instruction preI, exp(a), *Instruction postI]), *Stat post])
list[Stat] clean([*Stat pre, asm([]), *Stat post])
list[Stat] clean([*Stat pre, \do(cond(Exp c, Exp i, Exp t)), *Stat post])
default list[Stat] clean(list[Stat] x)
function breaks
&T breaks(&T l, str breakLabel)
function tryJoins
&T tryJoins(&T l, str joinLabel)
function fixContinues
&T fixContinues(&T input, str label)
function isSideEffectFree
bool isSideEffectFree(\true())
bool isSideEffectFree(\false())
bool isSideEffectFree(\load(_))
bool isSideEffectFree(\aload(_,_))
bool isSideEffectFree(null())
bool isSideEffectFree(const(_,_))
default bool isSideEffectFree(Exp _)
function recover
Exp recover(const(Type _, 0), \boolean())
Exp recover(const(Type _, 1), \boolean())
default Exp recover(Exp e, Type t)
function asm
Stat asm([stat(Stat s)])
function neg
Exp neg(neg(Exp e))
function \if
Stat \if(Exp c1, [\if(Exp c2, list[Stat] body)])