From 7bbb083c36273cfef246a1ba5c8ca9c0a4e8bbaa Mon Sep 17 00:00:00 2001 From: Skylot Date: Mon, 13 Jan 2020 15:30:12 +0300 Subject: [PATCH] refactor: small changes to switch region and region debug print --- .../java/jadx/core/codegen/RegionGen.java | 8 +-- .../jadx/core/dex/attributes/AttrNode.java | 1 + .../core/dex/attributes/IAttributeNode.java | 2 + .../jadx/core/dex/regions/SwitchRegion.java | 51 ++++++++++---- .../main/java/jadx/core/utils/DebugUtils.java | 69 +++++++++++++------ .../java/jadx/core/utils/StringUtils.java | 4 ++ 6 files changed, 98 insertions(+), 37 deletions(-) diff --git a/jadx-core/src/main/java/jadx/core/codegen/RegionGen.java b/jadx-core/src/main/java/jadx/core/codegen/RegionGen.java index 54b3c1fa8..4596d8c48 100644 --- a/jadx-core/src/main/java/jadx/core/codegen/RegionGen.java +++ b/jadx-core/src/main/java/jadx/core/codegen/RegionGen.java @@ -28,6 +28,7 @@ import jadx.core.dex.nodes.InsnNode; import jadx.core.dex.nodes.parser.FieldInitAttr; import jadx.core.dex.regions.Region; import jadx.core.dex.regions.SwitchRegion; +import jadx.core.dex.regions.SwitchRegion.CaseInfo; import jadx.core.dex.regions.SynchronizedRegion; import jadx.core.dex.regions.TryCatchRegion; import jadx.core.dex.regions.conditions.IfCondition; @@ -270,10 +271,9 @@ public class RegionGen extends InsnGen { code.add(") {"); code.incIndent(); - int size = sw.getKeys().size(); - for (int i = 0; i < size; i++) { - List keys = sw.getKeys().get(i); - IContainer c = sw.getCases().get(i); + for (CaseInfo caseInfo : sw.getCases()) { + List keys = caseInfo.getKeys(); + IContainer c = caseInfo.getContainer(); for (Object k : keys) { code.startLine("case "); if (k instanceof FieldNode) { diff --git a/jadx-core/src/main/java/jadx/core/dex/attributes/AttrNode.java b/jadx-core/src/main/java/jadx/core/dex/attributes/AttrNode.java index 4079c71a6..26dc41b71 100644 --- a/jadx-core/src/main/java/jadx/core/dex/attributes/AttrNode.java +++ b/jadx-core/src/main/java/jadx/core/dex/attributes/AttrNode.java @@ -118,6 +118,7 @@ public abstract class AttrNode implements IAttributeNode { return storage.toString(); } + @Override public boolean isAttrStorageEmpty() { return storage.isEmpty(); } diff --git a/jadx-core/src/main/java/jadx/core/dex/attributes/IAttributeNode.java b/jadx-core/src/main/java/jadx/core/dex/attributes/IAttributeNode.java index 50d70577f..b6435d5b1 100644 --- a/jadx-core/src/main/java/jadx/core/dex/attributes/IAttributeNode.java +++ b/jadx-core/src/main/java/jadx/core/dex/attributes/IAttributeNode.java @@ -35,4 +35,6 @@ public interface IAttributeNode { List getAttributesStringsList(); String getAttributesString(); + + boolean isAttrStorageEmpty(); } diff --git a/jadx-core/src/main/java/jadx/core/dex/regions/SwitchRegion.java b/jadx-core/src/main/java/jadx/core/dex/regions/SwitchRegion.java index 2ac0a44df..bbdfbcb91 100644 --- a/jadx-core/src/main/java/jadx/core/dex/regions/SwitchRegion.java +++ b/jadx-core/src/main/java/jadx/core/dex/regions/SwitchRegion.java @@ -4,33 +4,50 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import jadx.core.codegen.CodeWriter; import jadx.core.dex.nodes.BlockNode; import jadx.core.dex.nodes.IBranchRegion; import jadx.core.dex.nodes.IContainer; import jadx.core.dex.nodes.IRegion; +import jadx.core.utils.Utils; public final class SwitchRegion extends AbstractRegion implements IBranchRegion { private final BlockNode header; - private final List> keys; - private final List cases; + private final List cases; private IContainer defCase; public SwitchRegion(IRegion parent, BlockNode header) { super(parent); this.header = header; - this.keys = new ArrayList<>(); this.cases = new ArrayList<>(); } + public static final class CaseInfo { + private final List keys; + private final IContainer container; + + public CaseInfo(List keys, IContainer container) { + this.keys = keys; + this.container = container; + } + + public List getKeys() { + return keys; + } + + public IContainer getContainer() { + return container; + } + } + public BlockNode getHeader() { return header; } public void addCase(List keysList, IContainer c) { - keys.add(keysList); - cases.add(c); + cases.add(new CaseInfo(keysList, c)); } public void setDefaultCase(IContainer block) { @@ -41,19 +58,19 @@ public final class SwitchRegion extends AbstractRegion implements IBranchRegion return defCase; } - public List> getKeys() { - return keys; + public List getCases() { + return cases; } - public List getCases() { - return cases; + public List getCaseContainers() { + return Utils.collectionMap(cases, caseInfo -> caseInfo.container); } @Override public List getSubBlocks() { List all = new ArrayList<>(cases.size() + 2); all.add(header); - all.addAll(cases); + all.addAll(getCaseContainers()); if (defCase != null) { all.add(defCase); } @@ -63,7 +80,7 @@ public final class SwitchRegion extends AbstractRegion implements IBranchRegion @Override public List getBranches() { List branches = new ArrayList<>(cases.size() + 1); - branches.addAll(cases); + branches.addAll(getCaseContainers()); if (defCase != null) { branches.add(defCase); } @@ -77,6 +94,16 @@ public final class SwitchRegion extends AbstractRegion implements IBranchRegion @Override public String toString() { - return "Switch: " + cases.size() + ", default: " + defCase; + StringBuilder sb = new StringBuilder(); + sb.append("Switch: ").append(cases.size()); + for (CaseInfo caseInfo : cases) { + sb.append(CodeWriter.NL).append(" case ") + .append(Utils.listToString(caseInfo.getKeys())) + .append(" -> ").append(caseInfo.getContainer()); + } + if (defCase != null) { + sb.append(CodeWriter.NL).append(" default -> ").append(defCase); + } + return sb.toString(); } } diff --git a/jadx-core/src/main/java/jadx/core/utils/DebugUtils.java b/jadx-core/src/main/java/jadx/core/utils/DebugUtils.java index 9cb673986..16d8dbcb0 100644 --- a/jadx-core/src/main/java/jadx/core/utils/DebugUtils.java +++ b/jadx-core/src/main/java/jadx/core/utils/DebugUtils.java @@ -1,9 +1,12 @@ package jadx.core.utils; import java.io.File; +import java.util.Arrays; +import java.util.Iterator; import java.util.LinkedHashSet; -import java.util.Map; +import java.util.List; import java.util.Set; +import java.util.stream.Collectors; import org.jetbrains.annotations.TestOnly; import org.slf4j.Logger; @@ -12,6 +15,7 @@ import org.slf4j.LoggerFactory; import jadx.core.codegen.CodeWriter; import jadx.core.codegen.InsnGen; import jadx.core.codegen.MethodGen; +import jadx.core.dex.attributes.IAttributeNode; import jadx.core.dex.nodes.BlockNode; import jadx.core.dex.nodes.IBlock; import jadx.core.dex.nodes.IContainer; @@ -85,51 +89,74 @@ public class DebugUtils { printRegions(mth, false); } - public static void printRegion(MethodNode mth, IRegion region, boolean printInsn) { - printRegion(mth, region, "", printInsn); - } - public static void printRegions(MethodNode mth, boolean printInsns) { - LOG.debug("|{}", mth); - printRegion(mth, mth.getRegion(), "| ", printInsns); + printRegion(mth, mth.getRegion(), printInsns); } - private static void printRegion(MethodNode mth, IRegion region, String indent, boolean printInsns) { - LOG.debug("{}{} {}", indent, region, region.getAttributesString()); + public static void printRegion(MethodNode mth, IRegion region, boolean printInsns) { + CodeWriter cw = new CodeWriter(); + cw.startLine('|').add(mth.toString()); + printRegion(mth, region, cw, "| ", printInsns); + LOG.debug("\n{}", cw.finish().getCodeStr()); + } + + private static void printRegion(MethodNode mth, IRegion region, CodeWriter cw, String indent, boolean printInsns) { + printWithAttributes(cw, indent, region.toString(), region); indent += "| "; for (IContainer container : region.getSubBlocks()) { if (container instanceof IRegion) { - printRegion(mth, (IRegion) container, indent, printInsns); + printRegion(mth, (IRegion) container, cw, indent, printInsns); } else { - LOG.debug("{}{} {}", indent, container, container.getAttributesString()); + printWithAttributes(cw, indent, container.toString(), container); if (printInsns && container instanceof IBlock) { IBlock block = (IBlock) container; - printInsns(mth, indent, block); + printInsns(mth, cw, indent, block); } } } } - private static void printInsns(MethodNode mth, String indent, IBlock block) { + private static void printInsns(MethodNode mth, CodeWriter cw, String indent, IBlock block) { for (InsnNode insn : block.getInstructions()) { try { MethodGen mg = MethodGen.getFallbackMethodGen(mth); InsnGen ig = new InsnGen(mg, true); CodeWriter code = new CodeWriter(); ig.makeInsn(insn, code); - String insnStr = code.toString().substring(CodeWriter.NL.length()); - String attrStr = insn.isAttrStorageEmpty() ? "" : '\t' + insn.getAttributesString(); - LOG.debug("{}|> {}{}", indent, insnStr, attrStr); + String codeStr = code.finish().getCodeStr(); + + List insnStrings = Arrays.stream(codeStr.split(CodeWriter.NL)) + .filter(StringUtils::notBlank) + .map(s -> "|> " + s) + .collect(Collectors.toList()); + Iterator it = insnStrings.iterator(); + while (true) { + String insnStr = it.next(); + if (it.hasNext()) { + cw.startLine(indent).add(insnStr); + } else { + printWithAttributes(cw, indent, insnStr, insn); + break; + } + } } catch (CodegenException e) { - LOG.debug("{}|>!! {}", indent, insn); + cw.startLine(indent).add(">!! ").add(insn.toString()); } } } - public static void printMap(String desc, Map map) { - LOG.debug("Map of {}, size: {}", desc, map.size()); - for (Map.Entry entry : map.entrySet()) { - LOG.debug(" {} : {}", entry.getKey(), entry.getValue()); + private static void printWithAttributes(CodeWriter cw, String indent, String codeStr, IAttributeNode attrNode) { + String str = attrNode.isAttrStorageEmpty() ? codeStr : codeStr + ' ' + attrNode.getAttributesString(); + List attrStrings = Arrays.stream(str.split(CodeWriter.NL)) + .filter(StringUtils::notBlank) + .collect(Collectors.toList()); + Iterator it = attrStrings.iterator(); + if (!it.hasNext()) { + return; + } + cw.startLine(indent).add(it.next()); + while (it.hasNext()) { + cw.startLine(indent).add("|+ ").add(it.next()); } } } diff --git a/jadx-core/src/main/java/jadx/core/utils/StringUtils.java b/jadx-core/src/main/java/jadx/core/utils/StringUtils.java index f5643871c..896eb446f 100644 --- a/jadx-core/src/main/java/jadx/core/utils/StringUtils.java +++ b/jadx-core/src/main/java/jadx/core/utils/StringUtils.java @@ -211,6 +211,10 @@ public class StringUtils { return str == null || str.isEmpty(); } + public static boolean notBlank(String str) { + return notEmpty(str) && !str.trim().isEmpty(); + } + public static int countMatches(String str, String subStr) { if (str == null || str.isEmpty() || subStr == null || subStr.isEmpty()) { return 0;