Skip to main content

module lang::flybytes::Decompiler

rascal-0.42.0
org.rascalmpl.flybytes-0.2.11

Usage​

import lang::flybytes::Decompiler;

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)])