refactor: small changes to switch region and region debug print

This commit is contained in:
Skylot
2020-01-13 15:30:12 +03:00
parent 531650c9f2
commit 7bbb083c36
6 changed files with 98 additions and 37 deletions
@@ -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<Object> keys = sw.getKeys().get(i);
IContainer c = sw.getCases().get(i);
for (CaseInfo caseInfo : sw.getCases()) {
List<Object> keys = caseInfo.getKeys();
IContainer c = caseInfo.getContainer();
for (Object k : keys) {
code.startLine("case ");
if (k instanceof FieldNode) {
@@ -118,6 +118,7 @@ public abstract class AttrNode implements IAttributeNode {
return storage.toString();
}
@Override
public boolean isAttrStorageEmpty() {
return storage.isEmpty();
}
@@ -35,4 +35,6 @@ public interface IAttributeNode {
List<String> getAttributesStringsList();
String getAttributesString();
boolean isAttrStorageEmpty();
}
@@ -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<List<Object>> keys;
private final List<IContainer> cases;
private final List<CaseInfo> 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<Object> keys;
private final IContainer container;
public CaseInfo(List<Object> keys, IContainer container) {
this.keys = keys;
this.container = container;
}
public List<Object> getKeys() {
return keys;
}
public IContainer getContainer() {
return container;
}
}
public BlockNode getHeader() {
return header;
}
public void addCase(List<Object> 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<List<Object>> getKeys() {
return keys;
public List<CaseInfo> getCases() {
return cases;
}
public List<IContainer> getCases() {
return cases;
public List<IContainer> getCaseContainers() {
return Utils.collectionMap(cases, caseInfo -> caseInfo.container);
}
@Override
public List<IContainer> getSubBlocks() {
List<IContainer> 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<IContainer> getBranches() {
List<IContainer> 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();
}
}
@@ -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<String> insnStrings = Arrays.stream(codeStr.split(CodeWriter.NL))
.filter(StringUtils::notBlank)
.map(s -> "|> " + s)
.collect(Collectors.toList());
Iterator<String> 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<String> attrStrings = Arrays.stream(str.split(CodeWriter.NL))
.filter(StringUtils::notBlank)
.collect(Collectors.toList());
Iterator<String> it = attrStrings.iterator();
if (!it.hasNext()) {
return;
}
cw.startLine(indent).add(it.next());
while (it.hasNext()) {
cw.startLine(indent).add("|+ ").add(it.next());
}
}
}
@@ -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;