mirror of
https://github.com/wassname/ray.git
synced 2026-06-29 18:10:13 +08:00
[JavaWorker] Java code lint check and binding to CI (#2225)
* add java code lint check and fix the java code lint error * add java doc lint check and fix the java doc lint error * add java code and doc lint to the CI
This commit is contained in:
committed by
Philipp Moritz
parent
5789a247f9
commit
3b5e700fd7
+75
-75
@@ -1,88 +1,88 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<parent>
|
||||
<groupId>org.ray.parent</groupId>
|
||||
<artifactId>ray-superpom</artifactId>
|
||||
<version>1.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<parent>
|
||||
<groupId>org.ray.parent</groupId>
|
||||
<artifactId>ray-superpom</artifactId>
|
||||
<version>1.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>org.ray</groupId>
|
||||
<artifactId>ray-hook</artifactId>
|
||||
<name>java api hook for ray</name>
|
||||
<description>java api hook for ray</description>
|
||||
<url></url>
|
||||
<groupId>org.ray</groupId>
|
||||
<artifactId>ray-hook</artifactId>
|
||||
<name>java api hook for ray</name>
|
||||
<description>java api hook for ray</description>
|
||||
<url></url>
|
||||
|
||||
<packaging>jar</packaging>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
<dependencies>
|
||||
|
||||
<!-- https://mvnrepository.com/artifact/org.ow2.asm/asm -->
|
||||
<dependency>
|
||||
<groupId>org.ow2.asm</groupId>
|
||||
<artifactId>asm</artifactId>
|
||||
<version>6.0</version>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/org.ow2.asm/asm -->
|
||||
<dependency>
|
||||
<groupId>org.ow2.asm</groupId>
|
||||
<artifactId>asm</artifactId>
|
||||
<version>6.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-codec</groupId>
|
||||
<artifactId>commons-codec</artifactId>
|
||||
<version>1.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-codec</groupId>
|
||||
<artifactId>commons-codec</artifactId>
|
||||
<version>1.4</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>2.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>2.5</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.ray</groupId>
|
||||
<artifactId>ray-common</artifactId>
|
||||
<version>1.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.ray</groupId>
|
||||
<artifactId>ray-common</artifactId>
|
||||
<version>1.0</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>2.5</version>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifestEntries>
|
||||
<Premain-Class>org.ray.hook.Agent</Premain-Class>
|
||||
<Can-Retransform-Classes>true</Can-Retransform-Classes>
|
||||
</manifestEntries>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>2.5</version>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifestEntries>
|
||||
<Premain-Class>org.ray.hook.Agent</Premain-Class>
|
||||
<Can-Retransform-Classes>true</Can-Retransform-Classes>
|
||||
</manifestEntries>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<relocations>
|
||||
<relocation>
|
||||
<pattern>org.objectweb.asm</pattern>
|
||||
<shadedPattern>agent.org.objectweb.asm</shadedPattern>
|
||||
</relocation>
|
||||
</relocations>
|
||||
<createDependencyReducedPom>false</createDependencyReducedPom>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<plugin>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<relocations>
|
||||
<relocation>
|
||||
<pattern>org.objectweb.asm</pattern>
|
||||
<shadedPattern>agent.org.objectweb.asm</shadedPattern>
|
||||
</relocation>
|
||||
</relocations>
|
||||
<createDependencyReducedPom>false</createDependencyReducedPom>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
||||
@@ -6,21 +6,10 @@ import org.objectweb.asm.ClassWriter;
|
||||
|
||||
public class ClassAdapter {
|
||||
|
||||
public static class Result {
|
||||
|
||||
public byte[] classBuffer;
|
||||
public Set<MethodId> changedMethods;
|
||||
}
|
||||
|
||||
public static Result hookClass(ClassLoader loader, String className, byte[] classfileBuffer) {
|
||||
// we have to comment out this quick filter as this is not accurate
|
||||
// e.g., org/ray/api/test/ActorTest$Adder.class is skipped!!!
|
||||
// even worse, this is non-deterministic...
|
||||
/*
|
||||
if (detectBody.contains("org/ray/hook/")) {
|
||||
return classfileBuffer;
|
||||
}
|
||||
*/
|
||||
|
||||
ClassReader reader = new ClassReader(classfileBuffer);
|
||||
ClassWriter writer = new ClassWriter(reader, 0);
|
||||
@@ -46,4 +35,10 @@ public class ClassAdapter {
|
||||
rr.classBuffer = result;
|
||||
return rr;
|
||||
}
|
||||
|
||||
public static class Result {
|
||||
|
||||
public byte[] classBuffer;
|
||||
public Set<MethodId> changedMethods;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,20 +11,16 @@ import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.Type;
|
||||
|
||||
/**
|
||||
* rewrite phase 1
|
||||
* rewrite phase 1.
|
||||
*/
|
||||
public class ClassDetectVisitor extends ClassVisitor {
|
||||
|
||||
static int count = 0;
|
||||
final String className;
|
||||
final Set<MethodId> rayMethods = new HashSet<>();
|
||||
boolean isActor = false;
|
||||
static int count = 0;
|
||||
int actorCalls = 0;
|
||||
final ClassLoader loader;
|
||||
|
||||
public int actorCalls() {
|
||||
return actorCalls;
|
||||
}
|
||||
boolean isActor = false;
|
||||
int actorCalls = 0;
|
||||
|
||||
public ClassDetectVisitor(ClassLoader loader, ClassVisitor origin, String className) {
|
||||
super(Opcodes.ASM6, origin);
|
||||
@@ -32,15 +28,12 @@ public class ClassDetectVisitor extends ClassVisitor {
|
||||
this.loader = loader;
|
||||
}
|
||||
|
||||
public Set<MethodId> detectedMethods() {
|
||||
return rayMethods;
|
||||
public int actorCalls() {
|
||||
return actorCalls;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInnerClass(String name, String outerName,
|
||||
String innerName, int access) {
|
||||
// System.err.println("visist inner class " + outerName + "$" + innerName);
|
||||
super.visitInnerClass(name, outerName, innerName, access);
|
||||
public Set<MethodId> detectedMethods() {
|
||||
return rayMethods;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -51,20 +44,16 @@ public class ClassDetectVisitor extends ClassVisitor {
|
||||
return super.visitAnnotation(desc, visible);
|
||||
}
|
||||
|
||||
private void visitRayMethod(int access, String name, String mdesc) {
|
||||
if (name.equals("<init>")) {
|
||||
return;
|
||||
}
|
||||
|
||||
MethodId m = new MethodId(className, name, mdesc, (access & Opcodes.ACC_STATIC) != 0, loader);
|
||||
rayMethods.add(m);
|
||||
//System.err.println("Visit " + m.toString());
|
||||
count++;
|
||||
@Override
|
||||
public void visitInnerClass(String name, String outerName,
|
||||
String innerName, int access) {
|
||||
// System.err.println("visist inner class " + outerName + "$" + innerName);
|
||||
super.visitInnerClass(name, outerName, innerName, access);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodVisitor visitMethod(int access, String name, String mdesc, String signature,
|
||||
String[] exceptions) {
|
||||
String[] exceptions) {
|
||||
//System.out.println("Visit " + className + "." + name);
|
||||
if (isActor && (access & Opcodes.ACC_PUBLIC) != 0) {
|
||||
visitRayMethod(access, name, mdesc);
|
||||
@@ -81,41 +70,9 @@ public class ClassDetectVisitor extends ClassVisitor {
|
||||
return super.visitAnnotation(adesc, visible);
|
||||
}
|
||||
|
||||
private boolean isValidCallParameterOrReturnType(Type t) {
|
||||
if (t.equals(Type.VOID_TYPE)) {
|
||||
return false;
|
||||
}
|
||||
if (t.equals(Type.BOOLEAN_TYPE)) {
|
||||
return false;
|
||||
}
|
||||
if (t.equals(Type.CHAR_TYPE)) {
|
||||
return false;
|
||||
}
|
||||
if (t.equals(Type.BYTE_TYPE)) {
|
||||
return false;
|
||||
}
|
||||
if (t.equals(Type.SHORT_TYPE)) {
|
||||
return false;
|
||||
}
|
||||
if (t.equals(Type.INT_TYPE)) {
|
||||
return false;
|
||||
}
|
||||
if (t.equals(Type.FLOAT_TYPE)) {
|
||||
return false;
|
||||
}
|
||||
if (t.equals(Type.LONG_TYPE)) {
|
||||
return false;
|
||||
}
|
||||
if (t.equals(Type.DOUBLE_TYPE)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
|
||||
Object... bsmArgs) {
|
||||
Object... bsmArgs) {
|
||||
|
||||
// fix all actor calls from InvokeVirtual to InvokeStatic
|
||||
if (desc.contains("org/ray/api/funcs/RayFunc_")) {
|
||||
@@ -151,7 +108,8 @@ public class ClassDetectVisitor extends ClassVisitor {
|
||||
dsptr,
|
||||
h.isInterface());
|
||||
bsmArgs[i] = newh;
|
||||
//System.err.println("Change ray.call from " + h + " -> " + newh + ", isInterface = " + h.isInterface());
|
||||
//System.err.println("Change ray.call from " + h + " -> " + newh + ", isInterface
|
||||
// = " + h.isInterface());
|
||||
++actorCalls;
|
||||
}
|
||||
}
|
||||
@@ -159,6 +117,49 @@ public class ClassDetectVisitor extends ClassVisitor {
|
||||
}
|
||||
super.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
|
||||
}
|
||||
|
||||
private boolean isValidCallParameterOrReturnType(Type t) {
|
||||
if (t.equals(Type.VOID_TYPE)) {
|
||||
return false;
|
||||
}
|
||||
if (t.equals(Type.BOOLEAN_TYPE)) {
|
||||
return false;
|
||||
}
|
||||
if (t.equals(Type.CHAR_TYPE)) {
|
||||
return false;
|
||||
}
|
||||
if (t.equals(Type.BYTE_TYPE)) {
|
||||
return false;
|
||||
}
|
||||
if (t.equals(Type.SHORT_TYPE)) {
|
||||
return false;
|
||||
}
|
||||
if (t.equals(Type.INT_TYPE)) {
|
||||
return false;
|
||||
}
|
||||
if (t.equals(Type.FLOAT_TYPE)) {
|
||||
return false;
|
||||
}
|
||||
if (t.equals(Type.LONG_TYPE)) {
|
||||
return false;
|
||||
}
|
||||
if (t.equals(Type.DOUBLE_TYPE)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void visitRayMethod(int access, String name, String mdesc) {
|
||||
if (name.equals("<init>")) {
|
||||
return;
|
||||
}
|
||||
|
||||
MethodId m = new MethodId(className, name, mdesc, (access & Opcodes.ACC_STATIC) != 0, loader);
|
||||
rayMethods.add(m);
|
||||
//System.err.println("Visit " + m.toString());
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,75 +7,33 @@ import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
|
||||
/**
|
||||
* rewrite phase 2
|
||||
* rewrite phase 2.
|
||||
*/
|
||||
public class ClassOverrideVisitor extends ClassVisitor {
|
||||
|
||||
final String className;
|
||||
final Set<MethodId> rayRemoteMethods;
|
||||
MethodVisitor ClinitVisitor;
|
||||
|
||||
// init the static added field in <clinit>
|
||||
// static {
|
||||
// assign value to _hashOf_XXX
|
||||
// }
|
||||
class StaticBlockVisitor extends MethodVisitor {
|
||||
|
||||
StaticBlockVisitor(MethodVisitor mv) {
|
||||
super(Opcodes.ASM6, mv);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitCode() {
|
||||
super.visitCode();
|
||||
|
||||
// assign value for added hash fields within <clinit>
|
||||
for (MethodId m : rayRemoteMethods) {
|
||||
byte[] hash = m.getSha1Hash();
|
||||
insertByteArray(hash);
|
||||
mv.visitFieldInsn(Opcodes.PUTSTATIC, className, m.getStaticHashValueFieldName(), "[B");
|
||||
|
||||
System.out.println("assign field: " + m.getStaticHashValueFieldName() + " = " + MethodId
|
||||
.toHexHashString(hash));
|
||||
}
|
||||
}
|
||||
|
||||
private void insertByteArray(byte[] bytes) {
|
||||
int length = bytes.length;
|
||||
assert (length < Short.MAX_VALUE);
|
||||
mv.visitIntInsn(Opcodes.SIPUSH, length);
|
||||
mv.visitIntInsn(Opcodes.NEWARRAY, Opcodes.T_BYTE);
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
for (int i = 0; i < length; ++i) {
|
||||
mv.visitIntInsn(Opcodes.BIPUSH, i);
|
||||
mv.visitIntInsn(Opcodes.BIPUSH, bytes[i]);
|
||||
mv.visitInsn(Opcodes.BASTORE);
|
||||
if (i < (length - 1)) {
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
MethodVisitor clinitVisitor;
|
||||
|
||||
public ClassOverrideVisitor(ClassVisitor origin, String className,
|
||||
Set<MethodId> rayRemoteMethods) {
|
||||
Set<MethodId> rayRemoteMethods) {
|
||||
super(Opcodes.ASM6, origin);
|
||||
this.className = className;
|
||||
this.rayRemoteMethods = rayRemoteMethods;
|
||||
this.ClinitVisitor = null;
|
||||
this.clinitVisitor = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodVisitor visitMethod(int access, String name, String desc, String signature,
|
||||
String[] exceptions) {
|
||||
if ("<clinit>".equals(name) && ClinitVisitor == null) {
|
||||
String[] exceptions) {
|
||||
if ("<clinit>".equals(name) && clinitVisitor == null) {
|
||||
MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
|
||||
ClinitVisitor = new StaticBlockVisitor(mv);
|
||||
return ClinitVisitor;// dispatch the ASM modifications (assign values to the preComputedxxx static field) to the ClinitVisitor
|
||||
clinitVisitor = new StaticBlockVisitor(mv);
|
||||
return clinitVisitor;// dispatch the ASM modifications (assign values to the preComputedxxx
|
||||
// static field) to the clinitVisitor
|
||||
}
|
||||
|
||||
ClassVisitor this_ = this;
|
||||
ClassVisitor current = this;
|
||||
MethodId m = new MethodId(className, name, desc, (access & Opcodes.ACC_STATIC) != 0, null);
|
||||
if (rayRemoteMethods.contains(m)) {
|
||||
if (m.isStaticMethod()) {
|
||||
@@ -86,10 +44,11 @@ public class ClassOverrideVisitor extends ClassVisitor {
|
||||
// step 1: add a field for the function id of this method
|
||||
System.out.println("add field: " + m.getStaticHashValueFieldName());
|
||||
String fieldName = m.getStaticHashValueFieldName();
|
||||
this_.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, fieldName, "[B",
|
||||
current.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, fieldName, "[B",
|
||||
null, null);
|
||||
|
||||
// step 2: rewrite current method so if MethodSwitcher returns true, returns the added function id directly
|
||||
// step 2: rewrite current method so if MethodSwitcher returns true, returns the
|
||||
// added function id directly
|
||||
// else call the original method
|
||||
mv.visitFieldInsn(Opcodes.GETSTATIC, className, fieldName, "[B");
|
||||
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "org/ray/hook/runtime/MethodSwitcher",
|
||||
@@ -103,10 +62,7 @@ public class ClassOverrideVisitor extends ClassVisitor {
|
||||
mv.visitCode();// real work
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// non-static
|
||||
else {
|
||||
} else { // non-static
|
||||
return super.visitMethod(access, name, desc, signature, exceptions);
|
||||
}
|
||||
} else {
|
||||
@@ -116,7 +72,7 @@ public class ClassOverrideVisitor extends ClassVisitor {
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
if (ClinitVisitor == null) { // works fine
|
||||
if (clinitVisitor == null) { // works fine
|
||||
// Create an empty static block and let our method
|
||||
// visitor modify it the same way it modifies an
|
||||
// existing static block
|
||||
@@ -163,14 +119,6 @@ public class ClassOverrideVisitor extends ClassVisitor {
|
||||
org.objectweb.asm.Type[] args = org.objectweb.asm.Type
|
||||
.getArgumentTypes(mid.getIdMethodDesc());
|
||||
int argCount = args.length;
|
||||
/*
|
||||
for (int i = 0; i < argCount; ++i) {
|
||||
String ldsptr = args[i].getDescriptor();
|
||||
if (!ldsptr.endsWith(";"))
|
||||
ldsptr = "L" + ldsptr + ";";
|
||||
mv.visitLocalVariable("arg" + i, ldsptr, null, l0, l2, i);
|
||||
}
|
||||
*/
|
||||
mv.visitMaxs(2, argCount);
|
||||
mv.visitEnd();
|
||||
}
|
||||
@@ -220,4 +168,47 @@ public class ClassOverrideVisitor extends ClassVisitor {
|
||||
return str.substring(left);
|
||||
}
|
||||
|
||||
// init the static added field in <clinit>
|
||||
// static {
|
||||
// assign value to _hashOf_XXX
|
||||
// }
|
||||
class StaticBlockVisitor extends MethodVisitor {
|
||||
|
||||
StaticBlockVisitor(MethodVisitor mv) {
|
||||
super(Opcodes.ASM6, mv);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitCode() {
|
||||
super.visitCode();
|
||||
|
||||
// assign value for added hash fields within <clinit>
|
||||
for (MethodId m : rayRemoteMethods) {
|
||||
byte[] hash = m.getSha1Hash();
|
||||
insertByteArray(hash);
|
||||
mv.visitFieldInsn(Opcodes.PUTSTATIC, className, m.getStaticHashValueFieldName(), "[B");
|
||||
|
||||
System.out.println("assign field: " + m.getStaticHashValueFieldName() + " = " + MethodId
|
||||
.toHexHashString(hash));
|
||||
}
|
||||
}
|
||||
|
||||
private void insertByteArray(byte[] bytes) {
|
||||
int length = bytes.length;
|
||||
assert (length < Short.MAX_VALUE);
|
||||
mv.visitIntInsn(Opcodes.SIPUSH, length);
|
||||
mv.visitIntInsn(Opcodes.NEWARRAY, Opcodes.T_BYTE);
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
for (int i = 0; i < length; ++i) {
|
||||
mv.visitIntInsn(Opcodes.BIPUSH, i);
|
||||
mv.visitIntInsn(Opcodes.BIPUSH, bytes[i]);
|
||||
mv.visitInsn(Opcodes.BASTORE);
|
||||
if (i < (length - 1)) {
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.reflect.Method;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Enumeration;
|
||||
@@ -26,7 +25,7 @@ import org.ray.hook.runtime.LoadedFunctions;
|
||||
import org.ray.util.logger.RayLog;
|
||||
|
||||
/**
|
||||
* rewrite jars to new jars with methods marked using Ray annotations
|
||||
* rewrite jars to new jars with methods marked using Ray annotations.
|
||||
*/
|
||||
public class JarRewriter {
|
||||
|
||||
@@ -51,10 +50,32 @@ public class JarRewriter {
|
||||
rewrite(args[0], args[1]);
|
||||
}
|
||||
|
||||
public static LoadedFunctions load(String dir, String baseDir)
|
||||
throws FileNotFoundException, SecurityException {
|
||||
List<String> functions = JarRewriter.getRewrittenFunctions(dir);
|
||||
LoadedFunctions efuncs = new LoadedFunctions();
|
||||
efuncs.loader = JarLoader.loadJars(dir, false);
|
||||
|
||||
for (String func : functions) {
|
||||
MethodId mid = new MethodId(func, efuncs.loader);
|
||||
efuncs.functions.add(mid);
|
||||
}
|
||||
|
||||
if (baseDir != null && !baseDir.equals("")) {
|
||||
List<String> baseFunctions = JarRewriter.getRewrittenFunctions(baseDir);
|
||||
for (String func : baseFunctions) {
|
||||
MethodId mid = new MethodId(func, efuncs.loader);
|
||||
efuncs.functions.add(mid);
|
||||
}
|
||||
}
|
||||
|
||||
return efuncs;
|
||||
}
|
||||
|
||||
public static void rewrite(String fromDir, String toDir) throws IOException, DataFormatException {
|
||||
File fromDirFile = new File(fromDir);
|
||||
File toDirFileTmp = new File(toDir + ".tmp");
|
||||
File toDirFile = new File(toDir);
|
||||
final File toDirFile = new File(toDir);
|
||||
|
||||
File[] topFiles = fromDirFile.listFiles();
|
||||
if (topFiles.length != 1 || !topFiles[0].isDirectory()) {
|
||||
@@ -103,57 +124,6 @@ public class JarRewriter {
|
||||
FileUtils.moveDirectory(toDirFileTmp, toDirFile);
|
||||
}
|
||||
|
||||
public static LoadedFunctions load(String dir, String baseDir)
|
||||
throws FileNotFoundException, SecurityException {
|
||||
List<String> functions = JarRewriter.getRewrittenFunctions(dir);
|
||||
LoadedFunctions efuncs = new LoadedFunctions();
|
||||
efuncs.loader = JarLoader.loadJars(dir, false);
|
||||
|
||||
for (String func : functions) {
|
||||
MethodId mid = new MethodId(func, efuncs.loader);
|
||||
efuncs.functions.add(mid);
|
||||
}
|
||||
|
||||
if (baseDir != null && !baseDir.equals("")) {
|
||||
List<String> baseFunctions = JarRewriter.getRewrittenFunctions(baseDir);
|
||||
for (String func : baseFunctions) {
|
||||
MethodId mid = new MethodId(func, efuncs.loader);
|
||||
efuncs.functions.add(mid);
|
||||
}
|
||||
}
|
||||
|
||||
return efuncs;
|
||||
}
|
||||
|
||||
public static LoadedFunctions loadBase(String baseDir)
|
||||
throws FileNotFoundException, SecurityException {
|
||||
List<String> functions = JarRewriter.getRewrittenFunctions(baseDir);
|
||||
LoadedFunctions efuncs = new LoadedFunctions();
|
||||
efuncs.loader = null;
|
||||
|
||||
for (String func : functions) {
|
||||
MethodId mid = new MethodId(func, efuncs.loader);
|
||||
efuncs.functions.add(mid);
|
||||
}
|
||||
|
||||
return efuncs;
|
||||
}
|
||||
|
||||
public static List<String> getRewrittenFunctions(String rewrittenDir)
|
||||
throws FileNotFoundException {
|
||||
ArrayList<String> functions = new ArrayList<>();
|
||||
Scanner s = new Scanner(new File(rewrittenDir + "/" + FUNCTIONS_FILE));
|
||||
while (s.hasNext()) {
|
||||
String f = s.next();
|
||||
if (!f.startsWith("(")) {
|
||||
functions.add(f);
|
||||
}
|
||||
}
|
||||
s.close();
|
||||
|
||||
return functions;
|
||||
}
|
||||
|
||||
public static void rewrite(JarFile from, String to, BiConsumer<ClassLoader, MethodId> consumer)
|
||||
throws IOException {
|
||||
|
||||
@@ -170,7 +140,8 @@ public class JarRewriter {
|
||||
if (!je.isDirectory() && je.getName().endsWith(".class")) {
|
||||
className = je.getName().substring(0, je.getName().length() - ".class".length());
|
||||
|
||||
//System.err.println("XXXXXX " + from.getName() + " :: " + je.getName() + " - " + className);
|
||||
//System.err.println("XXXXXX " + from.getName() + " :: " + je.getName() + " - " +
|
||||
// className);
|
||||
ClassAdapter.Result result = ClassAdapter.hookClass(null, className, jeBytes);
|
||||
if (result.classBuffer != jeBytes) {
|
||||
String logInfo = "Rewrite class " + className + " from " + jeBytes.length + " bytes to "
|
||||
@@ -198,4 +169,33 @@ public class JarRewriter {
|
||||
ojStream.close();
|
||||
ofStream.close();
|
||||
}
|
||||
|
||||
public static List<String> getRewrittenFunctions(String rewrittenDir)
|
||||
throws FileNotFoundException {
|
||||
ArrayList<String> functions = new ArrayList<>();
|
||||
Scanner s = new Scanner(new File(rewrittenDir + "/" + FUNCTIONS_FILE));
|
||||
while (s.hasNext()) {
|
||||
String f = s.next();
|
||||
if (!f.startsWith("(")) {
|
||||
functions.add(f);
|
||||
}
|
||||
}
|
||||
s.close();
|
||||
|
||||
return functions;
|
||||
}
|
||||
|
||||
public static LoadedFunctions loadBase(String baseDir)
|
||||
throws FileNotFoundException, SecurityException {
|
||||
List<String> functions = JarRewriter.getRewrittenFunctions(baseDir);
|
||||
LoadedFunctions efuncs = new LoadedFunctions();
|
||||
efuncs.loader = null;
|
||||
|
||||
for (String func : functions) {
|
||||
MethodId mid = new MethodId(func, efuncs.loader);
|
||||
efuncs.functions.add(mid);
|
||||
}
|
||||
|
||||
return efuncs;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,27 +11,26 @@ import org.objectweb.asm.Type;
|
||||
import org.ray.util.logger.RayLog;
|
||||
|
||||
/**
|
||||
* Represent a Method in a Class
|
||||
* Represent a Method in a Class.
|
||||
*/
|
||||
public class MethodId {
|
||||
|
||||
static final String getFunctionIdPostfix = "_function_id";
|
||||
String className;
|
||||
String methodName;
|
||||
String methodDesc;
|
||||
boolean isStatic;
|
||||
ClassLoader loader;
|
||||
|
||||
static final String getFunctionIdPostfix = "_function_id";
|
||||
|
||||
public MethodId(String cls, String method, String mdesc, boolean isstatic, ClassLoader loader_) {
|
||||
public MethodId(String cls, String method, String mdesc, boolean isstatic, ClassLoader loader) {
|
||||
className = cls;
|
||||
methodName = method;
|
||||
methodDesc = mdesc;
|
||||
isStatic = isstatic;
|
||||
loader = loader_;
|
||||
this.loader = loader;
|
||||
}
|
||||
|
||||
public MethodId(String encodedString, ClassLoader loader_) {
|
||||
public MethodId(String encodedString, ClassLoader loader) {
|
||||
// className + "." + methodName + "::" + methodDesc + "&&" + isStatic;
|
||||
int lastPos3 = encodedString.lastIndexOf("&&");
|
||||
int lastPos2 = encodedString.lastIndexOf("::");
|
||||
@@ -45,7 +44,24 @@ public class MethodId {
|
||||
methodName = encodedString.substring(lastPos1 + ".".length(), lastPos2);
|
||||
methodDesc = encodedString.substring(lastPos2 + "::".length(), lastPos3);
|
||||
isStatic = Boolean.parseBoolean(encodedString.substring(lastPos3 + "&&".length()));
|
||||
loader = loader_;
|
||||
this.loader = loader;
|
||||
}
|
||||
|
||||
public static String toHexHashString(byte[] id) {
|
||||
String s = "";
|
||||
String hex = "0123456789abcdef";
|
||||
assert (id.length == 20);
|
||||
for (int i = 0; i < 20; i++) {
|
||||
int val = id[i] & 0xff;
|
||||
s += hex.charAt(val >> 4);
|
||||
s += hex.charAt(val & 0xf);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
private String toHexHashString() {
|
||||
byte[] id = this.getSha1Hash();
|
||||
return toHexHashString(id);
|
||||
}
|
||||
|
||||
public String getClassName() {
|
||||
@@ -76,23 +92,6 @@ public class MethodId {
|
||||
return "(L" + this.className + ";" + this.methodDesc.substring(1);
|
||||
}
|
||||
|
||||
public static String toHexHashString(byte[] id) {
|
||||
String s = "";
|
||||
String hex = "0123456789abcdef";
|
||||
assert (id.length == 20);
|
||||
for (int i = 0; i < 20; i++) {
|
||||
int val = id[i] & 0xff;
|
||||
s += hex.charAt(val >> 4);
|
||||
s += hex.charAt(val & 0xf);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
private String toHexHashString() {
|
||||
byte[] id = this.getSha1Hash();
|
||||
return toHexHashString(id);
|
||||
}
|
||||
|
||||
public Method load() {
|
||||
String loadClsName = className.replace('/', '.');
|
||||
Class<?> cls;
|
||||
@@ -153,7 +152,8 @@ public class MethodId {
|
||||
: "<nil>") + " vs id-hash: " + toHexHashString());
|
||||
}
|
||||
}
|
||||
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
|
||||
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException
|
||||
| IllegalAccessException e) {
|
||||
RayLog.core.error("load method hash field failed for " + toString(), e);
|
||||
}
|
||||
return m;
|
||||
|
||||
@@ -17,13 +17,13 @@ import org.apache.commons.io.filefilter.RegexFileFilter;
|
||||
import org.ray.util.logger.RayLog;
|
||||
|
||||
/**
|
||||
* load and unload jars from a dir
|
||||
* load and unload jars from a dir.
|
||||
*/
|
||||
public class JarLoader {
|
||||
|
||||
private static Method AddUrl = InitAddUrl();
|
||||
private static Method AddUrl = initAddUrl();
|
||||
|
||||
private static Method InitAddUrl() {
|
||||
private static Method initAddUrl() {
|
||||
try {
|
||||
Method m = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
|
||||
m.setAccessible(true);
|
||||
@@ -59,10 +59,6 @@ public class JarLoader {
|
||||
return loadJar(jars, explicitLoadForHook);
|
||||
}
|
||||
|
||||
public static void unloadJars(ClassLoader loader) {
|
||||
// TODO:
|
||||
}
|
||||
|
||||
private static URLClassLoader loadJar(Collection<File> appJars, boolean explicitLoadForHook) {
|
||||
List<JarFile> jars = new ArrayList<>();
|
||||
List<URL> urls = new ArrayList<>();
|
||||
@@ -128,4 +124,8 @@ public class JarLoader {
|
||||
|
||||
jars.addAll(files);
|
||||
}
|
||||
|
||||
public static void unloadJars(ClassLoader loader) {
|
||||
// TODO:
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,6 @@ import org.ray.hook.MethodId;
|
||||
|
||||
public class LoadedFunctions {
|
||||
|
||||
public ClassLoader loader = null;
|
||||
public final Set<MethodId> functions = Collections.synchronizedSet(new HashSet<>());
|
||||
public ClassLoader loader = null;
|
||||
}
|
||||
|
||||
@@ -10,15 +10,15 @@ public class MethodHash {
|
||||
this.hash = hash;
|
||||
}
|
||||
|
||||
public byte[] getHash() {
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Arrays.hashCode(getHash());
|
||||
}
|
||||
|
||||
public byte[] getHash() {
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package org.ray.hook.runtime;
|
||||
|
||||
/**
|
||||
* method mode switch at runtime
|
||||
* method mode switch at runtime.
|
||||
*/
|
||||
public class MethodSwitcher {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user