下面列出了怎么用org.objectweb.asm.util.CheckClassAdapter的API类实例代码及写法,或者点击链接到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();
}
}
/**
* See {@link org.objectweb.asm.util.CheckClassAdapter#CheckClassAdapter(ClassVisitor, boolean)}.
* @param api the api version
*/
protected DrillCheckClassAdapter(final int api, final ClassVisitor cv,
final boolean checkDataFlow) {
super(api);
/*
* We set up a chain of class visitors:
* this -> InnerAccessStripper -> CheckClassAdapter -> AccessRestorer -> cv
* Note the AccessRestorer references accessStripper to get the original
* access bits; the inner class could not be constructed before the call to
* super(), hence the need to set the delegate after that.
*/
accessStripper = new InnerClassAccessStripper(api, new CheckClassAdapter(
new AccessRestorer(api, cv), checkDataFlow));
setDelegate(accessStripper);
}
public static byte[] writeClass(ClassGroup group, ClassFile cf)
{
ClassWriter writer;
if (Deob.rsc) {
writer = new NonloadingClassWriter(group, ClassWriter.COMPUTE_MAXS);
}
else {
writer = new NonloadingClassWriter(group, ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
}
CheckClassAdapter cca = new CheckClassAdapter(writer, false);
cf.accept(cca);
byte[] data = writer.toByteArray();
if (!Deob.rsc)
validateDataFlow(cf.getName(), data);
return data;
}
@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);
}
private byte[] classNodeToBytes(ClassNode classNode) {
ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS);
classNode.accept(writer);
byte[] bytes = writer.toByteArray();
// verify bytecode
if (verifyAndPrint) {
ClassReader reader = new ClassReader(bytes);
ClassVisitor tracer = new TraceClassVisitor(new PrintWriter(System.out));
ClassVisitor checker = new CheckClassAdapter(tracer, true);
reader.accept(checker, 0);
}
return bytes;
}
/**
* Reads class as resource, instruments it (applies {@link Strategy}'s transformer at first,
* then {@link Runner}'s) and returns the resulting byte-code.
*
* @param className name of the class to be transformed.
* @return the byte-code of the transformed class.
* @throws IOException if class could not be read as a resource.
*/
private byte[] instrument(String className) throws IOException {
// Create ClassReader
ClassReader cr = new ClassReader(className);
// Build class info
ClassInfoVisitor ciVisitor = new ClassInfoVisitor();
cr.accept(ciVisitor, 0);
ClassInfo ci = ciVisitor.buildClassInfo();
// Construct transformation pipeline:
// apply the strategy's transformer at first,
// then the runner's one.
ClassWriter cw = new FrameClassWriter(this, ciCache, ci.getVersion());
ClassVisitor cv = new CheckClassAdapter(cw, false); // for debug
if (runner.needsTransformation()) {
cv = runner.createTransformer(cv, ci);
}
if (strategy.needsTransformation()) {
cv = strategy.createTransformer(cv, ci);
}
// Get transformed bytecode
cr.accept(cv, ClassReader.EXPAND_FRAMES);
return cw.toByteArray();
}
public String dumpVerify(byte[] bytecode, ClassLoader classLoader) {
if (bytecode == null) {
throw new NullPointerException("bytecode");
}
if (classLoader == null) {
throw new NullPointerException("classLoader");
}
final StringWriter out = new StringWriter();
final PrintWriter writer = new PrintWriter(out);
final ClassReader cr = new ClassReader(bytecode);
CheckClassAdapter.verify(cr, classLoader, true, writer);
return out.toString();
}
/**
* Weave tracking method call if the annotations present.
*/
private static void weaveIfNecessary(ClassReader classReader, File dest) throws IOException {
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
ModifierClassWriter mcw = new ModifierClassWriter(Opcodes.ASM5, cw);
classReader.accept(new CheckClassAdapter(mcw), ClassReader.EXPAND_FRAMES);
if (!mcw.isProceed()) {
return;
}
OutputStream out = null;
try {
out = new FileOutputStream(dest);
out.write(cw.toByteArray());
out.flush();
} finally {
closeQuietly(out);
}
}
@SuppressWarnings("unchecked")
public Class<T> generate() {
ClassWriter out = new ClassWriter(ClassWriter.COMPUTE_MAXS);
CheckClassAdapter writer = new CheckClassAdapter(out);
int offset = 0;
declareClass(writer);
declareConstructor(writer);
for (Method getter : inspector.getters) {
offset = declareField(getter, writer, offset);
}
writer.visitEnd();
return (Class<T>) new GeneratedClassLoader(options).defineClass(implementationName, out);
}
private void declareConstructor(CheckClassAdapter writer) {
MethodVisitor method = writer.visitMethod(ACC_PUBLIC, "<init>", GENERATED_CONSTRUCTOR, null, null);
method.visitCode();
method.visitVarInsn(ALOAD, 0);
method.visitVarInsn(ILOAD, 1);
method.visitLdcInsn(inspector.getSizeInBytes());
method.visitVarInsn(ALOAD, 2);
method.visitVarInsn(ALOAD, 3);
method.visitMethodInsn(INVOKESPECIAL,
classExtended,
"<init>",
constructorExtended);
method.visitInsn(RETURN);
method.visitMaxs(5, 5);
method.visitEnd();
}
@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();
}
}
/**
* 主方法
*/
public static void main(String[] args) throws Exception {
try {
final String source = "/Users/leix.xie/workspace/opensource/bistoury/bistoury-instrument-client/target/test-classes/qunar/tc/test/Test.class";
final ClassReader classReader = new ClassReader(new FileInputStream(source));
final ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
final ClassVisitor classVisitor = new ASMTest(new CheckClassAdapter(classWriter), source);
classReader.accept(classVisitor, ClassReader.EXPAND_FRAMES);
byte[] bytes = classWriter.toByteArray();
print(bytes);
} catch (Throwable t) {
t.printStackTrace();
}
//startReport();
}
/**
* See {@link org.objectweb.asm.util.CheckClassAdapter#verify(ClassReader, boolean, PrintWriter)}.
*/
public static void verify(final ClassReader cr, final boolean dump,
final PrintWriter pw) {
/*
* For plain verification, we don't need to restore the original access
* bytes the way we do when the check adapter is used as part of a chain, so
* we can just strip it and use the ASM version directly.
*/
final ClassWriter classWriter = new ClassWriter(0);
cr.accept(new InnerClassAccessStripper(CompilationConfig.ASM_API_VERSION,
classWriter), ClassReader.SKIP_DEBUG);
final ClassReader strippedCr = new ClassReader(classWriter.toByteArray());
CheckClassAdapter.verify(strippedCr, dump, pw);
}
private static void validateDataFlow(String name, byte[] data)
{
try
{
ClassReader cr = new ClassReader(data);
ClassWriter cw = new ClassWriter(cr, 0);
ClassVisitor cv = new CheckClassAdapter(cw, true);
cr.accept(cv, 0);
}
catch (Exception ex)
{
}
}
public void analyze(OutputStream out) {
for (Map.Entry<String, byte[]> e : classBytes.entrySet()) {
ClassReader reader = new ClassReader(e.getValue());
ClassVisitor visitor = new CheckClassAdapter(new TraceClassVisitor(new PrintWriter(out, true)));
reader.accept(visitor, 0);
}
}
private static byte[] generateClass(String internalClassName, Type testClassType, int iThread, List<Actor> actors,
List<Object> objArgs, boolean waitsEnabled)
{
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
CheckClassAdapter cca = new CheckClassAdapter(cw, false);
cca.visit(52, ACC_PUBLIC + ACC_SUPER, internalClassName, null, TEST_THREAD_EXECUTION_TYPE.getInternalName(), null);
generateConstructor(cca);
generateRun(cca, testClassType, iThread, actors, objArgs, waitsEnabled);
cca.visitEnd();
return cw.toByteArray();
}
private byte[] assertValidClass(final Class<?> clazz)
throws IllegalClassFormatException {
final byte[] bs = transform(clazz);
// printClass(bs);
final StringWriter sw = new StringWriter();
CheckClassAdapter.verify(new ClassReader(bs), false, new PrintWriter(sw));
assertTrue(sw.toString(), sw.toString().length() == 0);
return bs;
}
@Override
public void postApply(ITargetClassContext context) {
try {
context.getClassNode().accept(new CheckClassAdapter(new MixinClassWriter(ClassWriter.COMPUTE_FRAMES)));
} catch (RuntimeException ex) {
throw new ValidationFailedException(ex.getMessage(), ex);
}
}
private void verifyMutant(final Mutant mutant) {
// printMutant(mutant);
final StringWriter sw = new StringWriter();
final PrintWriter pw = new PrintWriter(sw);
CheckClassAdapter.verify(new ClassReader(mutant.getBytes()), false, pw);
assertTrue(sw.toString(), sw.toString().length() == 0);
}
private void assertValidClass(final Class<?> clazz)
throws IllegalClassFormatException {
final byte[] bs = transform(clazz);
// printClass(bs);
final StringWriter sw = new StringWriter();
CheckClassAdapter.verify(new ClassReader(bs), false, new PrintWriter(sw));
assertTrue(sw.toString(), sw.toString().length() == 0);
}
public ClassVisitor wrap(TypeDescription instrumentedType,
ClassVisitor classVisitor,
Implementation.Context implementationContext,
TypePool typePool,
FieldList<FieldDescription.InDefinedShape> fields,
MethodList<?> methods,
int writerFlags,
int readerFlags) {
return check
? new CheckClassAdapter(new TraceClassVisitor(classVisitor, printer, printWriter))
: new TraceClassVisitor(classVisitor, printer, printWriter);
}
@SuppressWarnings("unchecked")
public <T extends TypeEntry> void emitOuterType(T ast) {
ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
this.cw = writer;
if (VERIFY_EMITTED_BYTECODE) {
this.cw = new CheckClassAdapter(this.cw);
}
AstEmitter<AbstractEmitterContext, T> emitter = (AstEmitter<AbstractEmitterContext, T>) this.set.getAstEmitter(ast.getClass());
if (emitter == null) {
throw new IllegalArgumentException("No emitter for ast entry " + ast.getClass().getName());
}
emitter.emit(this, ast);
this.cw.visitEnd();
byte[] clazz = writer.toByteArray();
if (DUMP_INSTRUCTIONS_AFTER_WRITE) {
ClassReader cr = new ClassReader(clazz);
ClassNode cn = new ClassNode();
cr.accept(cn, 0);
List<MethodNode> methods = cn.methods;
for (MethodNode mn : methods) {
System.out.println("Method: " + mn.name + mn.desc);
Printer printer = new Textifier();
TraceMethodVisitor mp = new TraceMethodVisitor(printer);
for (Iterator<AbstractInsnNode> it = mn.instructions.iterator(); it.hasNext();) {
AbstractInsnNode insn = it.next();
insn.accept(mp);
}
StringWriter sw = new StringWriter();
printer.print(new PrintWriter(sw));
String s = sw.toString();
if (s.endsWith("\n")) {
s = s.substring(0, s.length() - 1);
}
System.out.println(s);
mn.instructions.accept(mp);
}
}
try {
this.out.write(clazz);
} catch (IOException e) {
Throwables.propagate(e);
}
}
protected void instrumentWorkflows(File adaptedTargetDir, Map<String, Clazz> clazzMap, Map<String, ClassInfo> classInfos, ClassLoader tmpClassLoader) throws IOException {
logger.info("Instrumenting classfiles");
for (Clazz clazz : clazzMap.values()) {
byte[] bytes;
InputStream is = clazz.classfile.openStream();
try {
ClassReader cr2 = new ClassReader(is);
ClassNode cn = new ClassNode();
cr2.accept(cn, flags);
traceClassNode(clazz.classname + " - original", cn);
// Now content of ClassNode can be modified and then serialized back into bytecode:
new TryCatchBlockHandler().instrument(cn);
ClassWriter cw2 = new ClassWriter(0);
cn.accept(cw2);
bytes = cw2.toByteArray();
traceBytes(clazz.classname + " - after TryCatchBlockHandler", bytes);
ClassReader cr = new ClassReader(bytes);
ClassWriter cw = new ClassWriter(0);
ScottyClassAdapter cv = new ScottyClassAdapter(cw, clazz.aggregatedInterruptableMethods);
cr.accept(cv, flags);
classInfos.put(clazz.classname, cv.getClassInfo());
bytes = cw.toByteArray();
traceBytes(clazz.classname + " - after ScottyClassAdapter", bytes);
// Recompute frames, etc.
ClassReader cr3 = new ClassReader(bytes);
ClassWriter cw3 = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
cr3.accept(cw3, ClassReader.SKIP_FRAMES);
bytes = cw3.toByteArray();
traceBytes(clazz.classname + " - after COMPUTE_FRAMES", bytes);
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
CheckClassAdapter.verify(new ClassReader(cw.toByteArray()), tmpClassLoader, false, pw);
if (sw.toString().length() != 0) {
logger.error("CheckClassAdapter.verify failed for class " + cn.name + ":\n" + sw.toString());
} else {
logger.info("CheckClassAdapter.verify succeeded for class " + cn.name);
}
} finally {
is.close();
}
File adaptedClassfileName = new File(adaptedTargetDir, clazz.classname + ".class");
adaptedClassfileName.getParentFile().mkdirs();
FileOutputStream fos = new FileOutputStream(adaptedClassfileName);
try {
fos.write(bytes);
} finally {
fos.close();
}
}
}
/**
* Dumps the output of CheckClassAdapter.verify to System.out
*
* @param bytes the bytecode of the class to check
*/
public static void dumpClass(byte[] bytes) {
ClassReader cr = new ClassReader(bytes);
CheckClassAdapter.verify(cr, true, new PrintWriter(System.out));
}