Để phân tích bytecode, tôi khuyên bạn nên ASM. Đưa ra một danh sách các lớp để phân tích, một người truy cập có thể được thực hiện tìm thấy các cuộc gọi phương thức mà bạn quan tâm. Một triển khai thực hiện phân tích các lớp trong tệp jar bên dưới.
Lưu ý rằng ASM sử dụng internalNames bằng '/' thay vì '.' như một dấu phân cách. Chỉ định phương thức đích là standard declaration mà không có công cụ sửa đổi.
Ví dụ, để liệt kê các phương pháp có thể được gọi System.out.println ("foo") trong thời gian chạy jar java:
java -cp "classes;asm-3.1.jar;asm-commons-3.1.jar" App \
c:/java/jdk/jre/lib/rt.jar \
java/io/PrintStream "void println(String)"
Sửa: nguồn và dòng số thêm: Lưu ý rằng đây chỉ cho biết lời gọi phương thức mục tiêu cuối cùng cho mỗi phương thức gọi - q ban đầu chỉ muốn biết mà phương thức. Tôi để nó như là một bài tập cho người đọc để hiển thị số dòng của tuyên bố phương thức gọi điện thoại, hoặc số dòng của mỗi lời gọi mục tiêu, tùy thuộc vào những gì bạn đang thực sự sau. :)
kết quả trong:
LogSupport.java:44 com/sun/activation/registries/LogSupport log (Ljava/lang/String;)V
LogSupport.java:50 com/sun/activation/registries/LogSupport log (Ljava/lang/String;Ljava/lang/Throwable;)V
...
Throwable.java:498 java/lang/Throwable printStackTraceAsCause (Ljava/io/PrintStream;[Ljava/lang/StackTraceElement;)V
--
885 methods invoke java/io/PrintStream println (Ljava/lang/String;)V
nguồn:
public class App {
private String targetClass;
private Method targetMethod;
private AppClassVisitor cv;
private ArrayList<Callee> callees = new ArrayList<Callee>();
private static class Callee {
String className;
String methodName;
String methodDesc;
String source;
int line;
public Callee(String cName, String mName, String mDesc, String src, int ln) {
className = cName; methodName = mName; methodDesc = mDesc; source = src; line = ln;
}
}
private class AppMethodVisitor extends MethodAdapter {
boolean callsTarget;
int line;
public AppMethodVisitor() { super(new EmptyVisitor()); }
public void visitMethodInsn(int opcode, String owner, String name, String desc) {
if (owner.equals(targetClass)
&& name.equals(targetMethod.getName())
&& desc.equals(targetMethod.getDescriptor())) {
callsTarget = true;
}
}
public void visitCode() {
callsTarget = false;
}
public void visitLineNumber(int line, Label start) {
this.line = line;
}
public void visitEnd() {
if (callsTarget)
callees.add(new Callee(cv.className, cv.methodName, cv.methodDesc,
cv.source, line));
}
}
private class AppClassVisitor extends ClassAdapter {
private AppMethodVisitor mv = new AppMethodVisitor();
public String source;
public String className;
public String methodName;
public String methodDesc;
public AppClassVisitor() { super(new EmptyVisitor()); }
public void visit(int version, int access, String name,
String signature, String superName, String[] interfaces) {
className = name;
}
public void visitSource(String source, String debug) {
this.source = source;
}
public MethodVisitor visitMethod(int access, String name,
String desc, String signature,
String[] exceptions) {
methodName = name;
methodDesc = desc;
return mv;
}
}
public void findCallingMethodsInJar(String jarPath, String targetClass,
String targetMethodDeclaration) throws Exception {
this.targetClass = targetClass;
this.targetMethod = Method.getMethod(targetMethodDeclaration);
this.cv = new AppClassVisitor();
JarFile jarFile = new JarFile(jarPath);
Enumeration<JarEntry> entries = jarFile.entries();
while (entries.hasMoreElements()) {
JarEntry entry = entries.nextElement();
if (entry.getName().endsWith(".class")) {
InputStream stream = new BufferedInputStream(jarFile.getInputStream(entry), 1024);
ClassReader reader = new ClassReader(stream);
reader.accept(cv, 0);
stream.close();
}
}
}
public static void main(String[] args) {
try {
App app = new App();
app.findCallingMethodsInJar(args[0], args[1], args[2]);
for (Callee c : app.callees) {
System.out.println(c.source+":"+c.line+" "+c.className+" "+c.methodName+" "+c.methodDesc);
}
System.out.println("--\n"+app.callees.size()+" methods invoke "+
app.targetClass+" "+
app.targetMethod.getName()+" "+app.targetMethod.getDescriptor());
} catch(Exception x) {
x.printStackTrace();
}
}
}
Guys miklosar đã chỉnh sửa q và nói điều này cần phải xảy ra trong thời gian chạy, có vẻ như vô số người nói cách làm điều này trong một IDE. Bỏ phiếu @chadwick –
có lẽ bạn có thể giải thích lý do tại sao bạn cần làm điều này trong thời gian chạy vì mọi người có thể không gặp phải yêu cầu này. –