Skip to main content

module lang::flybytes::Decompiler

rascal-0.34.0
flybytes-0.2.3

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)

Method decompile(Method m)

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 invertedCond

UnOp invertedCond("NULL")

UnOp invertedCond("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)])