mirror of
https://gitee.com/arthas/arthas.git
synced 2024-12-02 04:08:34 +08:00
update jad doc
This commit is contained in:
parent
de4a0a31e6
commit
61252e6edd
@ -38,7 +38,8 @@ import static com.taobao.text.ui.Element.label;
|
||||
@Name("jad")
|
||||
@Summary("Decompile class")
|
||||
@Description(Constants.EXAMPLE +
|
||||
" jad -c 39eb305e org.apache.log4j.Logger\n" +
|
||||
" jad java.lang.String\n" +
|
||||
" jad java.lang.String toString\n" +
|
||||
" jad -c 39eb305e org/apache/log4j/Logger\n" +
|
||||
" jad -c 39eb305e -E org\\\\.apache\\\\.*\\\\.StringUtils\n" +
|
||||
Constants.WIKI + Constants.WIKI_HOME + "jad")
|
||||
|
@ -28,7 +28,7 @@ Advanced Usage
|
||||
* [sm](sm.md) - check methods info for the loaded classes
|
||||
* [dump](dump.md) - dump the loaded classes in byte code to the specified location
|
||||
* [redefine](redefine.md) - load external `*.class` files and re-define it into JVM
|
||||
* [jad](jad.md) - de-compile the specified loaded classes
|
||||
* [jad](jad.md) - decompile the specified loaded classes
|
||||
* [classloader](classloader.md) - check the inheritance structure, urls, class loading info for the specified class; using classloader to get the url of the resource e.g. `java/lang/String.class`
|
||||
|
||||
## monitor/watch/trace - related
|
||||
|
@ -1,12 +1,12 @@
|
||||
jad
|
||||
===
|
||||
|
||||
> De-compile the specified classes.
|
||||
> Decompile the specified classes.
|
||||
|
||||
`jad` helps to de-compile the byte code running in JVM to the source code to assist you to understand the logic behind better.
|
||||
`jad` helps to decompile the byte code running in JVM to the source code to assist you to understand the logic behind better.
|
||||
|
||||
* The de-compiled code is syntax highlighted for better readability in Arthas console.
|
||||
* It is possible that there's grammar error in the de-compiled code, but it should not affect your interpretation.
|
||||
* The decompiled code is syntax highlighted for better readability in Arthas console.
|
||||
* It is possible that there's grammar error in the decompiled code, but it should not affect your interpretation.
|
||||
|
||||
### Options
|
||||
|
||||
@ -18,19 +18,78 @@ jad
|
||||
|
||||
### Usage
|
||||
|
||||
> If the target class is loaded by multiple classloaders, `jad` outputs the `hashcode` of the corresponding classloaders, then you can re-run `jad` and specify `-c <hashcode>` to de-compile the target class from the specified classloader.
|
||||
#### Decompile `java.lang.String`
|
||||
|
||||
```java
|
||||
$ jad java.lang.String
|
||||
|
||||
ClassLoader:
|
||||
|
||||
Location:
|
||||
|
||||
|
||||
/*
|
||||
* Decompiled with CFR 0_132.
|
||||
*/
|
||||
package java.lang;
|
||||
|
||||
import java.io.ObjectStreamField;
|
||||
...
|
||||
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[] arrby, int n, int n2) {
|
||||
String.checkBounds(arrby, n, n2);
|
||||
this.value = StringCoding.decode(arrby, n, n2);
|
||||
}
|
||||
...
|
||||
```
|
||||
|
||||
#### Decompile the specified method
|
||||
|
||||
```java
|
||||
$ jad demo.MathGame main
|
||||
|
||||
ClassLoader:
|
||||
+-sun.misc.Launcher$AppClassLoader@3d4eac69
|
||||
+-sun.misc.Launcher$ExtClassLoader@66350f69
|
||||
|
||||
Location:
|
||||
/private/tmp/arthas-demo.jar
|
||||
|
||||
public static void main(String[] args) throws InterruptedException {
|
||||
MathGame game = new MathGame();
|
||||
do {
|
||||
game.run();
|
||||
TimeUnit.SECONDS.sleep(1L);
|
||||
} while (true);
|
||||
}
|
||||
|
||||
Affect(row-cnt:1) cost in 228 ms.
|
||||
```
|
||||
|
||||
#### Decompile with specified classLoader
|
||||
|
||||
> If the target class is loaded by multiple classloaders, `jad` outputs the `hashcode` of the corresponding classloaders, then you can re-run `jad` and specify `-c <hashcode>` to decompile the target class from the specified 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
|
||||
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
|
||||
@ -39,7 +98,7 @@ ClassLoader:
|
||||
+-monitor's ModuleClassLoader
|
||||
|
||||
Location:
|
||||
/Users/zhuyong/Downloads/taobao-hsf.sar/plugins/monitor/lib/log4j-1.2.14.jar
|
||||
/Users/admin/app/log4j-1.2.14.jar
|
||||
|
||||
package org.apache.log4j;
|
||||
|
||||
@ -54,102 +113,7 @@ public class Logger extends Category
|
||||
super(name);
|
||||
}
|
||||
|
||||
public static Logger getLogger(String name)
|
||||
{
|
||||
return LogManager.getLogger(name);
|
||||
}
|
||||
|
||||
public static Logger getLogger(Class clazz)
|
||||
{
|
||||
return LogManager.getLogger(clazz.getName());
|
||||
}
|
||||
|
||||
public static Logger getRootLogger()
|
||||
{
|
||||
return LogManager.getRootLogger();
|
||||
}
|
||||
|
||||
public static Logger getLogger(String name, LoggerFactory factory)
|
||||
{
|
||||
return LogManager.getLogger(name, factory);
|
||||
}
|
||||
|
||||
public void trace(Object message)
|
||||
{
|
||||
if (repository.isDisabled(5000))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (Level.TRACE.isGreaterOrEqual(getEffectiveLevel()))
|
||||
{
|
||||
forcedLog(Logger.FQCN, Level.TRACE, message, null);
|
||||
}
|
||||
}
|
||||
|
||||
public void trace(Object message, Throwable t)
|
||||
{
|
||||
if (repository.isDisabled(5000))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (Level.TRACE.isGreaterOrEqual(getEffectiveLevel()))
|
||||
{
|
||||
forcedLog(Logger.FQCN, Level.TRACE, message, t);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isTraceEnabled()
|
||||
{
|
||||
if (repository.isDisabled(5000))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return Level.TRACE.isGreaterOrEqual(getEffectiveLevel());
|
||||
}
|
||||
|
||||
static
|
||||
{
|
||||
Logger.FQCN = Logger.class.getName();
|
||||
}
|
||||
|
||||
}
|
||||
...
|
||||
|
||||
Affect(row-cnt:1) cost in 190 ms.
|
||||
```
|
||||
|
||||
De-compile the specified method:
|
||||
|
||||
```bash
|
||||
$ jad com.taobao.container.web.arthas.rest.MetricsController directMetrics
|
||||
|
||||
ClassLoader:
|
||||
+-com.taobao.pandora.boot.loader.ReLaunchURLClassLoader@1817d444
|
||||
+-sun.misc.Launcher$AppClassLoader@14dad5dc
|
||||
+-sun.misc.Launcher$ExtClassLoader@a38d7a3
|
||||
|
||||
Location:
|
||||
/Users/zhuyong/middleware/tomcat-web/tomcat-web-web/target/classes/
|
||||
|
||||
private Map<String, Object> directMetrics(String ip, String[] metrics) {
|
||||
JSONObject obj;
|
||||
HashMap<String, Object> result = new HashMap<String, Object>();
|
||||
result.put("success", false);
|
||||
String metricUrl = "http://" + ip + ":8006/metrics/specific";
|
||||
String postBody = Arrays.stream(metrics).map(metric -> "metric=" + metric).collect(Collectors.joining("&"));
|
||||
HttpClientUtils.Response resp = HttpClientUtils.sendPostRequest((String)metricUrl, (String)postBody);
|
||||
if (resp.isSuccess() && (obj = JSON.parseObject(resp.getContent())).containsKey("success") && obj.getBoolean("success").booleanValue() && obj.containsKey("data")) {
|
||||
JSONArray dataArray = obj.getJSONArray("data");
|
||||
HashMap<String, Object> metricMap = new HashMap<String, Object>();
|
||||
for (Object aDataArray : dataArray) {
|
||||
JSONObject o = (JSONObject)aDataArray;
|
||||
metricMap.put(o.getString("metric"), o.get("value"));
|
||||
}
|
||||
result.put("data", metricMap);
|
||||
result.put("success", true);
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Affect(row-cnt:1) cost in 1508 ms.
|
||||
```
|
||||
|
@ -115,7 +115,7 @@ v2016-03-07
|
||||
v2016-01-18
|
||||
----
|
||||
|
||||
* [improvement] optimise [`jad`](jad.md); dump memory byte array in real time; using `jd-core-java` to de-compile; line number presented;
|
||||
* [improvement] optimise [`jad`](jad.md); dump memory byte array in real time; using `jd-core-java` to decompile; line number presented;
|
||||
* [bug] fix checking/re-producing issues when [`tt`](tt.md) is watching thread-context related methods invoking
|
||||
|
||||
v2016-01-08
|
||||
|
@ -18,19 +18,78 @@ jad
|
||||
|
||||
### 使用参考
|
||||
|
||||
>当有多个 `ClassLoader` 都加载了这个类时,`jad` 命令会输出对应 `ClassLoader` 实例的 `hashcode`,然后你只需要重新执行 `jad` 命令,并使用参数 `-c <hashcode>` 就可以反编译指定 ClassLoader 加载的那个类了;
|
||||
#### 编绎`java.lang.String`
|
||||
|
||||
```java
|
||||
$ jad java.lang.String
|
||||
|
||||
ClassLoader:
|
||||
|
||||
Location:
|
||||
|
||||
|
||||
/*
|
||||
* Decompiled with CFR 0_132.
|
||||
*/
|
||||
package java.lang;
|
||||
|
||||
import java.io.ObjectStreamField;
|
||||
...
|
||||
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[] arrby, int n, int n2) {
|
||||
String.checkBounds(arrby, n, n2);
|
||||
this.value = StringCoding.decode(arrby, n, n2);
|
||||
}
|
||||
...
|
||||
```
|
||||
|
||||
#### 反编绎指定的函数
|
||||
|
||||
```java
|
||||
$ jad demo.MathGame main
|
||||
|
||||
ClassLoader:
|
||||
+-sun.misc.Launcher$AppClassLoader@3d4eac69
|
||||
+-sun.misc.Launcher$ExtClassLoader@66350f69
|
||||
|
||||
Location:
|
||||
/private/tmp/arthas-demo.jar
|
||||
|
||||
public static void main(String[] args) throws InterruptedException {
|
||||
MathGame game = new MathGame();
|
||||
do {
|
||||
game.run();
|
||||
TimeUnit.SECONDS.sleep(1L);
|
||||
} while (true);
|
||||
}
|
||||
|
||||
Affect(row-cnt:1) cost in 228 ms.
|
||||
```
|
||||
|
||||
#### 反编绎时指定ClassLoader
|
||||
|
||||
> 当有多个 `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
|
||||
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
|
||||
@ -39,7 +98,7 @@ ClassLoader:
|
||||
+-monitor's ModuleClassLoader
|
||||
|
||||
Location:
|
||||
/Users/zhuyong/Downloads/taobao-hsf.sar/plugins/monitor/lib/log4j-1.2.14.jar
|
||||
/Users/admin/app/log4j-1.2.14.jar
|
||||
|
||||
package org.apache.log4j;
|
||||
|
||||
@ -54,102 +113,8 @@ public class Logger extends Category
|
||||
super(name);
|
||||
}
|
||||
|
||||
public static Logger getLogger(String name)
|
||||
{
|
||||
return LogManager.getLogger(name);
|
||||
}
|
||||
|
||||
public static Logger getLogger(Class clazz)
|
||||
{
|
||||
return LogManager.getLogger(clazz.getName());
|
||||
}
|
||||
|
||||
public static Logger getRootLogger()
|
||||
{
|
||||
return LogManager.getRootLogger();
|
||||
}
|
||||
|
||||
public static Logger getLogger(String name, LoggerFactory factory)
|
||||
{
|
||||
return LogManager.getLogger(name, factory);
|
||||
}
|
||||
|
||||
public void trace(Object message)
|
||||
{
|
||||
if (repository.isDisabled(5000))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (Level.TRACE.isGreaterOrEqual(getEffectiveLevel()))
|
||||
{
|
||||
forcedLog(Logger.FQCN, Level.TRACE, message, null);
|
||||
}
|
||||
}
|
||||
|
||||
public void trace(Object message, Throwable t)
|
||||
{
|
||||
if (repository.isDisabled(5000))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (Level.TRACE.isGreaterOrEqual(getEffectiveLevel()))
|
||||
{
|
||||
forcedLog(Logger.FQCN, Level.TRACE, message, t);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isTraceEnabled()
|
||||
{
|
||||
if (repository.isDisabled(5000))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return Level.TRACE.isGreaterOrEqual(getEffectiveLevel());
|
||||
}
|
||||
|
||||
static
|
||||
{
|
||||
Logger.FQCN = Logger.class.getName();
|
||||
}
|
||||
|
||||
}
|
||||
...
|
||||
|
||||
Affect(row-cnt:1) cost in 190 ms.
|
||||
```
|
||||
|
||||
反编译指定的方法:
|
||||
|
||||
```bash
|
||||
$ jad com.taobao.container.web.arthas.rest.MetricsController directMetrics
|
||||
|
||||
ClassLoader:
|
||||
+-com.taobao.pandora.boot.loader.ReLaunchURLClassLoader@1817d444
|
||||
+-sun.misc.Launcher$AppClassLoader@14dad5dc
|
||||
+-sun.misc.Launcher$ExtClassLoader@a38d7a3
|
||||
|
||||
Location:
|
||||
/Users/zhuyong/middleware/tomcat-web/tomcat-web-web/target/classes/
|
||||
|
||||
private Map<String, Object> directMetrics(String ip, String[] metrics) {
|
||||
JSONObject obj;
|
||||
HashMap<String, Object> result = new HashMap<String, Object>();
|
||||
result.put("success", false);
|
||||
String metricUrl = "http://" + ip + ":8006/metrics/specific";
|
||||
String postBody = Arrays.stream(metrics).map(metric -> "metric=" + metric).collect(Collectors.joining("&"));
|
||||
HttpClientUtils.Response resp = HttpClientUtils.sendPostRequest((String)metricUrl, (String)postBody);
|
||||
if (resp.isSuccess() && (obj = JSON.parseObject(resp.getContent())).containsKey("success") && obj.getBoolean("success").booleanValue() && obj.containsKey("data")) {
|
||||
JSONArray dataArray = obj.getJSONArray("data");
|
||||
HashMap<String, Object> metricMap = new HashMap<String, Object>();
|
||||
for (Object aDataArray : dataArray) {
|
||||
JSONObject o = (JSONObject)aDataArray;
|
||||
metricMap.put(o.getString("metric"), o.get("value"));
|
||||
}
|
||||
result.put("data", metricMap);
|
||||
result.put("success", true);
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Affect(row-cnt:1) cost in 1508 ms.
|
||||
```
|
@ -24,7 +24,7 @@ Affect(row-cnt:1) cost in 3 ms.
|
||||
```bash
|
||||
$ trace Test t >> &
|
||||
job id : 2
|
||||
cache location : /Users/zhuyong/logs/arthas-cache/28198/2
|
||||
cache location : /Users/admin/logs/arthas-cache/28198/2
|
||||
```
|
||||
|
||||
此时命令会在后台异步执行,并将结果异步保存在文件(~/logs/arthas-cache/${PID}/${JobId})中;
|
||||
|
Loading…
Reference in New Issue
Block a user