Skip to content

Commit

Permalink
fix: implement new type inference approach
Browse files Browse the repository at this point in the history
  • Loading branch information
skylot committed Dec 1, 2018
1 parent 6d59f77 commit 21e11c1
Show file tree
Hide file tree
Showing 94 changed files with 3,067 additions and 1,546 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,4 @@ jadx-output/
*.dump
*.log
*.cfg
*.orig
4 changes: 4 additions & 0 deletions jadx-core/src/main/java/jadx/api/JadxDecompiler.java
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,10 @@ RootNode getRoot() {
return root;
}

List<IDexTreeVisitor> getPasses() {
return passes;
}

synchronized BinaryXMLParser getXmlParser() {
if (xmlParser == null) {
xmlParser = new BinaryXMLParser(root);
Expand Down
25 changes: 12 additions & 13 deletions jadx-core/src/main/java/jadx/core/Jadx.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import jadx.core.dex.visitors.ClassModifier;
import jadx.core.dex.visitors.CodeShrinker;
import jadx.core.dex.visitors.ConstInlineVisitor;
import jadx.core.dex.visitors.DebugInfoVisitor;
import jadx.core.dex.visitors.ConstructorVisitor;
import jadx.core.dex.visitors.DependencyCollector;
import jadx.core.dex.visitors.DotGraphVisitor;
import jadx.core.dex.visitors.EnumVisitor;
Expand All @@ -31,6 +31,8 @@
import jadx.core.dex.visitors.blocksmaker.BlockFinish;
import jadx.core.dex.visitors.blocksmaker.BlockProcessor;
import jadx.core.dex.visitors.blocksmaker.BlockSplitter;
import jadx.core.dex.visitors.debuginfo.DebugInfoApplyVisitor;
import jadx.core.dex.visitors.debuginfo.DebugInfoParseVisitor;
import jadx.core.dex.visitors.regions.CheckRegions;
import jadx.core.dex.visitors.regions.IfRegionVisitor;
import jadx.core.dex.visitors.regions.LoopRegionVisitor;
Expand All @@ -39,8 +41,7 @@
import jadx.core.dex.visitors.regions.ReturnVisitor;
import jadx.core.dex.visitors.ssa.EliminatePhiNodes;
import jadx.core.dex.visitors.ssa.SSATransform;
import jadx.core.dex.visitors.typeinference.FinishTypeInference;
import jadx.core.dex.visitors.typeinference.TypeInference;
import jadx.core.dex.visitors.typeinference.TypeInferenceVisitor;

public class Jadx {
private static final Logger LOG = LoggerFactory.getLogger(Jadx.class);
Expand All @@ -59,29 +60,27 @@ public static List<IDexTreeVisitor> getPassesList(JadxArgs args) {
if (args.isFallbackMode()) {
passes.add(new FallbackModeVisitor());
} else {
passes.add(new DebugInfoParseVisitor());
passes.add(new BlockSplitter());
if (args.isRawCFGOutput()) {
passes.add(DotGraphVisitor.dumpRaw());
}

passes.add(new BlockProcessor());
passes.add(new BlockExceptionHandler());
passes.add(new BlockFinallyExtract());
passes.add(new BlockFinish());

passes.add(new SSATransform());
passes.add(new DebugInfoVisitor());
passes.add(new TypeInference());

if (args.isRawCFGOutput()) {
passes.add(DotGraphVisitor.dumpRaw());
}

passes.add(new ConstructorVisitor());
passes.add(new ConstInlineVisitor());
passes.add(new FinishTypeInference());
passes.add(new TypeInferenceVisitor());
passes.add(new EliminatePhiNodes());
passes.add(new DebugInfoApplyVisitor());

passes.add(new ModVisitor());

passes.add(new CodeShrinker());
passes.add(new ReSugarCode());

if (args.isCfgOutput()) {
passes.add(DotGraphVisitor.dump());
}
Expand Down
6 changes: 5 additions & 1 deletion jadx-core/src/main/java/jadx/core/clsp/ClspGraph.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
public class ClspGraph {
private static final Logger LOG = LoggerFactory.getLogger(ClspGraph.class);

private final Map<String, Set<String>> ancestorCache = Collections.synchronizedMap(new WeakHashMap<String, Set<String>>());
private final Map<String, Set<String>> ancestorCache = Collections.synchronizedMap(new WeakHashMap<>());
private Map<String, NClass> nameMap;

private final Set<String> missingClasses = new HashSet<>();
Expand Down Expand Up @@ -58,6 +58,10 @@ public void addApp(List<ClassNode> classes) {
}
}

public boolean isClsKnown(String fullName) {
return nameMap.containsKey(fullName);
}

private NClass addClass(ClassNode cls) {
String rawName = cls.getRawName();
NClass nClass = new NClass(rawName, -1);
Expand Down
15 changes: 1 addition & 14 deletions jadx-core/src/main/java/jadx/core/codegen/InsnGen.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package jadx.core.codegen;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.Iterator;
import java.util.List;
Expand Down Expand Up @@ -484,19 +483,7 @@ private void makeInsnBody(CodeWriter code, InsnNode insn, Set<Flags> state) thro
case FILL_ARRAY:
fallbackOnlyInsn(insn);
FillArrayNode arrayNode = (FillArrayNode) insn;
Object data = arrayNode.getData();
String arrStr;
if (data instanceof int[]) {
arrStr = Arrays.toString((int[]) data);
} else if (data instanceof short[]) {
arrStr = Arrays.toString((short[]) data);
} else if (data instanceof byte[]) {
arrStr = Arrays.toString((byte[]) data);
} else if (data instanceof long[]) {
arrStr = Arrays.toString((long[]) data);
} else {
arrStr = "?";
}
String arrStr = arrayNode.dataToString();
code.add('{').add(arrStr.substring(1, arrStr.length() - 1)).add('}');
break;

Expand Down
10 changes: 5 additions & 5 deletions jadx-core/src/main/java/jadx/core/codegen/MethodGen.java
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ private void addMethodArguments(CodeWriter argsCode, List<RegisterArg> args) {
int i = 0;
for (Iterator<RegisterArg> it = args.iterator(); it.hasNext(); ) {
RegisterArg arg = it.next();
ArgType argType = arg.getInitType();

// add argument annotation
if (paramsAnnotation != null) {
Expand All @@ -135,17 +136,16 @@ private void addMethodArguments(CodeWriter argsCode, List<RegisterArg> args) {
}
if (!it.hasNext() && mth.getAccessFlags().isVarArgs()) {
// change last array argument to varargs
ArgType type = arg.getType();
if (type.isArray()) {
ArgType elType = type.getArrayElement();
if (argType.isArray()) {
ArgType elType = argType.getArrayElement();
classGen.useType(argsCode, elType);
argsCode.add("...");
} else {
LOG.warn(ErrorsCounter.formatMsg(mth, "Last argument in varargs method not array"));
classGen.useType(argsCode, arg.getType());
classGen.useType(argsCode, argType);
}
} else {
classGen.useType(argsCode, arg.getType());
classGen.useType(argsCode, argType);
}
argsCode.add(' ');
argsCode.add(nameGen.assignArg(arg));
Expand Down
23 changes: 20 additions & 3 deletions jadx-core/src/main/java/jadx/core/codegen/NameGen.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ public class NameGen {
OBJ_ALIAS.put("java.lang.Float", "f");
OBJ_ALIAS.put("java.lang.Long", "l");
OBJ_ALIAS.put("java.lang.Double", "d");
OBJ_ALIAS.put("java.lang.StringBuilder", "sb");
}

public NameGen(MethodNode mth, boolean fallback) {
Expand Down Expand Up @@ -108,13 +109,22 @@ private String makeArgName(RegisterArg arg) {
String name = arg.getName();
String varName = name != null ? name : guessName(arg);
if (NameMapper.isReserved(varName)) {
return varName + "R";
varName = varName + "R";
}
if (!NameMapper.isValidIdentifier(varName)) {
varName = getFallbackName(arg);
}
return varName;
}

private String getFallbackName(RegisterArg arg) {
return "r" + arg.getRegNum();
StringBuilder sb = new StringBuilder();
sb.append('r').append(arg.getRegNum());
SSAVar sVar = arg.getSVar();
if (sVar != null) {
sb.append('v').append(sVar.getVersion());
}
return sb.toString();
}

private String guessName(RegisterArg arg) {
Expand All @@ -130,7 +140,11 @@ private String guessName(RegisterArg arg) {
}
}
}
return makeNameForType(arg.getType());
ArgType type = arg.getType();
if (!type.isTypeKnown() && arg.getInitType().isTypeKnown()) {
type = arg.getInitType();
}
return makeNameForType(type);
}

private String makeNameForType(ArgType type) {
Expand Down Expand Up @@ -236,6 +250,9 @@ private String makeNameFromInvoke(MethodInfo callMth) {
if ("forName".equals(name) && declType.equals(ArgType.CLASS)) {
return OBJ_ALIAS.get(Consts.CLASS_CLASS);
}
if (name.startsWith("to")) {
return fromName(name.substring(2));
}
return name;
}
}
13 changes: 10 additions & 3 deletions jadx-core/src/main/java/jadx/core/codegen/TypeGen.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,16 @@ private static String literalToString(long lit, ArgType type, StringUtils string
if (type == null || !type.isTypeKnown()) {
String n = Long.toString(lit);
if (Math.abs(lit) > 100) {
n += "; // 0x" + Long.toHexString(lit)
+ " float:" + Float.intBitsToFloat((int) lit)
+ " double:" + Double.longBitsToDouble(lit);
StringBuilder sb = new StringBuilder();
sb.append(n).append("(0x").append(Long.toHexString(lit));
if (type == null || type.contains(PrimitiveType.FLOAT)) {
sb.append(", float:").append(Float.intBitsToFloat((int) lit));
}
if (type == null || type.contains(PrimitiveType.DOUBLE)) {
sb.append(", double:").append(Double.longBitsToDouble(lit));
}
sb.append(')');
return sb.toString();
}
return n;
}
Expand Down
8 changes: 8 additions & 0 deletions jadx-core/src/main/java/jadx/core/dex/attributes/AType.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@
import jadx.core.dex.attributes.nodes.JadxError;
import jadx.core.dex.attributes.nodes.JadxWarn;
import jadx.core.dex.attributes.nodes.JumpInfo;
import jadx.core.dex.attributes.nodes.LocalVarsDebugInfoAttr;
import jadx.core.dex.attributes.nodes.LoopInfo;
import jadx.core.dex.attributes.nodes.LoopLabelAttr;
import jadx.core.dex.attributes.nodes.MethodInlineAttr;
import jadx.core.dex.attributes.nodes.PhiListAttr;
import jadx.core.dex.attributes.nodes.RegDebugInfoAttr;
import jadx.core.dex.attributes.nodes.SourceFileAttr;
import jadx.core.dex.nodes.parser.FieldInitAttr;
import jadx.core.dex.trycatch.CatchAttr;
Expand Down Expand Up @@ -55,6 +57,12 @@ public class AType<T extends IAttribute> {
public static final AType<LoopLabelAttr> LOOP_LABEL = new AType<>();
public static final AType<IgnoreEdgeAttr> IGNORE_EDGE = new AType<>();

// method
public static final AType<LocalVarsDebugInfoAttr> LOCAL_VARS_DEBUG_INFO = new AType<>();

// registers
public static final AType<RegDebugInfoAttr> REG_DEBUG_INFO = new AType<>();

private AType() {
}
}
10 changes: 10 additions & 0 deletions jadx-core/src/main/java/jadx/core/dex/attributes/AttrNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ private AttributeStorage initStorage() {
return store;
}

private void unloadIfEmpty() {
if (storage.isEmpty() && storage != EMPTY_ATTR_STORAGE) {
storage = EMPTY_ATTR_STORAGE;
}
}

@Override
public boolean contains(AFlag flag) {
return storage.contains(flag);
Expand Down Expand Up @@ -70,21 +76,25 @@ public <T> List<T> getAll(AType<AttrList<T>> type) {
@Override
public void remove(AFlag flag) {
storage.remove(flag);
unloadIfEmpty();
}

@Override
public <T extends IAttribute> void remove(AType<T> type) {
storage.remove(type);
unloadIfEmpty();
}

@Override
public void removeAttr(IAttribute attr) {
storage.remove(attr);
unloadIfEmpty();
}

@Override
public void clearAttributes() {
storage.clear();
unloadIfEmpty();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,6 @@ public String toString() {
if (list.isEmpty()) {
return "";
}
return "A:{" + Utils.listToString(list) + "}";
return "A[" + Utils.listToString(list) + "]";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package jadx.core.dex.attributes.nodes;

import java.util.List;

import jadx.core.dex.attributes.AType;
import jadx.core.dex.attributes.IAttribute;
import jadx.core.dex.visitors.debuginfo.LocalVar;
import jadx.core.utils.Utils;

public class LocalVarsDebugInfoAttr implements IAttribute {
private final List<LocalVar> localVars;

public LocalVarsDebugInfoAttr(List<LocalVar> localVars) {
this.localVars = localVars;
}

public List<LocalVar> getLocalVars() {
return localVars;
}

@Override
public AType<LocalVarsDebugInfoAttr> getType() {
return AType.LOCAL_VARS_DEBUG_INFO;
}

@Override
public String toString() {
return "Debug Info:\n " + Utils.listToString(localVars, "\n ");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package jadx.core.dex.attributes.nodes;

import java.util.Objects;

import jadx.core.dex.attributes.AType;
import jadx.core.dex.attributes.IAttribute;
import jadx.core.dex.instructions.args.ArgType;
import jadx.core.dex.visitors.debuginfo.LocalVar;

public class RegDebugInfoAttr implements IAttribute {

private final ArgType type;
private final String name;

public RegDebugInfoAttr(LocalVar var) {
this(var.getType(), var.getName());
}

public RegDebugInfoAttr(ArgType type, String name) {
this.type = type;
this.name = name;
}

public String getName() {
return name;
}

public ArgType getRegType() {
return type;
}

@Override
public AType getType() {
return AType.REG_DEBUG_INFO;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
RegDebugInfoAttr that = (RegDebugInfoAttr) o;
return Objects.equals(type, that.type) && Objects.equals(name, that.name);
}

@Override
public int hashCode() {
return Objects.hash(type, name);
}

@Override
public String toString() {
return "D('" + name + "' " + type + ")";
}
}
Loading

0 comments on commit 21e11c1

Please sign in to comment.