Skip to content

Instantly share code, notes, and snippets.

@comp500
Created August 21, 2020 23:27
Show Gist options
  • Save comp500/a752b4b5cd13f30e5e4ecbc07dabc511 to your computer and use it in GitHub Desktop.
Save comp500/a752b4b5cd13f30e5e4ecbc07dabc511 to your computer and use it in GitHub Desktop.

Revisions

  1. comp500 created this gist Aug 21, 2020.
    131 changes: 131 additions & 0 deletions jdwpdump.java
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,131 @@
    package link.infra.jdwp;

    import com.sun.jdi.Field;
    import com.sun.jdi.LocalVariable;
    import com.sun.jdi.Method;
    import com.sun.jdi.ReferenceType;
    import com.sun.jdi.*;
    import com.sun.jdi.connect.AttachingConnector;
    import com.sun.jdi.connect.Connector;
    import com.sun.jdi.connect.IllegalConnectorArgumentsException;
    import org.apache.bcel.classfile.*;
    import org.apache.bcel.generic.Type;
    import org.apache.bcel.generic.*;

    import java.io.*;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Map;

    public class App {
    public static void main(String[] args) throws IOException, IllegalConnectorArgumentsException {
    List<AttachingConnector> connectors = Bootstrap.virtualMachineManager().attachingConnectors();
    for (AttachingConnector connector : connectors) {
    if (connector.name().equals("com.sun.jdi.SocketAttach")) {
    Map<String, Connector.Argument> connArgs = connector.defaultArguments();
    connArgs.get("port").setValue("5005");
    VirtualMachine vm = connector.attach(connArgs);

    for (ReferenceType refType : vm.allClasses()) {
    if (!(refType instanceof ClassType)) {
    continue;
    }
    ClassType clazz = ((ClassType) refType);

    // TODO: test with j9+
    if (clazz.classLoader() == null) {
    continue;
    }
    // TODO: workaround for lambdas?
    String sourceName;
    try {
    sourceName = clazz.sourceName();
    } catch (AbsentInformationException ignored) { continue; }
    String name = clazz.name().replace('.', '/');

    byte[] hmmm = clazz.constantPool();
    ByteArrayOutputStream baos = new ByteArrayOutputStream(hmmm.length + 2);
    DataOutputStream dos = new DataOutputStream(baos);
    // TODO: unsigned?
    dos.writeShort(clazz.constantPoolCount());
    dos.write(hmmm);
    ConstantPoolGen poolGen = new ConstantPoolGen(new ConstantPool(new DataInputStream(new ByteArrayInputStream(baos.toByteArray()))));

    String superClassName;
    ClassType superClass = clazz.superclass();
    if (superClass != null) {
    superClassName = superClass.name().replace('.', '/');
    } else {
    superClassName = "java/lang/Object";
    }
    String[] implementedInterfaces = clazz.interfaces().stream().map(ReferenceType::name).toArray(String[]::new);

    ClassGen classGen = new ClassGen(name,
    superClassName,
    sourceName,
    clazz.modifiers(),
    implementedInterfaces, poolGen);
    classGen.setMinor(clazz.minorVersion());
    classGen.setMajor(clazz.majorVersion());
    String classGenericSignature = clazz.genericSignature();
    if (classGenericSignature != null && classGenericSignature.length() > 0) {
    classGen.addAttribute(new Signature(poolGen.lookupUtf8("Signature"), 2, poolGen.lookupUtf8(classGenericSignature), poolGen.getConstantPool()));
    }
    // TODO: the necessary metadata for bootstrap methods isn't available!! :(

    // TODO: inner classes
    // TODO: enclosing method?

    for (Field field : clazz.fields()) {
    FieldGen fieldGen = new FieldGen(field.modifiers(),
    Type.getType(Utility.getSignature(field.typeName())),
    field.name(),
    poolGen);
    String genericSignature = field.genericSignature();
    if (genericSignature != null && genericSignature.length() > 0) {
    fieldGen.addAttribute(new Signature(poolGen.lookupUtf8("Signature"), 2, poolGen.lookupUtf8(genericSignature), poolGen.getConstantPool()));
    }
    classGen.addField(fieldGen.getField());
    }

    for (Method method : clazz.methods()) {
    String[] argNameList = null;
    try {
    argNameList = method.arguments().stream().map(LocalVariable::name).toArray(String[]::new);
    } catch (AbsentInformationException ignored) {}
    String[] argTypeList = Utility.methodSignatureArgumentTypes(method.signature());
    if (argNameList == null || argTypeList.length != argNameList.length) {
    // TODO: better names
    argNameList = argTypeList;
    }
    MethodGen methodGen = new MethodGen(method.modifiers(),
    Type.getReturnType(method.signature()),
    Type.getArgumentTypes(method.signature()),
    argNameList,
    method.name(),
    name,
    new InstructionList(method.bytecodes()),
    poolGen);
    // TODO: line numbers
    // TODO: LVT
    // TODO: LVTT
    //method.variables();
    methodGen.setMaxStack();
    methodGen.setMaxLocals();
    String genericSignature = method.genericSignature();
    if (genericSignature != null && genericSignature.length() > 0) {
    methodGen.addAttribute(new Signature(poolGen.lookupUtf8("Signature"), 2, poolGen.lookupUtf8(genericSignature), poolGen.getConstantPool()));
    }
    classGen.addMethod(methodGen.getMethod());
    }

    if (name.endsWith("class_310")) {
    classGen.getJavaClass().dump(new File("test.class"));
    break;
    }
    }
    vm.dispose();
    }
    }
    }
    }