Search code examples
javajava-bytecode-asmbytecode-manipulation

Java Bytecode - ASM - Get Label Offset


I am trying to get the offsets of all labels in a method.

I tried using the following code:

private static ArrayList<Integer> GetLabelOffsets(MethodNode methodNode) {
    ArrayList<Integer> labelOffsets = new ArrayList<>();

    for (AbstractInsnNode instruction : methodNode.instructions.toArray()) {
        if (instruction instanceof JumpInsnNode) {
            JumpInsnNode jumpInsnNode = (JumpInsnNode) instruction;
            labelOffsets.add(jumpInsnNode.label.getLabel().getOffset());.
        }
    }

    return labelOffsets;
}

However the getOffset() method throws an Exception:

java.lang.IllegalStateException: Label offset position has not been resolved yet

How can I resolve these offset positions? Or what is the proper way to achieve this?

Edit

The MethodNode is an org.objectweb.asm.tree.MethodNode Object from the Java ASM library

Added more code at request:

public static HashMap<String, ClassNode> ParseJar(JarFile jar) {
    HashMap<String, ClassNode> classes = new HashMap<>();

    try {
        Enumeration<?> enumeration = jar.entries();
        while (enumeration.hasMoreElements()) {
            JarEntry entry = (JarEntry) enumeration.nextElement();

            if (entry.getName().endsWith(".class")) {
                ClassReader classReader = new ClassReader(jar.getInputStream(entry));
                ClassNode classNode = new ClassNode();
                classReader.accept(classNode, ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
                classes.put(classNode.name, classNode);
            }

        }
        jar.close();
        return classes;
    } catch (Exception ex) {
        return null;
    }
}

public static void main(String[] args) {
    JarFile jar = new JarFile(fileName);
    HashMap<String, ClassNode> classes = JarUtils.ParseJar(jar);
    for (ClassNode classNode : classes.values()) {
        for (MethodNode methodNode : classNode.methods) {
            ArrayList<Integer> offsets = GetLabelOffsets(methodNode);
            // do more stuff with offsets
        }
    }
}

Solution

  • From the documentation of getOffset():

    This method is intended for Attribute sub classes, and is normally not needed by class generators or adapters.

    Since this offset is defined in terms of bytes, it wouldn’t be very helpful when processing a list of instructions, especially as ASM abstracts the different forms of instructions that may have different lengths in byte code.

    The general idea is that this instruction list can be changed, so Labels represent logical positions and the offset will be calculated when writing a method’s resulting bytecode and the actual numbers are known.

    Within the instruction list, there should be a corresponding LabelNode referencing the same Label as the instruction.