core: split const-string and const-class instructions
This commit is contained in:
@@ -355,6 +355,10 @@ public class ClassGen {
|
||||
if (isInner(classInfo, cls.getClassInfo()))
|
||||
return shortName;
|
||||
|
||||
// don't add import if this class from same package
|
||||
if(classInfo.getPackage().equals(cls.getPackage()))
|
||||
return shortName;
|
||||
|
||||
for (ClassInfo cls : imports) {
|
||||
if (!cls.equals(classInfo)) {
|
||||
if (cls.getShortName().equals(shortName))
|
||||
|
||||
@@ -5,16 +5,12 @@ import jadx.core.dex.nodes.ClassNode;
|
||||
import jadx.core.dex.visitors.AbstractVisitor;
|
||||
import jadx.core.utils.exceptions.CodegenException;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class CodeGen extends AbstractVisitor {
|
||||
|
||||
private final File dir;
|
||||
private final IJadxArgs args;
|
||||
|
||||
public CodeGen(IJadxArgs args) {
|
||||
this.args = args;
|
||||
this.dir = args.getOutDir();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -8,6 +8,8 @@ import jadx.core.dex.info.FieldInfo;
|
||||
import jadx.core.dex.info.MethodInfo;
|
||||
import jadx.core.dex.instructions.ArithNode;
|
||||
import jadx.core.dex.instructions.ArithOp;
|
||||
import jadx.core.dex.instructions.ConstClassInsn;
|
||||
import jadx.core.dex.instructions.ConstStringInsn;
|
||||
import jadx.core.dex.instructions.FillArrayOp;
|
||||
import jadx.core.dex.instructions.GotoNode;
|
||||
import jadx.core.dex.instructions.IfNode;
|
||||
@@ -181,18 +183,19 @@ public class InsnGen {
|
||||
|
||||
private void makeInsnBody(CodeWriter code, InsnNode insn, EnumSet<InsnGenState> state) throws CodegenException {
|
||||
switch (insn.getType()) {
|
||||
case CONST_STR:
|
||||
String str = ((ConstStringInsn) insn).getString();
|
||||
code.add(StringUtils.unescapeString(str));
|
||||
break;
|
||||
|
||||
case CONST_CLASS:
|
||||
ArgType clsType = ((ConstClassInsn) insn).getClsType();
|
||||
code.add(useType(clsType)).add(".class");
|
||||
break;
|
||||
|
||||
case CONST:
|
||||
if (insn.getArgsCount() == 0) {
|
||||
// const in 'index' - string or class
|
||||
Object ind = ((IndexInsnNode) insn).getIndex();
|
||||
if (ind instanceof String)
|
||||
code.add(StringUtils.unescapeString(ind.toString()));
|
||||
else if (ind instanceof ArgType)
|
||||
code.add(useType((ArgType) ind)).add(".class");
|
||||
} else {
|
||||
LiteralArg arg = (LiteralArg) insn.getArg(0);
|
||||
code.add(lit(arg));
|
||||
}
|
||||
LiteralArg arg = (LiteralArg) insn.getArg(0);
|
||||
code.add(lit(arg));
|
||||
break;
|
||||
|
||||
case MOVE:
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
package jadx.core.dex.instructions;
|
||||
|
||||
import jadx.core.dex.instructions.args.ArgType;
|
||||
import jadx.core.dex.nodes.InsnNode;
|
||||
|
||||
public class ConstClassInsn extends InsnNode {
|
||||
|
||||
private final ArgType clsType;
|
||||
|
||||
public ConstClassInsn(ArgType clsType) {
|
||||
super(InsnType.CONST_CLASS, 0);
|
||||
this.clsType = clsType;
|
||||
}
|
||||
|
||||
public ArgType getClsType() {
|
||||
return clsType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString() + " " + clsType;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package jadx.core.dex.instructions;
|
||||
|
||||
import jadx.core.dex.nodes.InsnNode;
|
||||
|
||||
public class ConstStringInsn extends InsnNode {
|
||||
|
||||
private final String str;
|
||||
|
||||
public ConstStringInsn(String str) {
|
||||
super(InsnType.CONST_STR, 0);
|
||||
this.str = str;
|
||||
}
|
||||
|
||||
public String getString() {
|
||||
return str;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString() + " \"" + str + "\"";
|
||||
}
|
||||
}
|
||||
@@ -96,13 +96,13 @@ public class InsnDecoder {
|
||||
|
||||
case Opcodes.CONST_STRING:
|
||||
case Opcodes.CONST_STRING_JUMBO: {
|
||||
InsnNode node = new IndexInsnNode(InsnType.CONST, dex.getString(insn.getIndex()), 0);
|
||||
InsnNode node = new ConstStringInsn(dex.getString(insn.getIndex()));
|
||||
node.setResult(InsnArg.reg(insn, 0, ArgType.STRING));
|
||||
return node;
|
||||
}
|
||||
|
||||
case Opcodes.CONST_CLASS: {
|
||||
InsnNode node = new IndexInsnNode(InsnType.CONST, dex.getType(insn.getIndex()), 0);
|
||||
InsnNode node = new ConstClassInsn(dex.getType(insn.getIndex()));
|
||||
node.setResult(InsnArg.reg(insn, 0, ArgType.CLASS));
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ public enum InsnType {
|
||||
NOP, // replacement for removed instructions
|
||||
|
||||
CONST,
|
||||
CONST_STR,
|
||||
CONST_CLASS,
|
||||
|
||||
ARITH,
|
||||
NEG,
|
||||
|
||||
@@ -64,10 +64,27 @@ public abstract class InsnArg extends Typed {
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (parentInsn.getArg(i) == this) {
|
||||
InsnArg arg;
|
||||
if (insn.getType() == InsnType.MOVE) {
|
||||
arg = insn.getArg(0);
|
||||
} else {
|
||||
arg = wrap(insn);
|
||||
InsnType insnType = insn.getType();
|
||||
switch (insnType) {
|
||||
case MOVE:
|
||||
case CONST:
|
||||
arg = insn.getArg(0);
|
||||
String name = insn.getResult().getTypedVar().getName();
|
||||
if (name != null) {
|
||||
arg.getTypedVar().setName(name);
|
||||
}
|
||||
break;
|
||||
case CONST_STR:
|
||||
arg = wrap(insn);
|
||||
arg.getTypedVar().forceSetType(ArgType.STRING);
|
||||
break;
|
||||
case CONST_CLASS:
|
||||
arg = wrap(insn);
|
||||
arg.getTypedVar().forceSetType(ArgType.CLASS);
|
||||
break;
|
||||
default:
|
||||
arg = wrap(insn);
|
||||
break;
|
||||
}
|
||||
parentInsn.setArg(i, arg);
|
||||
return arg;
|
||||
@@ -80,8 +97,4 @@ public abstract class InsnArg extends Typed {
|
||||
// must be implemented in RegisterArg
|
||||
return false;
|
||||
}
|
||||
|
||||
public int getRegNum() {
|
||||
throw new UnsupportedOperationException("Must be called from RegisterArg");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package jadx.core.dex.instructions.args;
|
||||
|
||||
import jadx.core.dex.instructions.IndexInsnNode;
|
||||
import jadx.core.dex.instructions.ConstClassInsn;
|
||||
import jadx.core.dex.instructions.ConstStringInsn;
|
||||
import jadx.core.dex.instructions.InsnType;
|
||||
import jadx.core.dex.nodes.InsnNode;
|
||||
import jadx.core.dex.visitors.InstructionRemover;
|
||||
@@ -17,7 +18,6 @@ public class RegisterArg extends InsnArg {
|
||||
this.regNum = rn;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRegNum() {
|
||||
return regNum;
|
||||
}
|
||||
@@ -47,12 +47,15 @@ public class RegisterArg extends InsnArg {
|
||||
*/
|
||||
public Object getConstValue() {
|
||||
InsnNode parInsn = getAssignInsn();
|
||||
if (parInsn != null && parInsn.getType() == InsnType.CONST) {
|
||||
if (parInsn.getArgsCount() == 0) {
|
||||
// const in 'index' - string or class
|
||||
return ((IndexInsnNode) parInsn).getIndex();
|
||||
} else {
|
||||
return parInsn.getArg(0);
|
||||
if (parInsn != null) {
|
||||
InsnType insnType = parInsn.getType();
|
||||
switch (insnType) {
|
||||
case CONST:
|
||||
return parInsn.getArg(0);
|
||||
case CONST_STR:
|
||||
return ((ConstStringInsn) parInsn).getString();
|
||||
case CONST_CLASS:
|
||||
return ((ConstClassInsn) parInsn).getClsType();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
@@ -21,7 +21,7 @@ public class TypedVar {
|
||||
* This method must be used very carefully
|
||||
*/
|
||||
public boolean forceSetType(ArgType newType) {
|
||||
if (newType != null && !type.equals(newType)) {
|
||||
if (!newType.equals(type)) {
|
||||
type = newType;
|
||||
return true;
|
||||
} else {
|
||||
|
||||
@@ -4,6 +4,7 @@ import jadx.core.dex.info.ClassInfo;
|
||||
import jadx.core.dex.info.MethodInfo;
|
||||
import jadx.core.dex.instructions.InsnType;
|
||||
import jadx.core.dex.instructions.InvokeNode;
|
||||
import jadx.core.dex.instructions.args.InsnArg;
|
||||
import jadx.core.dex.instructions.args.RegisterArg;
|
||||
import jadx.core.dex.nodes.InsnNode;
|
||||
import jadx.core.dex.nodes.MethodNode;
|
||||
|
||||
@@ -71,7 +71,7 @@ public class InsnNode extends LineAttrNode {
|
||||
|
||||
public boolean containsArg(RegisterArg arg) {
|
||||
for (InsnArg a : arguments) {
|
||||
if (a == arg || (a.isRegister() && a.getRegNum() == arg.getRegNum()))
|
||||
if (a == arg || (a.isRegister() && ((RegisterArg)a).getRegNum() == arg.getRegNum()))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -168,7 +168,7 @@ public class DebugInfoParser {
|
||||
insn.setSourceLine(line);
|
||||
for (InsnArg arg : insn.getArguments())
|
||||
if (arg.isRegister()) {
|
||||
activeRegisters[arg.getRegNum()] = arg;
|
||||
activeRegisters[((RegisterArg) arg).getRegNum()] = arg;
|
||||
}
|
||||
|
||||
RegisterArg res = insn.getResult();
|
||||
@@ -211,7 +211,7 @@ public class DebugInfoParser {
|
||||
|
||||
private static void merge(InsnArg arg, LocalVar var) {
|
||||
if (arg != null && arg.isRegister()) {
|
||||
if (var.getRegNum() == arg.getRegNum())
|
||||
if (var.getRegNum() == ((RegisterArg) arg).getRegNum())
|
||||
arg.setTypedVar(var.getTypedVar());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,13 +36,12 @@ public class ConstInlinerVisitor extends AbstractVisitor {
|
||||
|
||||
private static boolean checkInsn(MethodNode mth, BlockNode block, InsnNode insn) {
|
||||
if (insn.getType() == InsnType.CONST) {
|
||||
if (insn.getArgsCount() == 1
|
||||
&& insn.getArg(0).isLiteral()
|
||||
if (insn.getArg(0).isLiteral()
|
||||
&& insn.getResult().getType().getRegCount() == 1 /* process only narrow types */) {
|
||||
long lit = ((LiteralArg) insn.getArg(0)).getLiteral();
|
||||
return replaceConst(mth, block, insn, lit);
|
||||
}
|
||||
// TODO process string const
|
||||
// TODO process string and class const
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -106,9 +105,7 @@ public class ConstInlinerVisitor extends AbstractVisitor {
|
||||
private static void fixTypes(MethodNode mth, InsnNode insn) {
|
||||
switch (insn.getType()) {
|
||||
case CONST:
|
||||
if (insn.getArgsCount() > 0) {
|
||||
insn.getArg(0).merge(insn.getResult());
|
||||
}
|
||||
insn.getArg(0).merge(insn.getResult());
|
||||
break;
|
||||
|
||||
case MOVE:
|
||||
|
||||
@@ -26,6 +26,8 @@ public class FallbackModeVisitor extends AbstractVisitor {
|
||||
case ARITH: // ??
|
||||
case NEG:
|
||||
case CONST:
|
||||
case CONST_STR:
|
||||
case CONST_CLASS:
|
||||
case CMP_L:
|
||||
case CMP_G:
|
||||
catchAttr.getTryBlock().removeInsn(insn);
|
||||
|
||||
@@ -4,6 +4,8 @@ import jadx.core.Consts;
|
||||
import jadx.core.deobf.NameMapper;
|
||||
import jadx.core.dex.attributes.AttributeType;
|
||||
import jadx.core.dex.info.MethodInfo;
|
||||
import jadx.core.dex.instructions.ConstClassInsn;
|
||||
import jadx.core.dex.instructions.ConstStringInsn;
|
||||
import jadx.core.dex.instructions.IndexInsnNode;
|
||||
import jadx.core.dex.instructions.InsnType;
|
||||
import jadx.core.dex.instructions.InvokeNode;
|
||||
@@ -98,12 +100,16 @@ public class ModVisitor extends AbstractVisitor {
|
||||
break;
|
||||
|
||||
case CONST:
|
||||
case CONST_STR:
|
||||
case CONST_CLASS:
|
||||
ClassNode parentClass = mth.getParentClass();
|
||||
FieldNode f = null;
|
||||
if (insn.getArgsCount() == 0) {
|
||||
// const-string
|
||||
IndexInsnNode node = (IndexInsnNode) insn;
|
||||
f = parentClass.getConstField(node.getIndex());
|
||||
if (insn.getType() == InsnType.CONST_STR) {
|
||||
String s = ((ConstStringInsn) insn).getString();
|
||||
f = parentClass.getConstField(s);
|
||||
} else if (insn.getType() == InsnType.CONST_CLASS) {
|
||||
ArgType t = ((ConstClassInsn) insn).getClsType();
|
||||
f = parentClass.getConstField(t);
|
||||
} else {
|
||||
LiteralArg arg = (LiteralArg) insn.getArg(0);
|
||||
ArgType type = arg.getType();
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package jadx.core.dex.visitors.regions;
|
||||
|
||||
import jadx.core.Consts;
|
||||
import jadx.core.dex.attributes.AttributeFlag;
|
||||
import jadx.core.dex.attributes.AttributeType;
|
||||
import jadx.core.dex.attributes.AttributesList;
|
||||
@@ -42,19 +43,23 @@ public class RegionMaker {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(RegionMaker.class);
|
||||
|
||||
private final MethodNode mth;
|
||||
private final BitSet processedBlocks;
|
||||
private BitSet processedBlocks;
|
||||
|
||||
public RegionMaker(MethodNode mth) {
|
||||
this.mth = mth;
|
||||
this.processedBlocks = new BitSet(mth.getBasicBlocks().size());
|
||||
if (Consts.DEBUG) {
|
||||
this.processedBlocks = new BitSet(mth.getBasicBlocks().size());
|
||||
}
|
||||
}
|
||||
|
||||
public Region makeRegion(BlockNode startBlock, RegionStack stack) {
|
||||
int id = startBlock.getId();
|
||||
if (processedBlocks.get(id))
|
||||
LOG.debug(" Block already processed: " + startBlock + ", mth: " + mth);
|
||||
else
|
||||
processedBlocks.set(id);
|
||||
if (Consts.DEBUG) {
|
||||
int id = startBlock.getId();
|
||||
if (processedBlocks.get(id))
|
||||
LOG.debug(" Block already processed: " + startBlock + ", mth: " + mth);
|
||||
else
|
||||
processedBlocks.set(id);
|
||||
}
|
||||
|
||||
Region r = new Region(stack.peekRegion());
|
||||
BlockNode next = startBlock;
|
||||
|
||||
Reference in New Issue
Block a user