mirror of
https://github.com/pxb1988/dex2jar.git
synced 2024-11-27 07:00:51 +00:00
d2j-smali support polymorphic/custom
This commit is contained in:
parent
bac5d542a6
commit
3e93d2021f
@ -53,14 +53,14 @@ VOID_TYPE:'V';
|
||||
fragment
|
||||
FRAGMENT_PRIMITIVE_TYPE:'B'|'Z'|'S'|'C'|'I'|'F'|'J'|'D';
|
||||
fragment
|
||||
FRAGMENT_OBJECT_TYPE: 'L' (ESC_SEQ |~(';'|':'|'\\'|' '|'\n'|'\t'|'\r'|'('|')'|'-'))+ ';' ;
|
||||
FRAGMENT_OBJECT_TYPE: 'L' (ESC_SEQ |~(';'|':'|'\\'|' '|'\n'|'\t'|'\r'|'('|')'))+ ';' ;
|
||||
fragment
|
||||
FRAGMENT_ARRAY_TYPE: ('[')+ (FRAGMENT_PRIMITIVE_TYPE|FRAGMENT_OBJECT_TYPE);
|
||||
|
||||
fragment
|
||||
FRAGMENT_ID: (ESC_SEQ| ~('\\'|'\r'|'\n'|'\t'|' '|':'|'-'|'='|','|'{'|'}'|'('|')'|'+'|'\"'|'\''|'#'|'/'|'.'|';'))+;
|
||||
fragment
|
||||
FRAGMENT_METHOD_PART: FRAGMENT_ID '(' (FRAGMENT_OBJECT_TYPE|FRAGMENT_ARRAY_TYPE|FRAGMENT_PRIMITIVE_TYPE)* ')' ('V' | FRAGMENT_OBJECT_TYPE|FRAGMENT_ARRAY_TYPE|FRAGMENT_PRIMITIVE_TYPE)
|
||||
FRAGMENT_METHOD_PROTO: '(' (FRAGMENT_OBJECT_TYPE|FRAGMENT_ARRAY_TYPE|FRAGMENT_PRIMITIVE_TYPE)* ')' ('V' | FRAGMENT_OBJECT_TYPE|FRAGMENT_ARRAY_TYPE|FRAGMENT_PRIMITIVE_TYPE)
|
||||
;
|
||||
fragment
|
||||
FRAGMENT_FIELD_PART:
|
||||
@ -69,8 +69,9 @@ FRAGMENT_FIELD_PART:
|
||||
;
|
||||
|
||||
|
||||
METHOD_FULL: (FRAGMENT_OBJECT_TYPE|FRAGMENT_ARRAY_TYPE) '->' FRAGMENT_METHOD_PART;
|
||||
METHOD_PART: FRAGMENT_METHOD_PART;
|
||||
METHOD_FULL: (FRAGMENT_OBJECT_TYPE|FRAGMENT_ARRAY_TYPE) '->' FRAGMENT_ID FRAGMENT_METHOD_PROTO;
|
||||
METHOD_PART: FRAGMENT_ID FRAGMENT_METHOD_PROTO;
|
||||
METHOD_PROTO: FRAGMENT_METHOD_PROTO;
|
||||
|
||||
FIELD_FULL: (FRAGMENT_OBJECT_TYPE|FRAGMENT_ARRAY_TYPE) '->' FRAGMENT_FIELD_PART;
|
||||
FIELD_PART: FRAGMENT_FIELD_PART;
|
||||
@ -174,6 +175,8 @@ sAnnotationValue
|
||||
:sSubannotation
|
||||
|sBaseValue
|
||||
|sArrayValue
|
||||
| ( '.iget' | '.iput' | '.sget' | '.sput' ) FIELD_FULL
|
||||
| ( '.invoke-instance' | '.invoke-static' ) METHOD_FULL
|
||||
;// field,method,array,subannotation
|
||||
sBaseValue
|
||||
:STRING
|
||||
@ -181,7 +184,11 @@ sBaseValue
|
||||
|BASE_FLOAT| FLOAT_INFINITY | FLOAT_NAN
|
||||
|BASE_DOUBLE|DOUBLE_INFINITY|DOUBLE_NAN
|
||||
|METHOD_FULL
|
||||
|METHOD_PROTO
|
||||
|OBJECT_TYPE
|
||||
|ARRAY_TYPE
|
||||
|PRIMITIVE_TYPE
|
||||
|VOID_TYPE
|
||||
|NULL
|
||||
|DENUM FIELD_FULL
|
||||
;
|
||||
@ -213,6 +220,10 @@ sInstruction
|
||||
|ft5c
|
||||
|fm5c
|
||||
|fmrc
|
||||
|fm45cc
|
||||
|fm4rcc
|
||||
|fmcustomc
|
||||
|fmcustomrc
|
||||
|ftrc
|
||||
|sLabel
|
||||
|f2sb
|
||||
@ -394,6 +405,14 @@ fmrc : op=('invoke-virtual/range'|'invoke-super/range'
|
||||
|'invoke-interface/range'
|
||||
) '{' (rstart=REGISTER '..' rend=REGISTER)? '}' ',' method=METHOD_FULL
|
||||
;
|
||||
fm45cc : op='invoke-polymorphic' '{' (REGISTER (',' REGISTER)* )? '}' ',' method=METHOD_FULL ',' proto=METHOD_PROTO
|
||||
;
|
||||
fm4rcc : op='invoke-polymorphic/range' '{' (rstart=REGISTER '..' rend=REGISTER)? '}' ',' method=METHOD_FULL ',' proto=METHOD_PROTO
|
||||
;
|
||||
fmcustomc : op='invoke-custom' '{' (REGISTER (',' REGISTER)* )? '}' ',' sArrayValue
|
||||
;
|
||||
fmcustomrc : op='invoke-custom/range' '{' (rstart=REGISTER '..' rend=REGISTER)? '}' ',' sArrayValue
|
||||
;
|
||||
ftrc : op='filled-new-array/range' '{' (rstart=REGISTER '..' rend=REGISTER)? '}' ',' type=(OBJECT_TYPE|ARRAY_TYPE);
|
||||
f31t: op=('fill-array-data'|'packed-switch'|'sparse-switch') r1=REGISTER ',' label=LABEL;
|
||||
f1t :op=('if-eqz'|'if-nez'|'if-ltz'|'if-gez'|'if-gtz'|'if-lez') r1=REGISTER ',' label=LABEL
|
||||
|
@ -16,9 +16,7 @@
|
||||
*/
|
||||
package com.googlecode.d2j.smali;
|
||||
|
||||
import com.googlecode.d2j.DexLabel;
|
||||
import com.googlecode.d2j.Field;
|
||||
import com.googlecode.d2j.Method;
|
||||
import com.googlecode.d2j.*;
|
||||
import com.googlecode.d2j.node.DexDebugNode;
|
||||
import com.googlecode.d2j.reader.InstructionFormat;
|
||||
import com.googlecode.d2j.reader.Op;
|
||||
@ -237,11 +235,9 @@ import java.util.*;
|
||||
@Override
|
||||
public void visitFieldStmt(Op op, int a, int b, Field field) {
|
||||
if (op.format == InstructionFormat.kFmt22c) {// iget,iput
|
||||
out.s("%s %s, %s, %s->%s:%s", op.displayName, reg(a), reg(b), BaksmaliDumper.escapeType(field.getOwner()),
|
||||
BaksmaliDumper.escapeId(field.getName()), BaksmaliDumper.escapeType(field.getType()));
|
||||
out.s("%s %s, %s, %s", op.displayName, reg(a), reg(b), BaksmaliDumper.escapeField(field));
|
||||
} else {
|
||||
out.s("%s %s, %s->%s:%s", op.displayName, reg(a), BaksmaliDumper.escapeType(field.getOwner()),
|
||||
BaksmaliDumper.escapeId(field.getName()), BaksmaliDumper.escapeType(field.getType()));
|
||||
out.s("%s %s, %s", op.displayName, reg(a), BaksmaliDumper.escapeField(field));
|
||||
}
|
||||
}
|
||||
|
||||
@ -341,9 +337,8 @@ import java.util.*;
|
||||
|
||||
if (args.length > 0) {
|
||||
if (op.format == InstructionFormat.kFmt3rc) { // invoke-x/range
|
||||
out.s("%s { %s .. %s }, %s->%s%s", op.displayName, reg(args[0]), reg(args[args.length - 1]),
|
||||
BaksmaliDumper.escapeType(method.getOwner()), BaksmaliDumper.escapeId(method.getName()),
|
||||
BaksmaliDumper.escapeMethodDesc(method));
|
||||
out.s("%s { %s .. %s }, %s", op.displayName, reg(args[0]), reg(args[args.length - 1]),
|
||||
BaksmaliDumper.escapeMethod(method));
|
||||
} else {
|
||||
boolean first = true;
|
||||
StringBuilder buff = new StringBuilder();
|
||||
@ -355,16 +350,72 @@ import java.util.*;
|
||||
}
|
||||
buff.append(reg(i));
|
||||
}
|
||||
out.s("%s { %s }, %s->%s%s", op.displayName, buff, BaksmaliDumper.escapeType(method.getOwner()),
|
||||
BaksmaliDumper.escapeId(method.getName()), BaksmaliDumper.escapeMethodDesc(method));
|
||||
out.s("%s { %s }, %s", op.displayName, buff, BaksmaliDumper.escapeMethod(method));
|
||||
}
|
||||
} else {
|
||||
out.s("%s { }, %s->%s%s", op.displayName, BaksmaliDumper.escapeType(method.getOwner()),
|
||||
BaksmaliDumper.escapeId(method.getName()), BaksmaliDumper.escapeMethodDesc(method));
|
||||
out.s("%s { }, %s", op.displayName, BaksmaliDumper.escapeMethod(method));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethodStmt(Op op, int[] args, Method method, Proto proto) {
|
||||
if (args.length > 0) {
|
||||
if (op.format == InstructionFormat.kFmt4rcc) { // invoke-x/range
|
||||
out.s("%s { %s .. %s }, %s, %s", op.displayName, reg(args[0]), reg(args[args.length - 1]),
|
||||
BaksmaliDumper.escapeMethod(method), BaksmaliDumper.escapeMethodDesc(proto));
|
||||
} else {
|
||||
boolean first = true;
|
||||
StringBuilder buff = new StringBuilder();
|
||||
for (int i : args) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
buff.append(", ");
|
||||
}
|
||||
buff.append(reg(i));
|
||||
}
|
||||
out.s("%s { %s }, %s, %s", op.displayName, buff, BaksmaliDumper.escapeMethod(method),
|
||||
BaksmaliDumper.escapeMethodDesc(proto));
|
||||
}
|
||||
} else {
|
||||
out.s("%s { }, %s, %s", op.displayName, BaksmaliDumper.escapeMethod(method),
|
||||
BaksmaliDumper.escapeMethodDesc(proto));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethodStmt(Op op, int[] args, String name, Proto proto, MethodHandle bsm, Object... bsmArgs) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("{ ").append( BaksmaliDumper.escapeValue(bsm)).append(", ").append(BaksmaliDumper.escapeValue(name)).append(", ").append(BaksmaliDumper.escapeMethodDesc(proto));
|
||||
for(Object o: bsmArgs) {
|
||||
sb.append(", ").append(BaksmaliDumper.escapeValue(o));
|
||||
}
|
||||
sb.append("}");
|
||||
|
||||
|
||||
if (args.length > 0) {
|
||||
if (op.format == InstructionFormat.kFmt3rc) { // invoke-x/range
|
||||
out.s("%s { %s .. %s }, %s", op.displayName, reg(args[0]), reg(args[args.length - 1]),
|
||||
sb);
|
||||
} else {
|
||||
boolean first = true;
|
||||
StringBuilder buff = new StringBuilder();
|
||||
for (int i : args) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
buff.append(", ");
|
||||
}
|
||||
buff.append(reg(i));
|
||||
}
|
||||
out.s("%s { %s }, %s", op.displayName, buff, sb);
|
||||
}
|
||||
} else {
|
||||
out.s("%s { }, %s", op.displayName, sb);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPackedSwitchStmt(Op op, int ra, int first_case, DexLabel[] labels) {
|
||||
DexLabel dx = new DexLabel();
|
||||
|
@ -119,7 +119,13 @@ public class BaksmaliDumper implements DexConstants {
|
||||
}
|
||||
}
|
||||
|
||||
static String escapeMethod(Method method) {
|
||||
return BaksmaliDumper.escapeType(method.getOwner()) + "->" + BaksmaliDumper.escapeId(method.getName()) + BaksmaliDumper.escapeMethodDesc(method);
|
||||
}
|
||||
static String escapeMethodDesc(Method m) {
|
||||
return escapeMethodDesc(m.getProto());
|
||||
}
|
||||
static String escapeMethodDesc(Proto m) {
|
||||
StringBuilder escapeBuff = new StringBuilder();
|
||||
escapeBuff.append("(");
|
||||
for (String t : m.getParameterTypes()) {
|
||||
@ -211,10 +217,12 @@ public class BaksmaliDumper implements DexConstants {
|
||||
if (obj instanceof DexType) {
|
||||
return escapeType(((DexType) obj).desc);
|
||||
}
|
||||
|
||||
// if (obj instanceof Method) {
|
||||
// return v((Method) obj);
|
||||
// }
|
||||
if(obj instanceof Proto) {
|
||||
return escapeMethodDesc((Proto) obj);
|
||||
}
|
||||
if(obj instanceof MethodHandle) {
|
||||
return escapeMethodHandle((MethodHandle) obj);
|
||||
}
|
||||
if (obj instanceof Field) {
|
||||
Field f = ((Field) obj);
|
||||
String owner = f.getOwner();
|
||||
@ -262,22 +270,39 @@ public class BaksmaliDumper implements DexConstants {
|
||||
return ((Boolean) obj).toString();
|
||||
}
|
||||
if (obj instanceof Method) {
|
||||
Method m = (Method) obj;
|
||||
StringBuilder buf = new StringBuilder();
|
||||
escapeType0(buf, m.getOwner());
|
||||
buf.append("->");
|
||||
escapeId0(buf, m.getName());
|
||||
buf.append("(");
|
||||
for (String a : m.getParameterTypes()) {
|
||||
escapeType0(buf, a);
|
||||
}
|
||||
buf.append(")");
|
||||
escapeType0(buf, m.getReturnType());
|
||||
return buf.toString();
|
||||
return escapeMethod((Method) obj);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String escapeMethodHandle(MethodHandle obj) {
|
||||
switch (obj.getType()) {
|
||||
case MethodHandle.INSTANCE_GET:
|
||||
return ".iget " + escapeField(obj.getField());
|
||||
case MethodHandle.INSTANCE_PUT:
|
||||
return ".iput " + escapeField(obj.getField());
|
||||
case MethodHandle.STATIC_GET:
|
||||
return ".sget " + escapeField(obj.getField());
|
||||
case MethodHandle.STATIC_PUT:
|
||||
return ".sput " + escapeField(obj.getField());
|
||||
|
||||
case MethodHandle.INVOKE_INSTANCE:
|
||||
return ".invoke-instance " + escapeMethod(obj.getMethod());
|
||||
case MethodHandle.INVOKE_STATIC:
|
||||
return ".invoke-static " + escapeMethod(obj.getMethod());
|
||||
default:
|
||||
}
|
||||
return "?";
|
||||
}
|
||||
|
||||
public static String escapeField(Field f) {
|
||||
String owner = f.getOwner();
|
||||
if (owner == null) {
|
||||
owner = f.getType();
|
||||
}
|
||||
return escapeType(owner) + "->" + f.getName() + ":" + escapeType(f.getType());
|
||||
}
|
||||
|
||||
private static void dumpAnns(List<DexAnnotationNode> anns, Out out) {
|
||||
for (DexAnnotationNode ann : anns) {
|
||||
dumpAnn(ann, out);
|
||||
|
@ -74,14 +74,18 @@ public class InvokeExpr extends AbstractInvokeExpr {
|
||||
public String toString0() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
int i = 0;
|
||||
if (super.vt == VT.INVOKE_NEW) {
|
||||
sb.append("new ").append(Util.toShortClassName(method.getOwner())).append('(');
|
||||
sb.append("new ").append(Util.toShortClassName(method.getOwner()));
|
||||
} else if (super.vt == VT.INVOKE_STATIC) {
|
||||
sb.append(Util.toShortClassName(method.getOwner())).append('.')
|
||||
.append(this.method.getName());
|
||||
} else {
|
||||
sb.append(super.vt == VT.INVOKE_STATIC ? Util.toShortClassName(method.getOwner()) : ops[0]).append('.')
|
||||
.append(this.method.getName()).append('(');
|
||||
sb.append(ops[i++]).append('.').append(this.method.getName());
|
||||
}
|
||||
sb.append('(');
|
||||
boolean first = true;
|
||||
for (int i = (vt == VT.INVOKE_STATIC || vt == VT.INVOKE_NEW) ? 0 : 1; i < ops.length; i++) {
|
||||
for (; i < ops.length; i++) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
|
@ -18,6 +18,7 @@ package com.googlecode.dex2jar.ir.expr;
|
||||
import com.googlecode.d2j.Method;
|
||||
import com.googlecode.d2j.Proto;
|
||||
import com.googlecode.dex2jar.ir.LabelAndLocalMapper;
|
||||
import com.googlecode.dex2jar.ir.Util;
|
||||
|
||||
public class InvokePolymorphicExpr extends AbstractInvokeExpr {
|
||||
public Proto proto;
|
||||
@ -54,8 +55,22 @@ public class InvokePolymorphicExpr extends AbstractInvokeExpr {
|
||||
@Override
|
||||
public String toString0() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int i = 0;
|
||||
sb.append(ops[i++]).append('.').append(this.method.getName());
|
||||
String[] argTypes = getProto().getParameterTypes();
|
||||
sb.append('(');
|
||||
int j = 0;
|
||||
boolean first = true;
|
||||
for (; i < ops.length; i++) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
sb.append(',');
|
||||
}
|
||||
sb.append("(").append(Util.toShortClassName(argTypes[j++])).append(")").append(ops[i]);
|
||||
}
|
||||
sb.append(')');
|
||||
|
||||
sb.append("InvokePolymorphicExpr(...)");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
@ -103,8 +103,7 @@ public class NewTransformer implements Transformer {
|
||||
if (orgOps[0].vt == NEW) {
|
||||
NewExpr newExpr = (NewExpr) ie.getOps()[0];
|
||||
if (newExpr != null) {
|
||||
Value[] nOps = new Value[orgOps.length - 1];
|
||||
System.arraycopy(orgOps, 1, nOps, 0, nOps.length);
|
||||
Value[] nOps = Arrays.copyOfRange(orgOps, 1, orgOps.length);
|
||||
InvokeExpr invokeNew = Exprs.nInvokeNew(nOps, ie.getArgs(), ie.getOwner());
|
||||
method.stmts.insertBefore(p, Stmts.nVoidInvoke(invokeNew));
|
||||
it.remove();
|
||||
@ -156,8 +155,7 @@ public class NewTransformer implements Transformer {
|
||||
}
|
||||
InvokeExpr ie = findInvokeExpr(obj.invokeStmt, null);
|
||||
Value[] orgOps = ie.getOps();
|
||||
Value[] nOps = new Value[orgOps.length - 1];
|
||||
System.arraycopy(orgOps, 1, nOps, 0, nOps.length);
|
||||
Value[] nOps = Arrays.copyOfRange(orgOps, 1, orgOps.length);
|
||||
InvokeExpr invokeNew = Exprs.nInvokeNew(nOps, ie.getArgs(), ie.getOwner());
|
||||
method.stmts.replace(obj.invokeStmt, Stmts.nAssign(obj.local, invokeNew));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user