From 2d7e19f13357da96fc2c519f6ce707d194f187d3 Mon Sep 17 00:00:00 2001 From: hengyunabc Date: Tue, 23 Feb 2021 16:46:30 +0800 Subject: [PATCH] JadModel support line mappings. #1 --- .../java/com/taobao/arthas/common/Pair.java | 64 +++++++++++++++++++ .../core/command/klass100/JadCommand.java | 6 +- .../arthas/core/command/model/JadModel.java | 12 +++- .../taobao/arthas/core/util/Decompiler.java | 29 +++++---- 4 files changed, 96 insertions(+), 15 deletions(-) create mode 100644 common/src/main/java/com/taobao/arthas/common/Pair.java diff --git a/common/src/main/java/com/taobao/arthas/common/Pair.java b/common/src/main/java/com/taobao/arthas/common/Pair.java new file mode 100644 index 000000000..bbebf836c --- /dev/null +++ b/common/src/main/java/com/taobao/arthas/common/Pair.java @@ -0,0 +1,64 @@ +package com.taobao.arthas.common; + +public class Pair { + private final X x; + private final Y y; + + public Pair(X x, Y y) { + this.x = x; + this.y = y; + } + + public X getFirst() { + return x; + } + + public Y getSecond() { + return y; + } + + public static Pair make(A a, B b) { + return new Pair(a, b); + } + + @Override + public boolean equals(Object o) { + if (o == this) + return true; + if (!(o instanceof Pair)) + return false; + + Pair other = (Pair) o; + + if (x == null) { + if (other.x != null) + return false; + } else { + if (!x.equals(other.x)) + return false; + } + if (y == null) { + if (other.y != null) + return false; + } else { + if (!y.equals(other.y)) + return false; + } + return true; + } + + @Override + public int hashCode() { + int hashCode = 1; + if (x != null) + hashCode = x.hashCode(); + if (y != null) + hashCode = (hashCode * 31) + y.hashCode(); + return hashCode; + } + + @Override + public String toString() { + return "P[" + x + "," + y + "]"; + } +} 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 3884b7683..8e19aed7b 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 @@ -2,6 +2,7 @@ package com.taobao.arthas.core.command.klass100; import com.alibaba.arthas.deps.org.slf4j.Logger; import com.alibaba.arthas.deps.org.slf4j.LoggerFactory; +import com.taobao.arthas.common.Pair; import com.taobao.arthas.core.command.Constants; import com.taobao.arthas.core.command.model.ClassVO; import com.taobao.arthas.core.command.model.ClassLoaderVO; @@ -32,6 +33,7 @@ import java.lang.instrument.Instrumentation; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.NavigableMap; import java.util.Set; import java.util.Collection; import java.util.regex.Pattern; @@ -177,7 +179,8 @@ public class JadCommand extends AnnotatedCommand { Map, File> classFiles = transformer.getDumpResult(); File classFile = classFiles.get(c); - String source = Decompiler.decompile(classFile.getAbsolutePath(), methodName, hideUnicode, lineNumber); + Pair> decompileResult = Decompiler.decompileWithMappings(classFile.getAbsolutePath(), methodName, hideUnicode, lineNumber); + String source = decompileResult.getFirst(); if (source != null) { source = pattern.matcher(source).replaceAll(""); } else { @@ -186,6 +189,7 @@ public class JadCommand extends AnnotatedCommand { JadModel jadModel = new JadModel(); jadModel.setSource(source); + jadModel.setMappings(decompileResult.getSecond()); if (!this.sourceOnly) { jadModel.setClassInfo(ClassUtils.createSimpleClassInfo(c)); jadModel.setLocation(ClassUtils.getCodeSource(c.getProtectionDomain().getCodeSource())); diff --git a/core/src/main/java/com/taobao/arthas/core/command/model/JadModel.java b/core/src/main/java/com/taobao/arthas/core/command/model/JadModel.java index 19a8691ba..d96630c27 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/model/JadModel.java +++ b/core/src/main/java/com/taobao/arthas/core/command/model/JadModel.java @@ -1,15 +1,17 @@ package com.taobao.arthas.core.command.model; import java.util.Collection; -import java.util.List; +import java.util.NavigableMap; /** * @author gongdewei 2020/4/22 + * @author hengyunabc 2021-02-23 */ public class JadModel extends ResultModel { private ClassVO classInfo; private String location; private String source; + private NavigableMap mappings; private Collection matchedClassLoaders; private String classLoaderClass; @@ -48,6 +50,14 @@ public class JadModel extends ResultModel { this.source = source; } + public NavigableMap getMappings() { + return mappings; + } + + public void setMappings(NavigableMap mappings) { + this.mappings = mappings; + } + public Collection getMatchedClasses() { return matchedClasses; } diff --git a/core/src/main/java/com/taobao/arthas/core/util/Decompiler.java b/core/src/main/java/com/taobao/arthas/core/util/Decompiler.java index 07beba6c6..14f2c3057 100644 --- a/core/src/main/java/com/taobao/arthas/core/util/Decompiler.java +++ b/core/src/main/java/com/taobao/arthas/core/util/Decompiler.java @@ -8,11 +8,14 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.NavigableMap; +import java.util.TreeMap; import org.benf.cfr.reader.api.CfrDriver; import org.benf.cfr.reader.api.OutputSinkFactory; import org.benf.cfr.reader.api.SinkReturns.LineNumberMapping; +import com.taobao.arthas.common.Pair; + /** * * @author hengyunabc 2018-11-16 @@ -28,17 +31,11 @@ public class Decompiler { return decompile(classFilePath, methodName, hideUnicode, true); } - /** - * @param classFilePath - * @param methodName - * @param hideUnicode - * @return - */ - public static String decompile(String classFilePath, String methodName, boolean hideUnicode, - boolean printLineNumber) { + public static Pair> decompileWithMappings(String classFilePath, + String methodName, boolean hideUnicode, boolean printLineNumber) { final StringBuilder sb = new StringBuilder(8192); - final Map lineMapping = new HashMap(); + final NavigableMap lineMapping = new TreeMap(); OutputSinkFactory mySink = new OutputSinkFactory() { @Override @@ -59,7 +56,7 @@ public class Decompiler { if (sinkType == SinkType.LINENUMBER) { LineNumberMapping mapping = (LineNumberMapping) sinkable; NavigableMap classFileMappings = mapping.getClassFileMappings(); - NavigableMap mappings = mapping.getMappings(); + NavigableMap mappings = mapping.getMappings(); if (classFileMappings != null && mappings != null) { for (Entry entry : mappings.entrySet()) { Integer srcLineNumber = classFileMappings.get(entry.getKey()); @@ -91,11 +88,17 @@ public class Decompiler { toAnalyse.add(classFilePath); driver.analyse(toAnalyse); - String result = sb.toString(); + String resultCode = sb.toString(); if (printLineNumber && !lineMapping.isEmpty()) { - result = addLineNumber(result, lineMapping); + resultCode = addLineNumber(resultCode, lineMapping); } - return result; + + return Pair.make(resultCode, lineMapping); + } + + public static String decompile(String classFilePath, String methodName, boolean hideUnicode, + boolean printLineNumber) { + return decompileWithMappings(classFilePath, methodName, hideUnicode, printLineNumber).getFirst(); } private static String addLineNumber(String src, Map lineMapping) {