下面列出了java.lang.instrument.UnmodifiableClassException#java.lang.instrument.IllegalClassFormatException 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
@Override
protected byte[] transform(final String className,
final Class<?> classBeingRedefined,
final ProtectionDomain protectionDomain,
final byte[] classBytes) throws IllegalClassFormatException {
if (!Objects.equal(className, monitorClassName)) {
return null;
}
LOG.info("monitor class: {}", className);
Lock lock = classFileBuffer.getLock();
lock.lock();
try {
final ClassReader classReader = new ClassReader(classFileBuffer.getClassBuffer(classBeingRedefined, classBytes));
final ClassWriter classWriter = new ClassWriter(computeFlag(classReader));
final ClassVisitor classVisitor = new MonitorClassVisitor(new CheckClassAdapter(classWriter), methodName, methodDesc);
classReader.accept(classVisitor, ClassReader.EXPAND_FRAMES);
byte[] bytes = classWriter.toByteArray();
classFileBuffer.setClassBuffer(classBeingRedefined, bytes);
return bytes;
} finally {
lock.unlock();
}
}
/**
* Apply transformation on a given class byte definition.
* The method will always return a non-null byte array (if no transformation has taken place
* the array content will be identical to the original one).
* @param className the full qualified name of the class in dot format (i.e. some.package.SomeClass)
* @param internalName class name internal name in / format (i.e. some/package/SomeClass)
* @param bytes class byte definition
* @param pd protection domain to be used (can be null)
* @return (possibly transformed) class byte definition
*/
public byte[] transformIfNecessary(String className, String internalName, byte[] bytes, @Nullable ProtectionDomain pd) {
byte[] result = bytes;
for (ClassFileTransformer cft : this.transformers) {
try {
byte[] transformed = cft.transform(this.classLoader, internalName, null, pd, result);
if (transformed != null) {
result = transformed;
}
}
catch (IllegalClassFormatException ex) {
throw new IllegalStateException("Class file transformation failed", ex);
}
}
return result;
}
public byte[] transform(
ClassLoader classLoader, String className, Class<?> classBeingRedefined,
ProtectionDomain pd, byte[] bytes) throws IllegalClassFormatException {
// Check if this class should be instrumented.
if (!instrClassesTarget.contains(className)) {
return null;
}
boolean isRedefinition = classBeingRedefined != null;
log("instrument class(" + className + ") " + (isRedefinition ? "redef" : "load"));
ClassReader reader = new ClassReader(bytes);
ClassWriter writer = new ClassWriter(
reader, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
CallbackClassVisitor classVisitor = new CallbackClassVisitor(writer);
reader.accept(classVisitor, 0);
instrClassesDone.add(className);
return writer.toByteArray();
}
/**
* Apply transformation on a given class byte definition.
* The method will always return a non-null byte array (if no transformation has taken place
* the array content will be identical to the original one).
* @param className the full qualified name of the class in dot format (i.e. some.package.SomeClass)
* @param internalName class name internal name in / format (i.e. some/package/SomeClass)
* @param bytes class byte definition
* @param pd protection domain to be used (can be null)
* @return (possibly transformed) class byte definition
*/
public byte[] transformIfNecessary(String className, String internalName, byte[] bytes, @Nullable ProtectionDomain pd) {
byte[] result = bytes;
for (ClassFileTransformer cft : this.transformers) {
try {
byte[] transformed = cft.transform(this.classLoader, internalName, null, pd, result);
if (transformed != null) {
result = transformed;
}
}
catch (IllegalClassFormatException ex) {
throw new IllegalStateException("Class file transformation failed", ex);
}
}
return result;
}
@Override public byte[] transform(ClassLoader loader, String className,
Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] classfileBuffer)
throws IllegalClassFormatException {
if (className.contains("TypeAnnotatedTestClass")) {
try {
// Here we remove and re-add the dummy fields. This shuffles the constant pool
return asm(loader, className, classBeingRedefined, protectionDomain, classfileBuffer);
} catch (Throwable e) {
// The retransform native code that called this method does not propagate
// exceptions. Instead of getting an uninformative generic error, catch
// problems here and print it, then exit.
e.printStackTrace();
System.exit(1);
}
}
return null;
}
public JavaClassFile(ClassReader reader) throws IllegalClassFormatException {
int magic = reader.readInt32();
//第一位必须是 cafe babe
if (magic != 0xCAFEBABE){
throw new IllegalClassFormatException("is not a Java .class file");
}
this.minorVersion = reader.readUint16();
this.majorVersion = JavaVersion.valueOf(reader.readUint16());
this.constantPool = readConstantPool(reader);
this.accessFlags = readAccessFlags(reader);
this.thisClassIndex = reader.readUint16();
this.superClassIndex = reader.readUint16();
this.interfacesIndex = reader.readUint16s();
this.fields = readMembers(reader);
this.methods = readMembers(reader);
this.attributes = readAttributes(reader);
reader.close();
}
@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
if (probes.containsKey(className)) {
try {
ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS);
TimingVisitor visitor = new TimingVisitor(classWriter, probes.get(className));
ClassReader reader = new ClassReader(classfileBuffer);
reader.accept(visitor, 0);
return classWriter.toByteArray();
} catch (Throwable t) {
Logger.getLogger(getClass().getName()).log(Level.SEVERE,
"Failed to instrument " + probes.get(className), t);
return classfileBuffer;
}
} else {
// Use the byte code as is...
return null;
}
}
@Test
void testTransform() throws IOException, IllegalClassFormatException {
List<TransformDescriptor> probes = ExampleAgent.readProbes(null);
ExampleTransformer transformer = new ExampleTransformer(probes);
byte[] originalClass = TestUtils.getByteCode(TestProgram.class);
byte[] transformedClass = transformer.transform(TestProgram.class.getClassLoader(),
Type.getInternalName(TestProgram.class), TestProgram.class, null, originalClass);
assertNotNull(transformedClass);
assertNotEquals(originalClass, transformedClass);
StringWriter writer = new StringWriter();
TraceClassVisitor visitor = new TraceClassVisitor(new PrintWriter(writer));
CheckClassAdapter checkAdapter = new CheckClassAdapter(visitor);
ClassReader reader = new ClassReader(transformedClass);
reader.accept(checkAdapter, 0);
String decompiledTransformedClass = writer.getBuffer().toString();
// System.out.println(decompiledTransformedClass);
assertNotNull(decompiledTransformedClass);
}
@Override public byte[] transform(ClassLoader loader, String className,
Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] classfileBuffer)
throws IllegalClassFormatException {
if (className.contains("TypeAnnotatedTestClass")) {
try {
// Here we remove and re-add the dummy fields. This shuffles the constant pool
return asm(loader, className, classBeingRedefined, protectionDomain, classfileBuffer);
} catch (Throwable e) {
// The retransform native code that called this method does not propagate
// exceptions. Instead of getting an uninformative generic error, catch
// problems here and print it, then exit.
e.printStackTrace();
System.exit(1);
}
}
return null;
}
public byte[] transform(
ClassLoader classLoader, String className, Class<?> classBeingRedefined,
ProtectionDomain pd, byte[] bytes) throws IllegalClassFormatException {
// Check if this class should be instrumented.
if (!instrClassesTarget.contains(className)) {
return null;
}
boolean isRedefinition = classBeingRedefined != null;
log("instrument class(" + className + ") " + (isRedefinition ? "redef" : "load"));
ClassReader reader = new ClassReader(bytes);
ClassWriter writer = new ClassWriter(
reader, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
CallbackClassVisitor classVisitor = new CallbackClassVisitor(writer);
reader.accept(classVisitor, 0);
instrClassesDone.add(className);
return writer.toByteArray();
}
private byte[] handleKeySpec() throws IllegalClassFormatException {
try {
ClassPool cp = ClassPool.getDefault();
cp.importPackage("java.util.Arrays");
cp.importPackage("javax.xml.bind.DatatypeConverter");
int mod = Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL;
CtClass cc = cp.get(CN_KEY_SPEC.replace('/', '.'));
CtClass cb = cp.get("byte[]");
CtField cfOld = new CtField(cb, "__h_ok", cc);
CtField cfNew = new CtField(cb, "__h_nk", cc);
cfOld.setModifiers(mod);
cfNew.setModifiers(mod);
cc.addField(cfOld, "DatatypeConverter.parseBase64Binary(\"MIIBuDCCASwGByqGSM44BAEwggEfAoGBAP1/U4EddRIpUt9KnC7s5Of2EbdSPO9EAMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00b/JmYLdrmVClpJ+f6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E+4P208UewwI1VBNaFpEy9nXzrith1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmCouuEC/BYHPUCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoDgYUAAoGBAIvfweZvmGo5otwawI3no7Udanxal3hX2haw962KL/nHQrnC4FG2PvUFf34OecSK1KtHDPQoSQ+DHrfdf6vKUJphw0Kn3gXm4LS8VK/LrY7on/wh2iUobS2XlhuIqEc5mLAUu9Hd+1qxsQkQ50d0lzKrnDqPsM0WA9htkdJJw2nS\");");
cc.addField(cfNew, "DatatypeConverter.parseBase64Binary(\"MIIBuDCCASwGByqGSM44BAEwggEfAoGBAP1/U4EddRIpUt9KnC7s5Of2EbdSPO9EAMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00b/JmYLdrmVClpJ+f6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E+4P208UewwI1VBNaFpEy9nXzrith1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmCouuEC/BYHPUCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoDgYUAAoGBAO0DidNibJHhtgxAnM9NszURYU25CVLAlwFdOWhiUkjrjOY459ObRZDVd35hQmN/cCLkDox7y2InJE6PDWfbx9BsgPmPvH75yKgPs3B8pClQVkgIpJp08R59hoZabYuvm7mxCyDGTl2lbrOi0a3j4vM5OoCWKQjIEZ28OpjTyCr3\");");
CtConstructor cm = cc.getConstructor("([B)V");
cm.insertBeforeBody("if(Arrays.equals($1,__h_ok)){$1=__h_nk;System.out.println(\"============================== agent working ==============================\");}");
return cc.toBytecode();
} catch (Exception e) {
throw new IllegalClassFormatException(e.getMessage());
}
}
public static byte[] patchByteCode(ClassLoader l, String className, ProtectionDomain pd, byte[] arr) throws IllegalClassFormatException {
if (ACTIVE == null) {
return arr;
}
if (Boolean.TRUE.equals(IN.get())) {
return arr;
}
try {
IN.set(Boolean.TRUE);
for (NbInstrumentation inst : ACTIVE) {
for (ClassFileTransformer t : inst.transformers) {
arr = t.transform(l, className, null, pd, arr);
}
}
} finally {
IN.set(null);
}
return arr;
}
@Override
public byte[] transform(
ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] arr
) throws IllegalClassFormatException {
byte[] ret = arr;
for (int i = 0; i < arr.length - 4; i++) {
if (arr[i] == 'H' && arr[i + 1] == 'e' && arr[i + 2] == 'l' &&
arr[i + 3] == 'o'
) {
ret = ret.clone();
ret[i] = 'A';
ret[i + 1] = 'h';
ret[i + 2] = 'o';
ret[i + 3] = 'j';
}
}
return ret;
}
@Override
public byte[] transform(
ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] arr
) throws IllegalClassFormatException {
byte[] ret = arr;
for (int i = 0; i < arr.length - 4; i++) {
if (arr[i] == 'H' && arr[i + 1] == 'e' && arr[i + 2] == 'l' &&
arr[i + 3] == 'o'
) {
ret = ret.clone();
ret[i] = 'A';
ret[i + 1] = 'h';
ret[i + 2] = 'o';
ret[i + 3] = 'j';
}
}
return ret;
}
/**
* Apply transformation on a given class byte definition.
* The method will always return a non-null byte array (if no transformation has taken place
* the array content will be identical to the original one).
* @param className the full qualified name of the class in dot format (i.e. some.package.SomeClass)
* @param internalName class name internal name in / format (i.e. some/package/SomeClass)
* @param bytes class byte definition
* @param pd protection domain to be used (can be null)
* @return (possibly transformed) class byte definition
*/
public byte[] transformIfNecessary(String className, String internalName, byte[] bytes, ProtectionDomain pd) {
byte[] result = bytes;
for (ClassFileTransformer cft : this.transformers) {
try {
byte[] transformed = cft.transform(this.classLoader, internalName, null, pd, result);
if (transformed != null) {
result = transformed;
}
}
catch (IllegalClassFormatException ex) {
throw new IllegalStateException("Class file transformation failed", ex);
}
}
return result;
}
@Override
public byte[] transform(
ClassLoader loader,
String className,
Class<?> classBeingRedefined,
ProtectionDomain protectionDomain,
byte[] classfileBuffer) throws IllegalClassFormatException {
// The first design had the enhancer as a class variable. That approach had some goods and bads.
// We don't had to create an enhancer for each class, but on the other end it would stay in memory forever.
// It also assumed that all calls come from the same class loader, which is fair, but this makes it more robust.
try {
Enhancer enhancer = Environment.getBytecodeProvider().getEnhancer( new EnhancementContextWrapper( enhancementContext, loader ) );
return enhancer.enhance( className, classfileBuffer );
}
catch (final Exception e) {
throw new IllegalClassFormatException( "Error performing enhancement of " + className ) {
@Override
public synchronized Throwable getCause() {
return e;
}
};
}
}
@Override public byte[] transform(ClassLoader loader, String className,
Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] classfileBuffer)
throws IllegalClassFormatException {
if (className.contains("TypeAnnotatedTestClass")) {
try {
// Here we remove and re-add the dummy fields. This shuffles the constant pool
return asm(loader, className, classBeingRedefined, protectionDomain, classfileBuffer);
} catch (Throwable e) {
// The retransform native code that called this method does not propagate
// exceptions. Instead of getting an uninformative generic error, catch
// problems here and print it, then exit.
e.printStackTrace();
System.exit(1);
}
}
return null;
}
@Override public byte[] transform(ClassLoader loader, String className,
Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] classfileBuffer)
throws IllegalClassFormatException {
if (className.contains("TypeAnnotatedTestClass")) {
try {
// Here we remove and re-add the dummy fields. This shuffles the constant pool
return asm(loader, className, classBeingRedefined, protectionDomain, classfileBuffer);
} catch (Throwable e) {
// The retransform native code that called this method does not propagate
// exceptions. Instead of getting an uninformative generic error, catch
// problems here and print it, then exit.
e.printStackTrace();
System.exit(1);
}
}
return null;
}
@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
if (className == null) {
return classfileBuffer;
}
if (className.equals(ENCODED_KEY_SPEC)) {
return handleKeySpec(classfileBuffer);
}
return classfileBuffer;
}
public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined,
ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
transformCount++;
if (transformCount % 1000 == 0) System.out.println("transformCount:" + transformCount);
return null;
}
@Override
protected byte[] transform(final String className,
final Class<?> classBeingRedefined,
final ProtectionDomain protectionDomain,
final byte[] classBytes)
throws IllegalClassFormatException {
if (!Objects.equals(className, debugClassName)) {
return null;
}
LOG.info("debug class: {}", className);
Lock lock = classFileBuffer.getLock();
lock.lock();
try {
final ClassReader classReader = new ClassReader(classFileBuffer.getClassBuffer(classBeingRedefined, classBytes));
final ClassMetadata classMetadata = new ClassMetadata();
classReader.accept(new MetadataCollector(classMetadata), ClassReader.SKIP_FRAMES);
final ClassWriter classWriter = new ClassWriter(computeFlag(classReader));
final ClassVisitor classVisitor = new DebuggerClassVisitor(new CheckClassAdapter(classWriter), source, classMetadata);
classReader.accept(classVisitor, ClassReader.SKIP_FRAMES);
byte[] bytes = classWriter.toByteArray();
classFileBuffer.setClassBuffer(classBeingRedefined, bytes);
return bytes;
} finally {
lock.unlock();
}
}
@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
try {
return transform(className, classBeingRedefined, protectionDomain, classfileBuffer);
} catch (Throwable e) {
System.err.print("Class: ");
System.err.print(className);
System.err.print(", ClassLoader: ");
System.err.print(loader);
System.err.print(" transform failed.\n");
e.printStackTrace(System.err);
logger.error("", "transform failed", "Classs: {}, ClassLoader: {} transform failed.", className, loader, e);
return null;
}
}
public byte[] transform(ClassLoader loader, String name, Class<?> classBeingRedefined,
ProtectionDomain pd, byte[] buffer) throws IllegalClassFormatException {
log("SimpleTransformer called for: " + name + "@" + incrCounter(name));
if (!shouldTransform(name))
return null;
log("transforming: class name = " + name);
int nrOfReplacements = TransformUtil.replace(buffer, TransformUtil.BeforePattern,
TransformUtil.AfterPattern);
log("replaced the string, nrOfReplacements = " + nrOfReplacements);
return buffer;
}
public byte[] preProcess(String className, byte[] classBytes) {
try {
byte[] result = this.transformer.transform(this.loader, className, null, null, classBytes);
return (result != null ? result : classBytes);
}
catch (IllegalClassFormatException ex) {
throw new IllegalStateException("Cannot transform due to illegal class format", ex);
}
}
private byte[] applyTransformers(String name, byte[] bytes) {
String internalName = StringUtils.replace(name, ".", "/");
try {
for (ClassFileTransformer transformer : this.classFileTransformers) {
byte[] transformed = transformer.transform(this, internalName, null, null, bytes);
bytes = (transformed != null ? transformed : bytes);
}
return bytes;
}
catch (IllegalClassFormatException ex) {
throw new IllegalStateException(ex);
}
}
@Override
@Nullable
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
if (this.targetClassLoader != loader) {
return null;
}
return this.targetTransformer.transform(
loader, className, classBeingRedefined, protectionDomain, classfileBuffer);
}
@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
if (className.startsWith("org.aspectj") || className.startsWith("org/aspectj")) {
return classfileBuffer;
}
return this.delegate.transform(loader, className, classBeingRedefined, protectionDomain, classfileBuffer);
}
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
if (className == null || loader == null
|| loader.getClass().getName().equals("sun.reflect.DelegatingClassLoader")
|| loader.getClass().getName().equals("org.apache.catalina.loader.StandardClassLoader")
|| loader.getClass().getName().equals("javax.management.remote.rmi.NoCallStackClassLoader")
|| loader.getClass().getName().equals("com.alibaba.fastjson.util.ASMClassLoader")
|| className.indexOf("$Proxy") != -1
|| className.startsWith("java")
) {
return null;
}
if (!classPoolMap.containsKey(loader)) {
ClassPool classPool = new ClassPool();
classPool.insertClassPath(new LoaderClassPath(loader));
classPoolMap.put(loader, classPool);
}
ClassPool cp = classPoolMap.get(loader);
try {
className = className.replaceAll("/", ".");
CtClass cclass = cp.get(className);
for (Collect c : collects) {
if (c.isTarget(className, loader, cclass)) { // 仅限定只能转换一次.
byte[] bytes = c.transform(loader, className, classfileBuffer, cclass);
//File f = new File("/Users/tommy/git/bit-monitoring-agent/target/" + cclass.getSimpleName() + ".class");
//Files.write(f.toPath(), bytes);
System.out.println(String.format("%s bit APM agent insert success", className));
return bytes;
}
}
} catch (Throwable e) {
new Exception(String.format("%s bit APM agent insert fail", className), e).printStackTrace();
}
return new byte[0];
}
@Override
public byte[] transform(ClassLoader loader, String className,
Class<?> classBeingRedefined, ProtectionDomain protectionDomain,
byte[] classfileBuffer) throws IllegalClassFormatException {
// 屏蔽
String target = "javax.servlet.http.HttpServlet";
if (target.equals(className)) {
try {
return buildClass(target, loader);
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
@Override
public byte[] transform(ClassLoader loader, String className,
Class<?> classBeingRedefined, ProtectionDomain protectionDomain,
byte[] classfileBuffer) throws IllegalClassFormatException {
/* The Daemon Thread bug is timing dependent and you want the transform method
* to return ASAP - so just return the buffer will be fine
*/
return classfileBuffer;
}