这是我参与更文挑战的第8天,活动详情查看: 更文挑战
本文内容基于arthas 3.5.2 版本,介绍类命令jad,dump的使用及实现
一.jad命令
反编译指定已加载类的源码
| 参数名称 | 参数缩写 | 参数说明 | 必填项 |
|---|---|---|---|
| class-pattern | 名称表达式匹配 | 必填 | |
| method-pattern | 方法名表达式匹配 | 可选 | |
| --regex | -E | 开启正则表达式匹配,默认为通配符匹配。 | 可选 |
| --code | -c | 指定class的 ClassLoader 的 hashcode | 可选 |
| --classLoaderClass | 指定执行表达式的 ClassLoader 的 class name | 可选 | |
| --hideUnicode | 不显示unicode码,默认为false | 可选 | |
| --source-only | 输出只显示源代码,默认为false | 可选 |
文件位于com.taobao.arthas.core.command.klass100.JadCommand.java。
指定执行表达式的 ClassLoader 的 class name,
对于只有唯一实例的ClassLoader才可以通过--classLoaderClass指定class name。
只有匹配到唯一的ClassLoader实例时才能正常工作,当存在多个的情况下需要通过-c指定hashcode
SearchUtils.searchClassOnly()搜索class,并根据E来判断是否开启正则匹配。
没有匹配到class,processNoMatch()报错提示,
匹配到多个时processMatches()提示使用jad -c 来确定唯一的class
匹配到唯一的class,查找内部类,按照(主类名$*),若不存在内部类withInnerClasses则为查到的唯一class作为参数,执行processExactMatch()。
InstrumentationUtils.retransformClasses(ClassFileTransformer transformer, boolean canRetransform)
注册ClassFileTransformer实例,注册多个则会按照注册顺序进行调用。
所有的类被加载完毕之后会调用ClassFileTransformer实例,相当于它们通过了redefineClasses方法进行重定义。布尔值参数canRetransform决定这里被重定义的类是否能够通过retransformClasses方法进行回滚。
inst.retransformClasses(clazz)回滚。inst.removeTransformer()删除ClassFileTransformer实例。
将class字节码写入文件中用于编译。
ClassDumpTransformer transformer = new ClassDumpTransformer(allClasses)文件写入arthas日志文件所在路径。
Decompiler.decompile(classFile.getAbsolutePath(), methodName, hideUnicode)反编译,使用Cfr库反编译,hideUnicode默认为false,会显示初始编码,例如:世界反编译后为\u4e16\u754c(hideUnicode为true正常显示文字?)
Pattern.compile("(?m)^/\\*\\s*\\*/\\s*$" + System.getProperty("line.separator"))删除反编译后的注释。
--source-only反编译时只显示源代码,默认为false,反编译结果里会带有ClassLoader信息
ClassUtils.createSimpleClassInfo(c)
ClassUtils.getCodeSource(c.getProtectionDomain().getCodeSource())。
二.dump命令
dump 已加载类的 bytecode 到特定目录
| 参数名称 | 参数缩写 | 参数说明 | 必填项 |
|---|---|---|---|
| class-pattern | 外部的.class文件的完整路径,支持多个 | 必填 | |
| --classLoaderClass | 指定执行表达式的 ClassLoader 的 class name | 可选 | |
| --code | -c | 指定class的 ClassLoader 的 hashcode | 可选 |
| --regex | -E | 开启正则表达式匹配,默认为通配符匹配 | 可选 |
| --directory | -d | 为class文件输出设置文件路径 | 可选 |
| --limit | -l | dump 的class文件个数限制,默认为50,原描述为5有误。 | 可选 |
文件位于com.taobao.arthas.core.command.klass100.DumpClassCommand.java。
SearchUtils.searchClass根据类的全限定名,classloader的hashcode,正则匹配获取。
若没有找到对应的class则执行processNoMatch方法直接提示未找到。
若匹配到的class数大于limit,则进入processMatches(process, matchedClasses)方法,提示使用--limit配置参数,显示更多的内容。并返回简单的class信息,只显示classLoader名和classLoader的hashcode的列表。
若没有超出限制,则执行processMatch(process, effect, inst, matchedClasses)方法。通过dump(inst, matchedClasses)方法dump具体的class文件。自定义ClassDumpTransformer类实现接口ClassFileTransformer中的transform方法。最后获取dump结果。