Skip to content

Commit

Permalink
fix: checks for casts in field access, move method inline to visitor (#…
Browse files Browse the repository at this point in the history
…962)

Signed-off-by: Skylot <skylot@gmail.com>
  • Loading branch information
skylot committed Sep 7, 2020
1 parent 89b4ae6 commit 691bf8f
Show file tree
Hide file tree
Showing 15 changed files with 373 additions and 114 deletions.
1 change: 1 addition & 0 deletions jadx-core/src/main/java/jadx/core/Consts.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

public class Consts {
public static final boolean DEBUG = false;
public static final boolean DEBUG_WITH_ERRORS = false; // TODO: fix errors
public static final boolean DEBUG_USAGE = false;
public static final boolean DEBUG_TYPE_INFERENCE = false;
public static final boolean DEBUG_OVERLOADED_CASTS = false;
Expand Down
7 changes: 5 additions & 2 deletions jadx-core/src/main/java/jadx/core/Jadx.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@
import jadx.core.dex.visitors.GenericTypesVisitor;
import jadx.core.dex.visitors.IDexTreeVisitor;
import jadx.core.dex.visitors.InitCodeVariables;
import jadx.core.dex.visitors.InlineMethods;
import jadx.core.dex.visitors.MarkFinallyVisitor;
import jadx.core.dex.visitors.MethodInlineVisitor;
import jadx.core.dex.visitors.MarkMethodsForInline;
import jadx.core.dex.visitors.MethodInvokeVisitor;
import jadx.core.dex.visitors.ModVisitor;
import jadx.core.dex.visitors.MoveInlineVisitor;
Expand Down Expand Up @@ -119,6 +120,7 @@ public static List<IDexTreeVisitor> getPassesList(JadxArgs args) {
passes.add(new DebugInfoApplyVisitor());
}

passes.add(new InlineMethods());
passes.add(new GenericTypesVisitor());
passes.add(new ShadowFieldVisitor());
passes.add(new DeboxingVisitor());
Expand All @@ -144,9 +146,10 @@ public static List<IDexTreeVisitor> getPassesList(JadxArgs args) {
passes.add(new FixAccessModifiers());
passes.add(new ProcessAnonymous());
passes.add(new ClassModifier());
passes.add(new MethodInlineVisitor());
passes.add(new LoopRegionVisitor());

passes.add(new MarkMethodsForInline());

passes.add(new ProcessVariables());
passes.add(new PrepareForCodeGen());
if (args.isCfgOutput()) {
Expand Down
6 changes: 5 additions & 1 deletion jadx-core/src/main/java/jadx/core/ProcessClass.java
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,11 @@ public static ICodeInfo generateCode(ClassNode cls) {
cls.setState(NOT_LOADED);
}
try {
cls.getDependencies().forEach(ProcessClass::process);
for (ClassNode depCls : cls.getDependencies()) {
depCls.startProcessStage();
process(depCls);
}
cls.startCodegenStage();
process(cls);

ICodeInfo code = CodeGen.generate(cls);
Expand Down
67 changes: 0 additions & 67 deletions jadx-core/src/main/java/jadx/core/codegen/InsnGen.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package jadx.core.codegen;

import java.util.ArrayList;
import java.util.EnumSet;
import java.util.Iterator;
import java.util.List;
Expand All @@ -10,14 +9,12 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import jadx.core.Consts;
import jadx.core.deobf.NameMapper;
import jadx.core.dex.attributes.AFlag;
import jadx.core.dex.attributes.AType;
import jadx.core.dex.attributes.nodes.FieldReplaceAttr;
import jadx.core.dex.attributes.nodes.GenericInfoAttr;
import jadx.core.dex.attributes.nodes.LoopLabelAttr;
import jadx.core.dex.attributes.nodes.MethodInlineAttr;
import jadx.core.dex.attributes.nodes.SkipMethodArgsAttr;
import jadx.core.dex.info.ClassInfo;
import jadx.core.dex.info.FieldInfo;
Expand All @@ -43,7 +40,6 @@
import jadx.core.dex.instructions.args.InsnWrapArg;
import jadx.core.dex.instructions.args.LiteralArg;
import jadx.core.dex.instructions.args.Named;
import jadx.core.dex.instructions.args.NamedArg;
import jadx.core.dex.instructions.args.RegisterArg;
import jadx.core.dex.instructions.args.SSAVar;
import jadx.core.dex.instructions.mods.ConstructorInsn;
Expand Down Expand Up @@ -705,12 +701,7 @@ private void inlineAnonymousConstructor(CodeWriter code, ClassNode cls, Construc

private void makeInvoke(InvokeNode insn, CodeWriter code) throws CodegenException {
MethodInfo callMth = insn.getCallMth();

// inline method
MethodNode callMthNode = mth.root().deepResolveMethod(callMth);
if (callMthNode != null && inlineMethod(callMthNode, insn, code)) {
return;
}

int k = 0;
InvokeType type = insn.getInvokeType();
Expand Down Expand Up @@ -844,64 +835,6 @@ private boolean processVarArg(CodeWriter code, BaseInvokeNode invokeInsn, InsnAr
return true;
}

private boolean inlineMethod(MethodNode callMthNode, InvokeNode insn, CodeWriter code) throws CodegenException {
MethodInlineAttr mia = callMthNode.get(AType.METHOD_INLINE);
if (mia == null) {
return false;
}
InsnNode inl = mia.getInsn();
if (Consts.DEBUG) {
code.add("/* inline method: ").add(callMthNode.toString()).add("*/").startLine();
}
if (forceAssign(inl, insn, callMthNode)) {
ArgType varType = callMthNode.getReturnType();
useType(code, varType);
code.add(' ');
code.add(mgen.getNameGen().assignNamedArg(new NamedArg("unused", varType)));
code.add(" = ");
}
if (callMthNode.getMethodInfo().getArgumentsTypes().isEmpty()) {
makeInsn(inl, code, Flags.BODY_ONLY);
} else {
// remap args
InsnArg[] regs = new InsnArg[callMthNode.getRegsCount()];
int[] regNums = mia.getArgsRegNums();
for (int i = 0; i < regNums.length; i++) {
InsnArg arg = insn.getArg(i);
regs[regNums[i]] = arg;
}
// replace args
InsnNode inlCopy = inl.copyWithoutResult();
List<RegisterArg> inlArgs = new ArrayList<>();
inlCopy.getRegisterArgs(inlArgs);
for (RegisterArg r : inlArgs) {
int regNum = r.getRegNum();
if (regNum >= regs.length) {
LOG.warn("Unknown register number {} in method call: {} from {}", r, callMthNode, mth);
} else {
InsnArg repl = regs[regNum];
if (repl == null) {
LOG.warn("Not passed register {} in method call: {} from {}", r, callMthNode, mth);
} else {
inlCopy.replaceArg(r, repl);
}
}
}
makeInsn(inlCopy, code, Flags.BODY_ONLY);
}
return true;
}

private boolean forceAssign(InsnNode inlineInsn, InvokeNode parentInsn, MethodNode callMthNode) {
if (parentInsn.getResult() != null) {
return false;
}
if (parentInsn.contains(AFlag.WRAPPED)) {
return false;
}
return !callMthNode.isVoidReturn();
}

private void makeTernary(TernaryInsn insn, CodeWriter code, Set<Flags> state) throws CodegenException {
boolean wrap = state.contains(Flags.BODY_ONLY);
if (wrap) {
Expand Down
4 changes: 3 additions & 1 deletion jadx-core/src/main/java/jadx/core/dex/attributes/AFlag.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ public enum AFlag {

HIDDEN, // instruction used inside other instruction but not listed in args

RESTART_CODEGEN,
RESTART_CODEGEN, // codegen must be executed again
RELOAD_AT_CODEGEN_STAGE, // class can't be analyzed at 'process' stage => unload before 'codegen' stage

DONT_RENAME, // do not rename during deobfuscation
ADDED_TO_REGION,

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package jadx.core.dex.attributes.nodes;

import java.util.List;
import java.util.Objects;

import jadx.core.Consts;
import jadx.core.dex.attributes.AFlag;
import jadx.core.dex.attributes.AType;
import jadx.core.dex.attributes.IAttribute;
import jadx.core.dex.instructions.args.RegisterArg;
Expand All @@ -10,15 +13,30 @@

public class MethodInlineAttr implements IAttribute {

public static void markForInline(MethodNode mth, InsnNode replaceInsn) {
private static final MethodInlineAttr INLINE_NOT_NEEDED = new MethodInlineAttr(null, null);

public static MethodInlineAttr markForInline(MethodNode mth, InsnNode replaceInsn) {
Objects.requireNonNull(replaceInsn);
List<RegisterArg> allArgRegs = mth.getAllArgRegs();
int argsCount = allArgRegs.size();
int[] regNums = new int[argsCount];
for (int i = 0; i < argsCount; i++) {
RegisterArg reg = allArgRegs.get(i);
regNums[i] = reg.getRegNum();
}
mth.addAttr(new MethodInlineAttr(replaceInsn, regNums));
MethodInlineAttr mia = new MethodInlineAttr(replaceInsn, regNums);
mth.addAttr(mia);
if (Consts.DEBUG) {
mth.addAttr(AType.COMMENTS, "Removed for inline");
} else {
mth.add(AFlag.DONT_GENERATE);
}
return mia;
}

public static MethodInlineAttr inlineNotNeeded(MethodNode mth) {
mth.addAttr(INLINE_NOT_NEEDED);
return INLINE_NOT_NEEDED;
}

private final InsnNode insn;
Expand All @@ -33,6 +51,10 @@ private MethodInlineAttr(InsnNode insn, int[] argsRegNums) {
this.argsRegNums = argsRegNums;
}

public boolean notNeeded() {
return insn == null;
}

public InsnNode getInsn() {
return insn;
}
Expand All @@ -48,6 +70,9 @@ public AType<MethodInlineAttr> getType() {

@Override
public String toString() {
if (notNeeded()) {
return "INLINE_NOT_NEEDED";
}
return "INLINE: " + insn;
}
}
27 changes: 27 additions & 0 deletions jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ public class ClassNode extends NotificationAttrNode implements ILoadable, ICodeN
private ClassNode parentClass;

private volatile ProcessState state = ProcessState.NOT_LOADED;
private LoadStage loadStage = LoadStage.NONE;

/** Top level classes used in this class (only for top level classes, empty for inners) */
private List<ClassNode> dependencies = Collections.emptyList();
Expand Down Expand Up @@ -288,6 +289,7 @@ public void unload() {
fields.forEach(FieldNode::unloadAttributes);
unloadAttributes();
setState(NOT_LOADED);
this.loadStage = LoadStage.NONE;
this.smali = null;
}

Expand Down Expand Up @@ -577,6 +579,30 @@ public void setState(ProcessState state) {
this.state = state;
}

public LoadStage getLoadStage() {
return loadStage;
}

public void startProcessStage() {
this.loadStage = LoadStage.PROCESS_STAGE;
}

public void startCodegenStage() {
this.loadStage = LoadStage.CODEGEN_STAGE;
if (contains(AFlag.RELOAD_AT_CODEGEN_STAGE)) {
unload();
remove(AFlag.RELOAD_AT_CODEGEN_STAGE);
}
}

public void reloadAtCodegenStage() {
ClassNode topCls = this.getTopParentClass();
if (topCls.getLoadStage() == LoadStage.CODEGEN_STAGE) {
throw new JadxRuntimeException("Class not yet loaded at codegen stage");
}
topCls.add(AFlag.RELOAD_AT_CODEGEN_STAGE);
}

public List<ClassNode> getDependencies() {
return dependencies;
}
Expand Down Expand Up @@ -632,4 +658,5 @@ public int compareTo(@NotNull ClassNode o) {
public String toString() {
return clsInfo.getFullName();
}

}
7 changes: 7 additions & 0 deletions jadx-core/src/main/java/jadx/core/dex/nodes/LoadStage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package jadx.core.dex.nodes;

public enum LoadStage {
NONE,
PROCESS_STAGE, // dependencies not yet loaded
CODEGEN_STAGE, // all dependencies loaded
}
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ private int fixClassVisibility(ClassNode cls) {
if (!accessFlags.isPublic()) {
// if class is used in inlinable method => make it public
for (MethodNode useMth : cls.getUseInMth()) {
boolean canInline = MethodInlineVisitor.canInline(useMth) || useMth.contains(AType.METHOD_INLINE);
boolean canInline = MarkMethodsForInline.canInline(useMth) || useMth.contains(AType.METHOD_INLINE);
if (canInline && !useMth.getUseIn().isEmpty()) {
return AccessFlags.PUBLIC;
}
Expand Down
Loading

0 comments on commit 691bf8f

Please sign in to comment.