You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
arthas/site/docs/doc/jad.md

187 lines
5.4 KiB
Markdown

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# jad
[`jad`在线教程](https://arthas.aliyun.com/doc/arthas-tutorials?language=cn&id=command-jad)
::: tip
反编译指定已加载类的源码
:::
`jad` 命令将 JVM 中实际运行的 class 的 byte code 反编译成 java 代码,便于你理解业务逻辑;如需批量下载指定包的目录的 class 字节码可以参考 [dump](/doc/dump.md)。
- 在 Arthas Console 上,反编译出来的源码是带语法高亮的,阅读更方便
- 当然,反编译出来的 java 代码可能会存在语法错误,但不影响你进行阅读理解
## 参数说明
| 参数名称 | 参数说明 |
| --------------------: | :----------------------------------------- |
| _class-pattern_ | 类名表达式匹配 |
| `[c:]` | 类所属 ClassLoader 的 hashcode |
| `[classLoaderClass:]` | 指定执行表达式的 ClassLoader 的 class name |
| [E] | 开启正则表达式匹配,默认为通配符匹配 |
## 使用参考
### 反编译`java.lang.String`
```java
$ jad java.lang.String
ClassLoader:
Location:
/*
* Decompiled with CFR.
*/
package java.lang;
import java.io.ObjectStreamField;
import java.io.Serializable;
...
public final class String
implements Serializable,
Comparable<String>,
CharSequence {
private final char[] value;
private int hash;
private static final long serialVersionUID = -6849794470754667710L;
private static final ObjectStreamField[] serialPersistentFields = new ObjectStreamField[0];
public static final Comparator<String> CASE_INSENSITIVE_ORDER = new CaseInsensitiveComparator();
...
public String(byte[] byArray, int n, int n2, Charset charset) {
/*460*/ if (charset == null) {
throw new NullPointerException("charset");
}
/*462*/ String.checkBounds(byArray, n, n2);
/*463*/ this.value = StringCoding.decode(charset, byArray, n, n2);
}
...
```
### 反编译时只显示源代码
默认情况下,反编译结果里会带有`ClassLoader`信息,通过`--source-only`选项,可以只打印源代码。方便和[mc](mc.md)/[retransform](retransform.md)命令结合使用。
```java
$ jad --source-only demo.MathGame
/*
* Decompiled with CFR 0_132.
*/
package demo;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;
public class MathGame {
private static Random random = new Random();
public int illegalArgumentCount = 0;
...
```
### 反编译指定的函数
```java
$ jad demo.MathGame main
ClassLoader:
+-sun.misc.Launcher$AppClassLoader@232204a1
+-sun.misc.Launcher$ExtClassLoader@7f31245a
Location:
/private/tmp/math-game.jar
public static void main(String[] args) throws InterruptedException {
MathGame game = new MathGame();
while (true) {
/*16*/ game.run();
/*17*/ TimeUnit.SECONDS.sleep(1L);
}
}
```
### 反编译时不显示行号
`--lineNumber` 参数默认值为 true显示指定为 false 则不打印行号。
```java
$ jad demo.MathGame main --lineNumber false
ClassLoader:
+-sun.misc.Launcher$AppClassLoader@232204a1
+-sun.misc.Launcher$ExtClassLoader@7f31245a
Location:
/private/tmp/math-game.jar
public static void main(String[] args) throws InterruptedException {
MathGame game = new MathGame();
while (true) {
game.run();
TimeUnit.SECONDS.sleep(1L);
}
}
```
### 反编译时指定 ClassLoader
::: tip
当有多个 `ClassLoader` 都加载了这个类时,`jad` 命令会输出对应 `ClassLoader` 实例的 `hashcode`,然后你只需要重新执行 `jad` 命令,并使用参数 `-c <hashcode>` 就可以反编译指定 ClassLoader 加载的那个类了;
:::
```java
$ jad org.apache.log4j.Logger
Found more than one class for: org.apache.log4j.Logger, Please use jad -c hashcode org.apache.log4j.Logger
HASHCODE CLASSLOADER
69dcaba4 +-monitor's ModuleClassLoader
6e51ad67 +-java.net.URLClassLoader@6e51ad67
+-sun.misc.Launcher$AppClassLoader@6951a712
+-sun.misc.Launcher$ExtClassLoader@6fafc4c2
2bdd9114 +-pandora-qos-service's ModuleClassLoader
4c0df5f8 +-pandora-framework's ModuleClassLoader
Affect(row-cnt:0) cost in 38 ms.
$ jad org.apache.log4j.Logger -c 69dcaba4
ClassLoader:
+-monitor's ModuleClassLoader
Location:
/Users/admin/app/log4j-1.2.14.jar
package org.apache.log4j;
import org.apache.log4j.spi.*;
public class Logger extends Category
{
private static final String FQCN;
protected Logger(String name)
{
super(name);
}
...
Affect(row-cnt:1) cost in 190 ms.
```
对于只有唯一实例的 ClassLoader 还可以通过`--classLoaderClass`指定 class name使用起来更加方便
`--classLoaderClass` 的值是 ClassLoader 的类名,只有匹配到唯一的 ClassLoader 实例时才能工作,目的是方便输入通用命令,而`-c <hashcode>`是动态变化的。
### 反编译时指定dump class文件目录
`jad`反编译需要将class dump到文件默认会dump到logback.xml中配置的log目录下使用`-d/--directory`可以将文件dump到指定目录。
```java
$ jad demo.MathGame -d /tmp/jad/dump
```