编写ASM代码工具类

简介: 编写ASM代码工具类

ASMPrint类

下面是ASMPrint类的代码,它是利用org.objectweb.asm.util.TraceClassVisitor类来实现的。在使用的时候,我们注意修改一下className、parsingOptions和asmCode参数就可以了。

import jdk.internal.org.objectweb.asm.ClassReader;
import jdk.internal.org.objectweb.asm.util.ASMifier;
import jdk.internal.org.objectweb.asm.util.Printer;
import jdk.internal.org.objectweb.asm.util.Textifier;
import jdk.internal.org.objectweb.asm.util.TraceClassVisitor;
 
import java.io.IOException;
import java.io.PrintWriter;
 
public class ASMPrint {
    public static void main(String[] args) throws IOException {
        // (1) 设置参数
        String className = "sample.HelloWorld";
        int parsingOptions = ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG;
        boolean asmCode = true;
 
        // (2) 打印结果
        Printer printer = asmCode ? new ASMifier() : new Textifier();
        PrintWriter printWriter = new PrintWriter(System.out, true);
        TraceClassVisitor traceClassVisitor = new TraceClassVisitor(null, printer, printWriter);
        new ClassReader(className).accept(traceClassVisitor, parsingOptions);
    }
}

在现在阶段,我们主要是使用这个类,来帮助我们生成ASM代码;

ASMPrint类使用示例

假如,有如下一个HelloWorld类:

public class HelloWorld {
    public void test() {
        System.out.println("Test Method");
    }
}

对于ASMPrint类来说,其中

  • className值设置为类的全限定名,可以是我们自己写的类,例如sample.HelloWorld,也可以是JDK自带的类,例如java.lang.Comparable。
  • asmCode值设置为true或false。如果是true,可以打印出对应的ASM代码;如果是false,可以打印出方法对应的Instruction。
  • parsingOptions值设置为ClassReader.SKIP_CODE、ClassReader.SKIP_DEBUG、ClassReader.SKIP_FRAMES、ClassReader.EXPAND_FRAMES的组合值,也可以设置为0,可以打印出详细程度不同的信息。

运行结果示例:

package asm.sample;
import java.util.*;
import jdk.internal.org.objectweb.asm.*;
public class HelloWorldDump implements Opcodes {
 
public static byte[] dump () throws Exception {
 
ClassWriter cw = new ClassWriter(0);
FieldVisitor fv;
MethodVisitor mv;
AnnotationVisitor av0;
 
cw.visit(52, ACC_PUBLIC + ACC_SUPER, "sample/HelloWorld", null, "java/lang/Object", new String[] { "java/lang/Cloneable" });
 
{
fv = cw.visitField(ACC_PRIVATE + ACC_FINAL + ACC_STATIC, "intValue", "I", null, new Integer(10));
fv.visitEnd();
}
{
mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
mv.visitInsn(RETURN);
mv.visitMaxs(1, 1);
mv.visitEnd();
}
{
mv = cw.visitMethod(ACC_PUBLIC, "test", "()V", null, null);
mv.visitCode();
mv.visitInsn(ICONST_1);
mv.visitVarInsn(ISTORE, 1);
mv.visitInsn(ICONST_2);
mv.visitVarInsn(ISTORE, 2);
mv.visitVarInsn(ILOAD, 1);
mv.visitVarInsn(ILOAD, 2);
mv.visitInsn(IADD);
mv.visitVarInsn(ISTORE, 3);
mv.visitInsn(RETURN);
mv.visitMaxs(2, 4);
mv.visitEnd();
}
{
mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null);
mv.visitParameter("args", 0);
mv.visitCode();
mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
mv.visitLdcInsn("HelloWorld");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);
mv.visitInsn(RETURN);
mv.visitMaxs(2, 1);
mv.visitEnd();
}
cw.visitEnd();
 
return cw.toByteArray();
}
}

粘贴到Android studio会自动排版。

类似工具:

public class PrintASMCodeCore {
    public static void main(String[] args) throws Exception {
        readClass(ServiceProvider.class.getName());
    }
 
    /**
     * @param className 接受.分割符分割的类名
     */
    private static void readClass(String className) throws IOException {
        // (1) 设置参数
        int parsingOptions = ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG;
        // (2) 打印结果
        Printer printer = new ASMifier();
        PrintWriter printWriter = new PrintWriter(System.out, true);
        TraceClassVisitor traceClassVisitor = new TraceClassVisitor(null, printer, printWriter);
        new ClassReader(className).accept(traceClassVisitor, parsingOptions);
    }
}

其他相关工具类

PrintASMCodeCore.java

package run;
 
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.util.ASMifier;
import org.objectweb.asm.util.Printer;
import org.objectweb.asm.util.TraceClassVisitor;
 
import java.io.IOException;
import java.io.PrintWriter;
 
/**
 * Print asm core code.
 *
 * @see ASMPrint
 * @see PrintASMCodeTree
 * @see PrintASMTextClass
 * @see PrintASMTextLambda
 */
public class PrintASMCodeCore {
    public static void main(String[] args) throws IOException {
        // (1) 设置参数
        String className = "sample.HelloWorld";
        int parsingOptions = ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG;
 
        // (2) 打印结果
        Printer printer = new ASMifier();
        PrintWriter printWriter = new PrintWriter(System.out, true);
        TraceClassVisitor traceClassVisitor = new TraceClassVisitor(null, printer, printWriter);
        new ClassReader(className).accept(traceClassVisitor, parsingOptions);
    }
}

PrintASMCodeTree.java

package run;
 
import lsieun.asm.util.TreePrinter;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.util.Printer;
import org.objectweb.asm.util.TraceClassVisitor;
 
import java.io.IOException;
import java.io.PrintWriter;
 
/**
 * Print asm tree code.
 *
 * @see ASMPrint
 * @see PrintASMCodeCore
 * @see PrintASMTextClass
 * @see PrintASMTextLambda
 */
public class PrintASMCodeTree {
    public static void main(String[] args) throws IOException {
        // (1) 设置参数
        String className = "sample.HelloWorld";
        int parsingOptions = ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG;
 
        // (2) 打印结果
        Printer printer = new TreePrinter();
        PrintWriter printWriter = new PrintWriter(System.out, true);
        TraceClassVisitor traceClassVisitor = new TraceClassVisitor(null, printer, printWriter);
        new ClassReader(className).accept(traceClassVisitor, parsingOptions);
    }
}

PrintASMTextClass.java

package run;
 
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.util.Printer;
import org.objectweb.asm.util.Textifier;
import org.objectweb.asm.util.TraceClassVisitor;
 
import java.io.IOException;
import java.io.PrintWriter;
 
/**
 * @see ASMPrint
 * @see PrintASMCodeCore
 * @see PrintASMCodeTree
 * @see PrintASMTextLambda
 */
public class PrintASMTextClass {
    public static void main(String[] args) throws IOException {
        // (1) 设置参数
        String className = "sample.HelloWorld";
        int parsingOptions = ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG;
 
        // (2) 打印结果
        Printer printer = new Textifier();
        PrintWriter printWriter = new PrintWriter(System.out, true);
        TraceClassVisitor traceClassVisitor = new TraceClassVisitor(null, printer, printWriter);
        new ClassReader(className).accept(traceClassVisitor, parsingOptions);
    }
}

PrintASMTextLambda.java

package run;
 
import lsieun.utils.StringUtils;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.util.Printer;
import org.objectweb.asm.util.Textifier;
import org.objectweb.asm.util.TraceClassVisitor;
 
import java.io.IOException;
import java.io.PrintWriter;
 
/**
 * Print Lambda anonymous inner class.
 *
 * @see ASMPrint
 * @see PrintASMCodeCore
 * @see PrintASMCodeTree
 * @see PrintASMTextClass
 */
public class PrintASMTextLambda {
    public static void main(String[] args) throws IOException {
        // (1) 设置参数
        String str = "[-54, -2, -70, -66, ...]";
        byte[] bytes = StringUtils.array2Bytes(str);
        int parsingOptions = ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG;
 
        // (2) 打印结果
        Printer printer = new Textifier();
        PrintWriter printWriter = new PrintWriter(System.out, true);
        TraceClassVisitor traceClassVisitor = new TraceClassVisitor(null, printer, printWriter);
        new ClassReader(bytes).accept(traceClassVisitor, parsingOptions);
    }
}

PrintOpcodeTable.java

package run;
 
import lsieun.utils.OpcodeConst;
 
/**
 * Print opcode between {@link #start} and {@link #stop}.
 */
public class PrintOpcodeTable {
    private static int start = 0;
    private static int stop = 256;
 
    public static void main(String[] args) throws Exception {
        printOpcode();
    }
 
    public static void printOpcode() {
        if (start < 0) {
            start = 0;
        }
        if (stop > 256) {
            stop = 256;
        }
        int num = stop - start;
        int column = 4;
        int row = num / column;
        int remainder = num % column;
        if (remainder != 0) {
            row++;
        }
        System.out.println("| opcode | mnemonic symbol | opcode | mnemonic symbol | opcode | mnemonic symbol | opcode | mnemonic symbol |");
        System.out.println("|--------|-----------------|--------|-----------------|--------|-----------------|--------|-----------------|");
        for (int i = 0; i < row; i++) {
            int val1 = start + i;
            int val2 = val1 + row;
            int val3 = val2 + row;
            int val4 = val3 + row;
            String line = String.format("| %-6d | %-15s | %-6d | %-15s | %-6d | %-15s | %-6d | %-15s |",
                    val1, getOpcodeName(val1),
                    val2, getOpcodeName(val2),
                    val3, getOpcodeName(val3),
                    val4, getOpcodeName(val4)
            );
            System.out.println(line);
        }
    }
 
    public static String getOpcodeName(int i) {
        if (i < 0 || i >= OpcodeConst.OPCODE_NAMES_LENGTH) {
            return "";
        }
        if (i < start || i >= stop) {
            return "";
        }
        String opcodeName = OpcodeConst.getOpcodeName(i);
        if (OpcodeConst.ILLEGAL_OPCODE.equals(opcodeName)) {
            opcodeName = "";
        }
        return opcodeName;
    }
}
相关文章
|
5月前
|
Java API
使用ASM为一个类增加属性工具类
使用ASM为一个类增加属性工具类
51 0
|
5月前
|
存储 算法 Java
Android 进阶——代码插桩必知必会&ASM7字节码操作
Android 进阶——代码插桩必知必会&ASM7字节码操作
241 0
|
5月前
|
存储 Java 编译器
使用ASM来书写Java代码
使用ASM来书写Java代码
46 0
|
开发框架 Java Maven
SpringBoot自定义maven-plugin插件整合asm代码插桩
公司开发框架增加了web系统license授权证书校验模块,实行一台机器一个授权证书,初步方案是增加拦截器针对全局请求进行拦截校验,评估后认为校验方式单一,应该增加重要工具类,业务service实现中每个方法的进行校验,因为涉及代码量较大硬编码工作困难,故选择通过自定义maven插件在编译期间进行动态代码插桩操作
144 1
|
编解码 数据库 计算机视觉
【图像分割和识别】活动形状模型 (ASM) 和活动外观模型 (AAM)(Matlab代码实现)
【图像分割和识别】活动形状模型 (ASM) 和活动外观模型 (AAM)(Matlab代码实现)
103 0
|
6月前
|
Oracle 关系型数据库
oracle asm 磁盘显示offline
oracle asm 磁盘显示offline
323 2
|
25天前
|
存储 Oracle 关系型数据库
数据库数据恢复—Oracle ASM磁盘组故障数据恢复案例
Oracle数据库数据恢复环境&故障: Oracle ASM磁盘组由4块磁盘组成。Oracle ASM磁盘组掉线 ,ASM实例不能mount。 Oracle数据库故障分析&恢复方案: 数据库数据恢复工程师对组成ASM磁盘组的磁盘进行分析。对ASM元数据进行分析发现ASM存储元数据损坏,导致磁盘组无法挂载。
|
6月前
|
存储 Oracle 关系型数据库
【数据库数据恢复】Oracle数据库ASM磁盘组掉线的数据恢复案例
oracle数据库ASM磁盘组掉线,ASM实例不能挂载。数据库管理员尝试修复数据库,但是没有成功。
【数据库数据恢复】Oracle数据库ASM磁盘组掉线的数据恢复案例
|
SQL Oracle 关系型数据库
Oracle ASM磁盘和磁盘组的常用SQL语句
Oracle ASM磁盘和磁盘组的常用SQL语句
282 0