Skip to content

Tonic-Box/YABR

Repository files navigation

YABR - Yet Another Bytecode Reader/Writer

A Java bytecode library with class-file parsing, bytecode editing, mutable IRs, (de)compilation, and a set of higher-level analyses.

Quick Start

// Load a class
ClassPool pool = ClassPool.getDefault();
ClassFile cf = pool.loadClass(inputStream);

// Create a new class with a default constructor
int access = new AccessBuilder().setPublic().build();
ClassFile newClass = ClassFactory.createClass(pool, "com/example/MyClass", access);

// Add a field with a getter and setter
FieldEntry field = newClass.createNewField(access, "value", "I", new ArrayList<>());
ClassFactory.generateGetter(newClass, field, false);
ClassFactory.generateSetter(newClass, field, false);

// Write the class
newClass.rebuild();
byte[] bytes = newClass.write();

Documentation

Guide Description
Quick Start Getting started
Architecture Module structure and design
Class Files ClassPool, ClassFile, ConstPool
Bytecode API Bytecode editing
Generation API Fluent class generation
Visitors Traversal patterns
SSA Guide SSA intermediate representation
SSA Transforms Optimizations and analysis
LLVM Lowering Lower SSA IR to textual LLVM IR
LLVM Lifting Lift LLVM IR back to SSA
SSA IR Migration API changes from the SSA IR redesign
Analysis APIs Code analysis and semantic queries
PDG API Program Dependence Graph with slicing
SDG API Interprocedural System Dependence Graph
CPG API Code Property Graph with taint analysis
Query API Bytecode query language
Abstract Execution API Operand-stack and local def-use
AST Guide AST recovery, mutation, and emission
AST Editor ExprEditor-style AST transformation
Renamer API Class, method, and field renaming
Frame Computation StackMapTable generation

Bytecode Generation

import com.tonic.builder.ClassBuilder;
import com.tonic.type.AccessFlags;

byte[] bytes = ClassBuilder.create("com/example/Calculator")
    .version(AccessFlags.V11, 0)
    .access(AccessFlags.ACC_PUBLIC)
    .addMethod(AccessFlags.ACC_PUBLIC | AccessFlags.ACC_STATIC, "add", "(II)I")
        .code()
            .iload(0)
            .iload(1)
            .iadd()
            .ireturn()
        .end()
    .end()
    .toByteArray();

SSA Pipeline

Bytecode -> Lift -> SSA IR -> Optimize -> Lower -> Bytecode
                       |                    ^
                   [Recover]            [Lower]
                       |                    |
                       v                    |
                      AST ----[Mutate]----> AST
SSA ssa = new SSA(constPool)
    .withConstantFolding()
    .withCopyPropagation()
    .withDeadCodeElimination();

ssa.transform(method);  // lift, optimize, and lower

The IR can also be lowered to textual LLVM IR (.ll) and lifted back. See LLVM Lowering and LLVM Lifting.

Decompilation

import com.tonic.analysis.source.decompile.ClassDecompiler;

String source = ClassDecompiler.decompile(classFile);

// With per-method bytecode-offset-to-source-line maps
DecompileResult result = new ClassDecompiler(classFile).decompileWithLineMap();

Analysis APIs

Call graph, dependency, type inference, pattern search, xrefs, data flow, similarity, and graph analyses (PDG, SDG, CPG) are documented in Analysis APIs.

Examples

Runnable examples are in examples/src/main/java/com/tonic/demo/, including class creation, SSA transformation, LLVM lowering, AST mutation, decompilation, call graphs, dependency analysis, type inference, and pattern search.

Project Layout

YABR is a Gradle multi-project. Production code is split into layered modules (core, bytecode, renamer, ssa, source, analyses, execution, query) whose dependencies are acyclic and build-enforced; the all module merges them into a single jar. See Architecture.

Installation

The published artifact is the merged jar from the all module. Via JitPack:

repositories {
    mavenCentral()
    maven { url = uri("https://jitpack.io") }
}

dependencies {
    implementation("com.github.Tonic-Box.YABR:all:<version>")
}

Building

./gradlew build              # build and test all modules
./gradlew :all:shadowJar     # produce the merged jar

Requirements

  • Java 11+

Acknowledgements

Inspired by classpooly.

License

MIT

About

Java bytecode toolkit: procedural API, SSA IR, optimization transforms, mutable AST API, (de)compilation.

Topics

Resources

License

Stars

Watchers

Forks

Contributors

Languages