diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/ClassDumpTransformer.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/ClassDumpTransformer.java index 773d47c7d1..ec62ab1386 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/ClassDumpTransformer.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/ClassDumpTransformer.java @@ -52,18 +52,23 @@ public Map, File> getDumpResult() { return dumpResult; } - private void dumpClassIfNecessary(Class clazz, byte[] data) { - String className = clazz.getName(); - ClassLoader classLoader = clazz.getClassLoader(); + public File dumpDir() { String classDumpDir = "classdump"; - - // 创建类所在的包路径 - File dumpDir = null; + final File dumpDir; if (directory != null) { dumpDir = directory; } else { dumpDir = new File(arthasLogHome, classDumpDir); } + return dumpDir; + } + + private void dumpClassIfNecessary(Class clazz, byte[] data) { + String className = clazz.getName(); + ClassLoader classLoader = clazz.getClassLoader(); + + // 创建类所在的包路径 + File dumpDir = dumpDir(); if (!dumpDir.mkdirs() && !dumpDir.exists()) { logger.warn("create dump directory:{} failed.", dumpDir.getAbsolutePath()); return; diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/JadCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/JadCommand.java index f218e873e1..8ea8d58e81 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/JadCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/JadCommand.java @@ -47,6 +47,7 @@ @Description(Constants.EXAMPLE + " jad java.lang.String\n" + " jad java.lang.String toString\n" + + " jad java.lang.String -d /tmp/jad/dump\n" + " jad --source-only java.lang.String\n" + " jad -c 39eb305e org/apache/log4j/Logger\n" + " jad -c 39eb305e -E org\\\\.apache\\\\.*\\\\.StringUtils\n" + @@ -62,6 +63,7 @@ public class JadCommand extends AnnotatedCommand { private boolean isRegEx = false; private boolean hideUnicode = false; private boolean lineNumber; + private String directory; /** * jad output source code only @@ -118,6 +120,12 @@ public void setLineNumber(boolean lineNumber) { this.lineNumber = lineNumber; } + @Option(shortName = "d", longName = "directory") + @Description("Sets the destination directory for dummped class files required by cfr decompiler") + public void setDirectory(String directory) { + this.directory = directory; + } + @Override public void process(CommandProcess process) { RowAffect affect = new RowAffect(); @@ -173,10 +181,19 @@ private ExitStatus processExactMatch(CommandProcess process, RowAffect affect, I allClasses.add(c); try { - ClassDumpTransformer transformer = new ClassDumpTransformer(allClasses); + final ClassDumpTransformer transformer; + if (directory == null) { + transformer = new ClassDumpTransformer(allClasses); + } else { + transformer = new ClassDumpTransformer(allClasses, new File(directory)); + } InstrumentationUtils.retransformClasses(inst, transformer, allClasses); Map, File> classFiles = transformer.getDumpResult(); + if (classFiles == null || classFiles.isEmpty()) { + return ExitStatus.failure(-1, "jad: fail to dump class file for decompiler, make sure you have write permission of the directory \"" + transformer.dumpDir() + + "\" or try with \"-d/--directory\" to specify the directory of dump files"); + } File classFile = classFiles.get(c); Pair> decompileResult = Decompiler.decompileWithMappings(classFile.getAbsolutePath(), methodName, hideUnicode, lineNumber); diff --git a/site/docs/doc/jad.md b/site/docs/doc/jad.md index 28665ea3a9..a784e62132 100644 --- a/site/docs/doc/jad.md +++ b/site/docs/doc/jad.md @@ -176,3 +176,11 @@ Affect(row-cnt:1) cost in 190 ms. 对于只有唯一实例的 ClassLoader 还可以通过`--classLoaderClass`指定 class name,使用起来更加方便: `--classLoaderClass` 的值是 ClassLoader 的类名,只有匹配到唯一的 ClassLoader 实例时才能工作,目的是方便输入通用命令,而`-c `是动态变化的。 + +### 反编译时指定dump class文件目录 + +`jad`反编译需要将class dump到文件,默认会dump到logback.xml中配置的log目录下,使用`-d/--directory`可以将文件dump到指定目录。 + +```java +$ jad demo.MathGame -d /tmp/jad/dump +``` \ No newline at end of file diff --git a/site/docs/en/doc/jad.md b/site/docs/en/doc/jad.md index 1a4c72d466..b713acc5fc 100644 --- a/site/docs/en/doc/jad.md +++ b/site/docs/en/doc/jad.md @@ -176,3 +176,11 @@ Affect(row-cnt:1) cost in 190 ms. For classloader with only one instance, it can be specified by `--classLoaderClass` using class name, which is more convenient to use. The value of `--classloaderclass` is the class name of classloader. It can only work when it matches a unique classloader instance. The purpose is to facilitate the input of general commands. However, `-c ` is dynamic. + +### Decompile with specified directory for dumpping class + +Decompile class with `jad` need to dump corresponding classes into files. The default directory for dumpping classes is the directory of log file specified in logback.xml, we can use `-d/--directory` to specify the directory for dummping class. + +```java +$ jad demo.MathGame -d /tmp/jad/dump +```