Skip to content

Commit 3e93d20

Browse files
committed
d2j-smali support polymorphic/custom
1 parent bac5d54 commit 3e93d20

File tree

6 files changed

+155
-43
lines changed

6 files changed

+155
-43
lines changed

d2j-smali/src/main/antlr4/com/googlecode/d2j/smali/antlr4/Smali.g4

+23-4
Original file line numberDiff line numberDiff line change
@@ -53,14 +53,14 @@ VOID_TYPE:'V';
5353
fragment
5454
FRAGMENT_PRIMITIVE_TYPE:'B'|'Z'|'S'|'C'|'I'|'F'|'J'|'D';
5555
fragment
56-
FRAGMENT_OBJECT_TYPE: 'L' (ESC_SEQ |~(';'|':'|'\\'|' '|'\n'|'\t'|'\r'|'('|')'|'-'))+ ';' ;
56+
FRAGMENT_OBJECT_TYPE: 'L' (ESC_SEQ |~(';'|':'|'\\'|' '|'\n'|'\t'|'\r'|'('|')'))+ ';' ;
5757
fragment
5858
FRAGMENT_ARRAY_TYPE: ('[')+ (FRAGMENT_PRIMITIVE_TYPE|FRAGMENT_OBJECT_TYPE);
5959

6060
fragment
6161
FRAGMENT_ID: (ESC_SEQ| ~('\\'|'\r'|'\n'|'\t'|' '|':'|'-'|'='|','|'{'|'}'|'('|')'|'+'|'\"'|'\''|'#'|'/'|'.'|';'))+;
6262
fragment
63-
FRAGMENT_METHOD_PART: FRAGMENT_ID '(' (FRAGMENT_OBJECT_TYPE|FRAGMENT_ARRAY_TYPE|FRAGMENT_PRIMITIVE_TYPE)* ')' ('V' | FRAGMENT_OBJECT_TYPE|FRAGMENT_ARRAY_TYPE|FRAGMENT_PRIMITIVE_TYPE)
63+
FRAGMENT_METHOD_PROTO: '(' (FRAGMENT_OBJECT_TYPE|FRAGMENT_ARRAY_TYPE|FRAGMENT_PRIMITIVE_TYPE)* ')' ('V' | FRAGMENT_OBJECT_TYPE|FRAGMENT_ARRAY_TYPE|FRAGMENT_PRIMITIVE_TYPE)
6464
;
6565
fragment
6666
FRAGMENT_FIELD_PART:
@@ -69,8 +69,9 @@ FRAGMENT_FIELD_PART:
6969
;
7070

7171

72-
METHOD_FULL: (FRAGMENT_OBJECT_TYPE|FRAGMENT_ARRAY_TYPE) '->' FRAGMENT_METHOD_PART;
73-
METHOD_PART: FRAGMENT_METHOD_PART;
72+
METHOD_FULL: (FRAGMENT_OBJECT_TYPE|FRAGMENT_ARRAY_TYPE) '->' FRAGMENT_ID FRAGMENT_METHOD_PROTO;
73+
METHOD_PART: FRAGMENT_ID FRAGMENT_METHOD_PROTO;
74+
METHOD_PROTO: FRAGMENT_METHOD_PROTO;
7475

7576
FIELD_FULL: (FRAGMENT_OBJECT_TYPE|FRAGMENT_ARRAY_TYPE) '->' FRAGMENT_FIELD_PART;
7677
FIELD_PART: FRAGMENT_FIELD_PART;
@@ -174,14 +175,20 @@ sAnnotationValue
174175
:sSubannotation
175176
|sBaseValue
176177
|sArrayValue
178+
| ( '.iget' | '.iput' | '.sget' | '.sput' ) FIELD_FULL
179+
| ( '.invoke-instance' | '.invoke-static' ) METHOD_FULL
177180
;// field,method,array,subannotation
178181
sBaseValue
179182
:STRING
180183
|BOOLEAN|BYTE|SHORT|CHAR|INT|LONG
181184
|BASE_FLOAT| FLOAT_INFINITY | FLOAT_NAN
182185
|BASE_DOUBLE|DOUBLE_INFINITY|DOUBLE_NAN
183186
|METHOD_FULL
187+
|METHOD_PROTO
184188
|OBJECT_TYPE
189+
|ARRAY_TYPE
190+
|PRIMITIVE_TYPE
191+
|VOID_TYPE
185192
|NULL
186193
|DENUM FIELD_FULL
187194
;
@@ -213,6 +220,10 @@ sInstruction
213220
|ft5c
214221
|fm5c
215222
|fmrc
223+
|fm45cc
224+
|fm4rcc
225+
|fmcustomc
226+
|fmcustomrc
216227
|ftrc
217228
|sLabel
218229
|f2sb
@@ -394,6 +405,14 @@ fmrc : op=('invoke-virtual/range'|'invoke-super/range'
394405
|'invoke-interface/range'
395406
) '{' (rstart=REGISTER '..' rend=REGISTER)? '}' ',' method=METHOD_FULL
396407
;
408+
fm45cc : op='invoke-polymorphic' '{' (REGISTER (',' REGISTER)* )? '}' ',' method=METHOD_FULL ',' proto=METHOD_PROTO
409+
;
410+
fm4rcc : op='invoke-polymorphic/range' '{' (rstart=REGISTER '..' rend=REGISTER)? '}' ',' method=METHOD_FULL ',' proto=METHOD_PROTO
411+
;
412+
fmcustomc : op='invoke-custom' '{' (REGISTER (',' REGISTER)* )? '}' ',' sArrayValue
413+
;
414+
fmcustomrc : op='invoke-custom/range' '{' (rstart=REGISTER '..' rend=REGISTER)? '}' ',' sArrayValue
415+
;
397416
ftrc : op='filled-new-array/range' '{' (rstart=REGISTER '..' rend=REGISTER)? '}' ',' type=(OBJECT_TYPE|ARRAY_TYPE);
398417
f31t: op=('fill-array-data'|'packed-switch'|'sparse-switch') r1=REGISTER ',' label=LABEL;
399418
f1t :op=('if-eqz'|'if-nez'|'if-ltz'|'if-gez'|'if-gtz'|'if-lez') r1=REGISTER ',' label=LABEL

d2j-smali/src/main/java/com/googlecode/d2j/smali/BaksmaliCodeDumper.java

+65-14
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,7 @@
1616
*/
1717
package com.googlecode.d2j.smali;
1818

19-
import com.googlecode.d2j.DexLabel;
20-
import com.googlecode.d2j.Field;
21-
import com.googlecode.d2j.Method;
19+
import com.googlecode.d2j.*;
2220
import com.googlecode.d2j.node.DexDebugNode;
2321
import com.googlecode.d2j.reader.InstructionFormat;
2422
import com.googlecode.d2j.reader.Op;
@@ -237,11 +235,9 @@ public void visitEnd() {
237235
@Override
238236
public void visitFieldStmt(Op op, int a, int b, Field field) {
239237
if (op.format == InstructionFormat.kFmt22c) {// iget,iput
240-
out.s("%s %s, %s, %s->%s:%s", op.displayName, reg(a), reg(b), BaksmaliDumper.escapeType(field.getOwner()),
241-
BaksmaliDumper.escapeId(field.getName()), BaksmaliDumper.escapeType(field.getType()));
238+
out.s("%s %s, %s, %s", op.displayName, reg(a), reg(b), BaksmaliDumper.escapeField(field));
242239
} else {
243-
out.s("%s %s, %s->%s:%s", op.displayName, reg(a), BaksmaliDumper.escapeType(field.getOwner()),
244-
BaksmaliDumper.escapeId(field.getName()), BaksmaliDumper.escapeType(field.getType()));
240+
out.s("%s %s, %s", op.displayName, reg(a), BaksmaliDumper.escapeField(field));
245241
}
246242
}
247243

@@ -341,9 +337,8 @@ public void visitMethodStmt(Op op, int[] args, Method method) {
341337

342338
if (args.length > 0) {
343339
if (op.format == InstructionFormat.kFmt3rc) { // invoke-x/range
344-
out.s("%s { %s .. %s }, %s->%s%s", op.displayName, reg(args[0]), reg(args[args.length - 1]),
345-
BaksmaliDumper.escapeType(method.getOwner()), BaksmaliDumper.escapeId(method.getName()),
346-
BaksmaliDumper.escapeMethodDesc(method));
340+
out.s("%s { %s .. %s }, %s", op.displayName, reg(args[0]), reg(args[args.length - 1]),
341+
BaksmaliDumper.escapeMethod(method));
347342
} else {
348343
boolean first = true;
349344
StringBuilder buff = new StringBuilder();
@@ -355,16 +350,72 @@ public void visitMethodStmt(Op op, int[] args, Method method) {
355350
}
356351
buff.append(reg(i));
357352
}
358-
out.s("%s { %s }, %s->%s%s", op.displayName, buff, BaksmaliDumper.escapeType(method.getOwner()),
359-
BaksmaliDumper.escapeId(method.getName()), BaksmaliDumper.escapeMethodDesc(method));
353+
out.s("%s { %s }, %s", op.displayName, buff, BaksmaliDumper.escapeMethod(method));
360354
}
361355
} else {
362-
out.s("%s { }, %s->%s%s", op.displayName, BaksmaliDumper.escapeType(method.getOwner()),
363-
BaksmaliDumper.escapeId(method.getName()), BaksmaliDumper.escapeMethodDesc(method));
356+
out.s("%s { }, %s", op.displayName, BaksmaliDumper.escapeMethod(method));
364357
}
365358

366359
}
367360

361+
@Override
362+
public void visitMethodStmt(Op op, int[] args, Method method, Proto proto) {
363+
if (args.length > 0) {
364+
if (op.format == InstructionFormat.kFmt4rcc) { // invoke-x/range
365+
out.s("%s { %s .. %s }, %s, %s", op.displayName, reg(args[0]), reg(args[args.length - 1]),
366+
BaksmaliDumper.escapeMethod(method), BaksmaliDumper.escapeMethodDesc(proto));
367+
} else {
368+
boolean first = true;
369+
StringBuilder buff = new StringBuilder();
370+
for (int i : args) {
371+
if (first) {
372+
first = false;
373+
} else {
374+
buff.append(", ");
375+
}
376+
buff.append(reg(i));
377+
}
378+
out.s("%s { %s }, %s, %s", op.displayName, buff, BaksmaliDumper.escapeMethod(method),
379+
BaksmaliDumper.escapeMethodDesc(proto));
380+
}
381+
} else {
382+
out.s("%s { }, %s, %s", op.displayName, BaksmaliDumper.escapeMethod(method),
383+
BaksmaliDumper.escapeMethodDesc(proto));
384+
}
385+
}
386+
387+
@Override
388+
public void visitMethodStmt(Op op, int[] args, String name, Proto proto, MethodHandle bsm, Object... bsmArgs) {
389+
StringBuilder sb = new StringBuilder();
390+
sb.append("{ ").append( BaksmaliDumper.escapeValue(bsm)).append(", ").append(BaksmaliDumper.escapeValue(name)).append(", ").append(BaksmaliDumper.escapeMethodDesc(proto));
391+
for(Object o: bsmArgs) {
392+
sb.append(", ").append(BaksmaliDumper.escapeValue(o));
393+
}
394+
sb.append("}");
395+
396+
397+
if (args.length > 0) {
398+
if (op.format == InstructionFormat.kFmt3rc) { // invoke-x/range
399+
out.s("%s { %s .. %s }, %s", op.displayName, reg(args[0]), reg(args[args.length - 1]),
400+
sb);
401+
} else {
402+
boolean first = true;
403+
StringBuilder buff = new StringBuilder();
404+
for (int i : args) {
405+
if (first) {
406+
first = false;
407+
} else {
408+
buff.append(", ");
409+
}
410+
buff.append(reg(i));
411+
}
412+
out.s("%s { %s }, %s", op.displayName, buff, sb);
413+
}
414+
} else {
415+
out.s("%s { }, %s", op.displayName, sb);
416+
}
417+
}
418+
368419
@Override
369420
public void visitPackedSwitchStmt(Op op, int ra, int first_case, DexLabel[] labels) {
370421
DexLabel dx = new DexLabel();

d2j-smali/src/main/java/com/googlecode/d2j/smali/BaksmaliDumper.java

+41-16
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,13 @@ static void escapeType0(StringBuilder sb, String id) {
119119
}
120120
}
121121

122+
static String escapeMethod(Method method) {
123+
return BaksmaliDumper.escapeType(method.getOwner()) + "->" + BaksmaliDumper.escapeId(method.getName()) + BaksmaliDumper.escapeMethodDesc(method);
124+
}
122125
static String escapeMethodDesc(Method m) {
126+
return escapeMethodDesc(m.getProto());
127+
}
128+
static String escapeMethodDesc(Proto m) {
123129
StringBuilder escapeBuff = new StringBuilder();
124130
escapeBuff.append("(");
125131
for (String t : m.getParameterTypes()) {
@@ -211,10 +217,12 @@ static String escapeValue(Object obj) {
211217
if (obj instanceof DexType) {
212218
return escapeType(((DexType) obj).desc);
213219
}
214-
215-
// if (obj instanceof Method) {
216-
// return v((Method) obj);
217-
// }
220+
if(obj instanceof Proto) {
221+
return escapeMethodDesc((Proto) obj);
222+
}
223+
if(obj instanceof MethodHandle) {
224+
return escapeMethodHandle((MethodHandle) obj);
225+
}
218226
if (obj instanceof Field) {
219227
Field f = ((Field) obj);
220228
String owner = f.getOwner();
@@ -262,22 +270,39 @@ static String escapeValue(Object obj) {
262270
return ((Boolean) obj).toString();
263271
}
264272
if (obj instanceof Method) {
265-
Method m = (Method) obj;
266-
StringBuilder buf = new StringBuilder();
267-
escapeType0(buf, m.getOwner());
268-
buf.append("->");
269-
escapeId0(buf, m.getName());
270-
buf.append("(");
271-
for (String a : m.getParameterTypes()) {
272-
escapeType0(buf, a);
273-
}
274-
buf.append(")");
275-
escapeType0(buf, m.getReturnType());
276-
return buf.toString();
273+
return escapeMethod((Method) obj);
277274
}
278275
return null;
279276
}
280277

278+
private static String escapeMethodHandle(MethodHandle obj) {
279+
switch (obj.getType()) {
280+
case MethodHandle.INSTANCE_GET:
281+
return ".iget " + escapeField(obj.getField());
282+
case MethodHandle.INSTANCE_PUT:
283+
return ".iput " + escapeField(obj.getField());
284+
case MethodHandle.STATIC_GET:
285+
return ".sget " + escapeField(obj.getField());
286+
case MethodHandle.STATIC_PUT:
287+
return ".sput " + escapeField(obj.getField());
288+
289+
case MethodHandle.INVOKE_INSTANCE:
290+
return ".invoke-instance " + escapeMethod(obj.getMethod());
291+
case MethodHandle.INVOKE_STATIC:
292+
return ".invoke-static " + escapeMethod(obj.getMethod());
293+
default:
294+
}
295+
return "?";
296+
}
297+
298+
public static String escapeField(Field f) {
299+
String owner = f.getOwner();
300+
if (owner == null) {
301+
owner = f.getType();
302+
}
303+
return escapeType(owner) + "->" + f.getName() + ":" + escapeType(f.getType());
304+
}
305+
281306
private static void dumpAnns(List<DexAnnotationNode> anns, Out out) {
282307
for (DexAnnotationNode ann : anns) {
283308
dumpAnn(ann, out);

dex-ir/src/main/java/com/googlecode/dex2jar/ir/expr/InvokeExpr.java

+8-4
Original file line numberDiff line numberDiff line change
@@ -74,14 +74,18 @@ public Value clone(LabelAndLocalMapper mapper) {
7474
public String toString0() {
7575
StringBuilder sb = new StringBuilder();
7676

77+
int i = 0;
7778
if (super.vt == VT.INVOKE_NEW) {
78-
sb.append("new ").append(Util.toShortClassName(method.getOwner())).append('(');
79+
sb.append("new ").append(Util.toShortClassName(method.getOwner()));
80+
} else if (super.vt == VT.INVOKE_STATIC) {
81+
sb.append(Util.toShortClassName(method.getOwner())).append('.')
82+
.append(this.method.getName());
7983
} else {
80-
sb.append(super.vt == VT.INVOKE_STATIC ? Util.toShortClassName(method.getOwner()) : ops[0]).append('.')
81-
.append(this.method.getName()).append('(');
84+
sb.append(ops[i++]).append('.').append(this.method.getName());
8285
}
86+
sb.append('(');
8387
boolean first = true;
84-
for (int i = (vt == VT.INVOKE_STATIC || vt == VT.INVOKE_NEW) ? 0 : 1; i < ops.length; i++) {
88+
for (; i < ops.length; i++) {
8589
if (first) {
8690
first = false;
8791
} else {

dex-ir/src/main/java/com/googlecode/dex2jar/ir/expr/InvokePolymorphicExpr.java

+16-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import com.googlecode.d2j.Method;
1919
import com.googlecode.d2j.Proto;
2020
import com.googlecode.dex2jar.ir.LabelAndLocalMapper;
21+
import com.googlecode.dex2jar.ir.Util;
2122

2223
public class InvokePolymorphicExpr extends AbstractInvokeExpr {
2324
public Proto proto;
@@ -54,8 +55,22 @@ public Value clone(LabelAndLocalMapper mapper) {
5455
@Override
5556
public String toString0() {
5657
StringBuilder sb = new StringBuilder();
58+
int i = 0;
59+
sb.append(ops[i++]).append('.').append(this.method.getName());
60+
String[] argTypes = getProto().getParameterTypes();
61+
sb.append('(');
62+
int j = 0;
63+
boolean first = true;
64+
for (; i < ops.length; i++) {
65+
if (first) {
66+
first = false;
67+
} else {
68+
sb.append(',');
69+
}
70+
sb.append("(").append(Util.toShortClassName(argTypes[j++])).append(")").append(ops[i]);
71+
}
72+
sb.append(')');
5773

58-
sb.append("InvokePolymorphicExpr(...)");
5974
return sb.toString();
6075
}
6176
}

dex-ir/src/main/java/com/googlecode/dex2jar/ir/ts/NewTransformer.java

+2-4
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,7 @@ void replaceAST(IrMethod method) {
103103
if (orgOps[0].vt == NEW) {
104104
NewExpr newExpr = (NewExpr) ie.getOps()[0];
105105
if (newExpr != null) {
106-
Value[] nOps = new Value[orgOps.length - 1];
107-
System.arraycopy(orgOps, 1, nOps, 0, nOps.length);
106+
Value[] nOps = Arrays.copyOfRange(orgOps, 1, orgOps.length);
108107
InvokeExpr invokeNew = Exprs.nInvokeNew(nOps, ie.getArgs(), ie.getOwner());
109108
method.stmts.insertBefore(p, Stmts.nVoidInvoke(invokeNew));
110109
it.remove();
@@ -156,8 +155,7 @@ void replace0(IrMethod method, Map<Local, TObject> init, int size) {
156155
}
157156
InvokeExpr ie = findInvokeExpr(obj.invokeStmt, null);
158157
Value[] orgOps = ie.getOps();
159-
Value[] nOps = new Value[orgOps.length - 1];
160-
System.arraycopy(orgOps, 1, nOps, 0, nOps.length);
158+
Value[] nOps = Arrays.copyOfRange(orgOps, 1, orgOps.length);
161159
InvokeExpr invokeNew = Exprs.nInvokeNew(nOps, ie.getArgs(), ie.getOwner());
162160
method.stmts.replace(obj.invokeStmt, Stmts.nAssign(obj.local, invokeNew));
163161
}

0 commit comments

Comments
 (0)