forked from alibaba/arthas
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
jad command support classes created by lambda method. fix alibaba#305
- Loading branch information
1 parent
6df48f3
commit 56ab5dc
Showing
2 changed files
with
196 additions
and
28 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
194 changes: 194 additions & 0 deletions
194
core/src/main/java/com/taobao/arthas/core/util/Decompiler.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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(); | ||
} | ||
} | ||
} |