mirror of
https://github.com/alibaba/arthas.git
synced 2024-04-21 10:21:39 +00:00
jad command support classes created by lambda method. fix #305
This commit is contained in:
@@ -5,6 +5,7 @@ import com.taobao.arthas.core.command.Constants;
|
||||
import com.taobao.arthas.core.shell.command.AnnotatedCommand;
|
||||
import com.taobao.arthas.core.shell.command.CommandProcess;
|
||||
import com.taobao.arthas.core.util.ClassUtils;
|
||||
import com.taobao.arthas.core.util.Decompiler;
|
||||
import com.taobao.arthas.core.util.FileUtils;
|
||||
import com.taobao.arthas.core.util.LogUtil;
|
||||
import com.taobao.arthas.core.util.SearchUtils;
|
||||
@@ -119,7 +120,7 @@ public class JadCommand extends AnnotatedCommand {
|
||||
File classFile = classFiles.get(c);
|
||||
|
||||
String source;
|
||||
source = decompileWithCFR(classFile.getAbsolutePath(), c, methodName);
|
||||
source = Decompiler.decompile(classFile.getAbsolutePath(), methodName);
|
||||
if (source != null) {
|
||||
source = pattern.matcher(source).replaceAll("");
|
||||
} else {
|
||||
@@ -163,33 +164,6 @@ public class JadCommand extends AnnotatedCommand {
|
||||
process.write("No class found for: " + classPattern + "\n");
|
||||
}
|
||||
|
||||
private String decompileWithCFR(String classPath, Class<?> clazz, String methodName) {
|
||||
List<String> options = new ArrayList<String>();
|
||||
options.add(classPath);
|
||||
// options.add(clazz.getName());
|
||||
if (methodName != null) {
|
||||
options.add(methodName);
|
||||
}
|
||||
options.add(OUTPUTOPTION);
|
||||
options.add(DecompilePath);
|
||||
options.add(COMMENTS);
|
||||
options.add("false");
|
||||
String args[] = new String[options.size()];
|
||||
options.toArray(args);
|
||||
Main.main(args);
|
||||
String outputFilePath = DecompilePath + File.separator + Type.getInternalName(clazz) + ".java";
|
||||
File outputFile = new File(outputFilePath);
|
||||
if (outputFile.exists()) {
|
||||
try {
|
||||
return FileUtils.readFileToString(outputFile, Charset.defaultCharset());
|
||||
} catch (IOException e) {
|
||||
logger.error(null, "error read decompile result in: " + outputFilePath, e);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
String[] names = {
|
||||
"com.taobao.container.web.arthas.mvc.AppInfoController",
|
||||
|
||||
@@ -0,0 +1,194 @@
|
||||
package com.taobao.arthas.core.util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.benf.cfr.reader.bytecode.analysis.parse.utils.Pair;
|
||||
import org.benf.cfr.reader.entities.ClassFile;
|
||||
import org.benf.cfr.reader.entities.Method;
|
||||
import org.benf.cfr.reader.relationship.MemberNameResolver;
|
||||
import org.benf.cfr.reader.state.ClassFileSourceImpl;
|
||||
import org.benf.cfr.reader.state.DCCommonState;
|
||||
import org.benf.cfr.reader.state.TypeUsageCollector;
|
||||
import org.benf.cfr.reader.state.TypeUsageInformation;
|
||||
import org.benf.cfr.reader.util.AnalysisType;
|
||||
import org.benf.cfr.reader.util.CannotLoadClassException;
|
||||
import org.benf.cfr.reader.util.ConfusedCFRException;
|
||||
import org.benf.cfr.reader.util.ListFactory;
|
||||
import org.benf.cfr.reader.util.getopt.GetOptParser;
|
||||
import org.benf.cfr.reader.util.getopt.Options;
|
||||
import org.benf.cfr.reader.util.getopt.OptionsImpl;
|
||||
import org.benf.cfr.reader.util.output.Dumper;
|
||||
import org.benf.cfr.reader.util.output.DumperFactory;
|
||||
import org.benf.cfr.reader.util.output.DumperFactoryImpl;
|
||||
import org.benf.cfr.reader.util.output.IllegalIdentifierDump;
|
||||
import org.benf.cfr.reader.util.output.StreamDumper;
|
||||
import org.benf.cfr.reader.util.output.ToStringDumper;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author hengyunabc 2018-11-16
|
||||
*
|
||||
*/
|
||||
public class Decompiler {
|
||||
|
||||
/**
|
||||
* @see org.benf.cfr.reader.Main#main(String[])
|
||||
* @param classFilePath
|
||||
* @param methodName
|
||||
* @return
|
||||
*/
|
||||
public static String decompile(String classFilePath, String methodName) {
|
||||
StringBuilder result = new StringBuilder(8192);
|
||||
|
||||
List<String> argList = new ArrayList<String>();
|
||||
argList.add(classFilePath);
|
||||
if (methodName != null) {
|
||||
argList.add("--methodname");
|
||||
argList.add(methodName);
|
||||
}
|
||||
String args[] = argList.toArray(new String[0]);
|
||||
|
||||
GetOptParser getOptParser = new GetOptParser();
|
||||
|
||||
Options options = null;
|
||||
List<String> files = null;
|
||||
try {
|
||||
Pair processedArgs = getOptParser.parse(args, OptionsImpl.getFactory());
|
||||
files = (List) processedArgs.getFirst();
|
||||
options = (Options) processedArgs.getSecond();
|
||||
} catch (Exception e) {
|
||||
getOptParser.showHelp(OptionsImpl.getFactory(), e);
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
if ((options.optionIsSet(OptionsImpl.HELP)) || (files.isEmpty())) {
|
||||
getOptParser.showOptionHelp(OptionsImpl.getFactory(), options, OptionsImpl.HELP);
|
||||
return "";
|
||||
}
|
||||
|
||||
ClassFileSourceImpl classFileSource = new ClassFileSourceImpl(options);
|
||||
|
||||
boolean skipInnerClass = (files.size() > 1)
|
||||
&& (((Boolean) options.getOption(OptionsImpl.SKIP_BATCH_INNER_CLASSES)).booleanValue());
|
||||
|
||||
Collections.sort(files);
|
||||
|
||||
for (String path : files) {
|
||||
classFileSource.clearConfiguration();
|
||||
DCCommonState dcCommonState = new DCCommonState(options, classFileSource);
|
||||
DumperFactory dumperFactory = new DumperFactoryImpl(options);
|
||||
|
||||
path = classFileSource.adjustInputPath(path);
|
||||
|
||||
AnalysisType type = (AnalysisType) options.getOption(OptionsImpl.ANALYSE_AS);
|
||||
if (type == null)
|
||||
type = dcCommonState.detectClsJar(path);
|
||||
|
||||
if (type == AnalysisType.JAR) {
|
||||
// doJar(dcCommonState, path, dumperFactory);
|
||||
}
|
||||
if (type == AnalysisType.CLASS)
|
||||
result.append(doClass(dcCommonState, path, skipInnerClass, dumperFactory));
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
public static String doClass(DCCommonState dcCommonState, String path, boolean skipInnerClass,
|
||||
DumperFactory dumperFactory) {
|
||||
StringBuilder result = new StringBuilder(8192);
|
||||
Options options = dcCommonState.getOptions();
|
||||
IllegalIdentifierDump illegalIdentifierDump = IllegalIdentifierDump.Factory.get(options);
|
||||
Dumper d = new ToStringDumper();
|
||||
try {
|
||||
ClassFile c = dcCommonState.getClassFileMaybePath(path);
|
||||
if ((skipInnerClass) && (c.isInnerClass()))
|
||||
return "";
|
||||
dcCommonState.configureWith(c);
|
||||
dumperFactory.getProgressDumper().analysingType(c.getClassType());
|
||||
try {
|
||||
c = dcCommonState.getClassFile(c.getClassType());
|
||||
} catch (CannotLoadClassException e) {
|
||||
}
|
||||
if (((Boolean) options.getOption(OptionsImpl.DECOMPILE_INNER_CLASSES)).booleanValue()) {
|
||||
c.loadInnerClasses(dcCommonState);
|
||||
}
|
||||
if (((Boolean) options.getOption(OptionsImpl.RENAME_DUP_MEMBERS)).booleanValue()) {
|
||||
MemberNameResolver.resolveNames(dcCommonState,
|
||||
ListFactory.newList(dcCommonState.getClassCache().getLoadedTypes()));
|
||||
}
|
||||
|
||||
c.analyseTop(dcCommonState);
|
||||
|
||||
TypeUsageCollector collectingDumper = new TypeUsageCollector(c);
|
||||
c.collectTypeUsages(collectingDumper);
|
||||
|
||||
d = new StringDumper(collectingDumper.getTypeUsageInformation(), options, illegalIdentifierDump);
|
||||
|
||||
// d = dumperFactory.getNewTopLevelDumper(c.getClassType(), summaryDumper,
|
||||
// collectingDumper.getTypeUsageInformation(), illegalIdentifierDump);
|
||||
|
||||
String methname = (String) options.getOption(OptionsImpl.METHODNAME);
|
||||
if (methname == null)
|
||||
c.dump(d);
|
||||
else {
|
||||
try {
|
||||
for (Method method : c.getMethodByName(methname))
|
||||
method.dump(d, true);
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new IllegalArgumentException("No such method '" + methname + "'.");
|
||||
}
|
||||
}
|
||||
d.print("");
|
||||
result.append(d.toString());
|
||||
} catch (ConfusedCFRException e) {
|
||||
result.append(e.toString()).append("\n");
|
||||
for (Object x : e.getStackTrace())
|
||||
result.append(x).append("\n");
|
||||
} catch (CannotLoadClassException e) {
|
||||
result.append("Can't load the class specified:").append("\n");
|
||||
result.append(e.toString()).append("\n");
|
||||
} catch (RuntimeException e) {
|
||||
result.append(e.toString()).append("\n");
|
||||
for (Object x : e.getStackTrace())
|
||||
result.append(x).append("\n");
|
||||
} finally {
|
||||
if (d != null)
|
||||
d.close();
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
public static class StringDumper extends StreamDumper {
|
||||
private StringWriter sw = new StringWriter();
|
||||
|
||||
public StringDumper(TypeUsageInformation typeUsageInformation, Options options,
|
||||
IllegalIdentifierDump illegalIdentifierDump) {
|
||||
super(typeUsageInformation, options, illegalIdentifierDump);
|
||||
}
|
||||
|
||||
public void addSummaryError(Method paramMethod, String paramString) {
|
||||
|
||||
}
|
||||
|
||||
public void close() {
|
||||
try {
|
||||
sw.close();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void write(String source) {
|
||||
sw.write(source);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return sw.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user