下面列出了org.objectweb.asm.tree.ClassNode#accept ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
/**
* Check to see if a class is well-formed.
*
* @param logger the logger to write to if a problem is found
* @param logTag a tag to print to the log if a problem is found
* @param classNode the class to check
* @return true if the class is ok, false otherwise
*/
public static boolean isClassOk(final Logger logger, final String logTag, final ClassNode classNode) {
final StringWriter sw = new StringWriter();
final ClassWriter verifyWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
classNode.accept(verifyWriter);
final ClassReader ver = new ClassReader(verifyWriter.toByteArray());
try {
DrillCheckClassAdapter.verify(ver, false, new PrintWriter(sw));
} catch(final Exception e) {
logger.info("Caught exception verifying class:");
logClass(logger, logTag, classNode);
throw e;
}
final String output = sw.toString();
if (!output.isEmpty()) {
logger.info("Invalid class:\n" + output);
return false;
}
return true;
}
/**
* Saves a jar without the manifest
*
* @param nodeList The loaded ClassNodes
* @param path the exact jar output path
*/
public static void saveAsJarClassesOnly(ArrayList<ClassNode> nodeList, String path) {
try {
JarOutputStream out = new JarOutputStream(new FileOutputStream(path));
ArrayList<String> noDupe = new ArrayList<String>();
for (ClassNode cn : nodeList) {
ClassWriter cw = new ClassWriter(0);
cn.accept(cw);
String name = cn.name + ".class";
if (!noDupe.contains(name)) {
noDupe.add(name);
out.putNextEntry(new ZipEntry(name));
out.write(cw.toByteArray());
out.closeEntry();
}
}
noDupe.clear();
out.close();
} catch (IOException e) {
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
}
}
/**
* Not called for built-in types
* @param type the type to generate
* @return the bytecode for that type
*/
byte[] createJCas_TypeCoverClass(TypeImpl type) {
this.type = type;
typeJavaDescriptor = type.getJavaDescriptor();
typeJavaClassName = type.getName().replace('.', '/') + "_Type";
cn = new ClassNode(ASM5); // java 8
cn.version = JAVA_CLASS_VERSION;
cn.access = ACC_PUBLIC + ACC_SUPER;
cn.name = typeJavaClassName;
cn.superName = type.getSuperType().getName().replace('.', '/') + "_Type";
// TODO
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
cn.accept(cw);
return cw.toByteArray();
}
/**
* Given a map of ClassNodes and mappings, returns a map of class names to
* class bytes.
*
* @param nodes
* @param mappings
* @return
*/
public static Map<String, byte[]> process(Map<String, ClassNode> nodes, Map<String, MappedClass> mappings, boolean useMaxs) {
Map<String, byte[]> out = new HashMap<String, byte[]>();
SkidRemapper mapper = new SkidRemapper(mappings);
try {
for (ClassNode cn : nodes.values()) {
ClassWriter cw = new MappingClassWriter(mappings, useMaxs ? ClassWriter.COMPUTE_MAXS : ClassWriter.COMPUTE_FRAMES);
ClassVisitor remapper = new ClassRemapper(cw, mapper);
cn.accept(remapper);
out.put(mappings.containsKey(cn.name) ? mappings.get(cn.name).getNewName() : cn.name, cw.toByteArray());
}
} catch (Exception e) {
e.printStackTrace();
}
return out;
}
@Override
public void process(FabricLauncher launcher, Consumer<ClassNode> classEmitter) {
if (classExists(launcher, TO)
&& !classExists(launcher, "cpw.mods.fml.relauncher.FMLRelauncher")) {
if (!(launcher instanceof Knot)) {
throw new RuntimeException("1.2.5 FML patch only supported on Knot!");
}
debug("Detected 1.2.5 FML - Knotifying ModClassLoader...");
try {
ClassNode patchedClassLoader = loadClass(launcher, FROM);
ClassNode remappedClassLoader = new ClassNode();
patchedClassLoader.accept(new ClassRemapper(remappedClassLoader, new Remapper() {
@Override
public String map(String internalName) {
return FROM_INTERNAL.equals(internalName) ? TO_INTERNAL : internalName;
}
}));
classEmitter.accept(remappedClassLoader);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) {
if (!classesToRedefine.contains(classBeingRedefined))
return classfileBuffer;
ClassWriter writer;
try {
ClassReader reader = new ClassReader(classfileBuffer);
ClassNode node = new ClassNode(Opcodes.ASM5);
reader.accept(node, 0);
this.agentJobs.stream()
.filter(job -> job.getToTransform().getName().replace('.', '/').equals(className))
.forEach(job -> job.apply(node));
writer = new FixedClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES, loader);
node.accept(writer);
} catch (Throwable e) {
e.printStackTrace();
throw new RuntimeException(e);
}
return writer.toByteArray();
}
@Override
public byte[] transform(String name, String transformedName, byte[] bytes) {
if (bytes == null) return null;
Collection<ITransformer> transformers = transformerMap.get(transformedName);
if (transformers.isEmpty()) return bytes;
logger.info("Found {} transformers for {}", transformers.size(), transformedName);
ClassReader reader = new ClassReader(bytes);
ClassNode node = new ClassNode();
reader.accept(node, ClassReader.EXPAND_FRAMES);
MutableInt classWriterFlags = new MutableInt(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
transformers.forEach(transformer -> {
logger.info("Applying transformer {} on {}...", transformer.getClass().getName(), transformedName);
transformer.transform(node, transformedName);
if (transformer instanceof FontRendererTransformer) {
classWriterFlags.setValue(0);
}
});
ClassWriter writer = new ClassWriter(classWriterFlags.getValue());
try {
node.accept(writer);
} catch (Throwable t) {
logger.error("Exception when transforming " + transformedName + " : " + t.getClass().getSimpleName());
t.printStackTrace();
outputBytecode(transformedName, writer);
return bytes;
}
outputBytecode(transformedName, writer);
return writer.toByteArray();
}
private static Map<String, byte[]> toByteCode(List<ClassNode> classes) {
Map<String, byte[]> out = new LinkedHashMap<>();
for (ClassNode n : classes) {
ClassWriter cw = new ClassWriter(0);
n.accept(cw);
out.put(n.name, cw.toByteArray());
}
return out;
}
public static ClassWriter accept(ClassNode cn) {
ClassWriter cw = new ClassWriter(0);
try {
cn.accept(cw);
} catch (Exception e) {
e.printStackTrace();
try {
Thread.sleep(200);
cn.accept(cw);
} catch (InterruptedException e1) {
}
}
return cw;
}
/**
* Saves a jar without the manifest
*
* @param nodeList The loaded ClassNodes
* @param path the exact jar output path
*/
public static void saveAsJar(ArrayList<ClassNode> nodeList, String path) {
try {
JarOutputStream out = new JarOutputStream(new FileOutputStream(path));
ArrayList<String> noDupe = new ArrayList<String>();
for (ClassNode cn : nodeList) {
ClassWriter cw = new ClassWriter(0);
cn.accept(cw);
String name = cn.name + ".class";
if (!noDupe.contains(name)) {
noDupe.add(name);
out.putNextEntry(new ZipEntry(name));
out.write(cw.toByteArray());
out.closeEntry();
}
}
for (FileContainer container : BytecodeViewer.files)
for (Entry<String, byte[]> entry : container.files.entrySet()) {
String filename = entry.getKey();
if (!filename.startsWith("META-INF")) {
if (!noDupe.contains(filename)) {
noDupe.add(filename);
out.putNextEntry(new ZipEntry(filename));
out.write(entry.getValue());
out.closeEntry();
}
}
}
noDupe.clear();
out.close();
} catch (IOException e) {
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
}
}
protected String decompile(ClassNode cn, MethodNode mn) {
if (last != null && cn.equals(last)
&& ((lastMn == null && mn == null) || (mn != null && lastMn != null && mn.equals(lastMn)))) {
// same node, same output
return lastOutput;
}
last = cn;
lastMn = mn;
// do not regenerate anything here
ClassWriter cw = new ClassWriter(0);
cn.accept(cw);
return decompile(cw.toByteArray(), mn);
}
private static void traceClassNode(String message, ClassNode cn) {
if (logger.isTraceEnabled()) {
ClassWriter cw = new ClassWriter(0);
cn.accept(cw);
traceBytes(message, cw.toByteArray());
}
}
public Map<String, byte[]> getGeneratedClasses() {
Map<String, byte[]> result = new HashMap<String, byte[]>();
for (ClassNode classNode : newClasses) {
ClassWriter cw = new ComputeClassWriter(ClassWriter.COMPUTE_FRAMES, resourceLoader);
classNode.accept(cw);
result.put(classNode.name, cw.toByteArray());
}
return result;
}
private static byte[] classFix(InputStream input, ClassMetadataReader reader, boolean stripNumbers) throws IOException {
ClassReader cr = new ClassReader(input);
ClassNode cn = new ClassNode();
cr.accept(cn, stripNumbers ? (ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES) : ClassReader.SKIP_FRAMES);
ClassWriter cw = new SafeClassWriter(reader, ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
cn.accept(cw);
return cw.toByteArray();
}
private static Map<String, byte[]> getClassBytes(Map<String, ClassNode> classMap) {
Map<String, byte[]> byteMap = new HashMap<>();
for (ClassNode node : classMap.values()) {
ClassWriter writer = new ClassWriter(0);
node.accept(writer);
byte[] classBytes = writer.toByteArray();
byteMap.put(node.name, classBytes);
}
return byteMap;
}
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();
}
}
}
private byte[] getClassNodeBytes(ClassNode cn) {
ClassWriter cw = new ClassWriter(0);
cn.accept(cw);
byte[] b = cw.toByteArray();
return b;
}
@Override
public byte[] transform(String name, String realName, byte[] bytes) {
if (transformingLevel > 0) {
LOGGER.warn("Reentrant class loaded {} at level {}", realName, transformingLevel);
}
++transformingLevel;
if (transformingClasses.containsKey(realName)) {
ClassTransformer transformer = transformingClasses.get(realName);
try {
LOGGER.info("Transforming class " + realName);
ClassNode classNode = new ClassNode();
ClassReader classReader = new ClassReader(bytes);
classReader.accept(classNode, 0);
transformer.transform(classNode);
ClassWriter classWriter =
new NoClassLoadingClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
classNode.accept(classWriter);
// let gc clean this up
transformingClasses.remove(realName);
bytes = classWriter.toByteArray();
} catch (Exception e) {
LOGGER.error(
e.getClass().getSimpleName()
+ " thrown from transforming class "
+ realName
+ ": "
+ e.getMessage());
ASMStackLogger.printStackTrace(e);
}
}
--transformingLevel;
return bytes;
}
/**
* Gets the bytes of a given ClassNode.
*
* @param cn
* @param useMaxs
* @return
*/
public static byte[] getNodeBytes(ClassNode cn, boolean useMaxs) {
ClassWriter cw = new ClassWriter(useMaxs ? ClassWriter.COMPUTE_MAXS : ClassWriter.COMPUTE_FRAMES);
cn.accept(cw);
byte[] b = cw.toByteArray();
return b;
}
/**
* Writes a class to a byte array
* @param classNode
* @param classFile
* @throws IOException
*/
public static byte[] writeClass(ClassNode classNode) throws IOException {
ClassWriter classWriter = new ClassLoadingClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
classNode.accept(classWriter);
return classWriter.toByteArray();
}