From 0862aaeb391be02864482c43c1c6b99cdc1c6467 Mon Sep 17 00:00:00 2001 From: Bob Pan Date: Thu, 31 Aug 2023 12:55:00 +0800 Subject: [PATCH] support dex 038 --- .../com/googlecode/d2j/smali/antlr4/Smali.g4 | 12 +- .../googlecode/d2j/smali/AntlrSmaliUtil.java | 82 ++++++++++++ .../d2j/smali/BaksmaliCodeDumper.java | 23 +++- d2j-smali/src/test/java/a/SmaliTest.java | 9 +- .../java/com/googlecode/d2j/CallSite.java | 37 ++++++ .../java/com/googlecode/d2j/DexConstants.java | 15 +++ .../com/googlecode/d2j/node/DexCodeNode.java | 4 +- .../d2j/node/insn/MethodCustomStmtNode.java | 18 +-- .../d2j/visitors/DexCodeVisitor.java | 4 +- .../googlecode/d2j/reader/DexFileReader.java | 27 ++-- .../googlecode/d2j/util/ASMifierCodeV.java | 4 +- .../java/com/googlecode/d2j/util/Escape.java | 23 ++++ .../d2j/converter/Dex2IRConverter.java | 6 +- .../googlecode/dex2jar/test/TestUtils.java | 8 +- .../src/test/resources/dexes/dex038.dex | Bin 0 -> 1376 bytes .../googlecode/d2j/dex/writer/CodeWriter.java | 121 ++++++++++++++++++ .../d2j/dex/writer/DexFileWriter.java | 15 ++- .../d2j/dex/writer/ev/EncodedAnnotation.java | 42 +++++- .../d2j/dex/writer/ev/EncodedArray.java | 23 +++- .../d2j/dex/writer/ev/EncodedValue.java | 73 ++++++++++- .../d2j/dex/writer/item/CallSiteIdItem.java | 46 +++++++ .../d2j/dex/writer/item/ClassDefItem.java | 7 +- .../d2j/dex/writer/item/ConstPool.java | 65 ++++++++-- .../d2j/dex/writer/item/EncodedArrayItem.java | 34 ----- .../d2j/dex/writer/item/HeadItem.java | 18 ++- .../d2j/dex/writer/item/SectionItem.java | 6 - 26 files changed, 599 insertions(+), 123 deletions(-) create mode 100644 dex-reader-api/src/main/java/com/googlecode/d2j/CallSite.java create mode 100644 dex-translator/src/test/resources/dexes/dex038.dex create mode 100644 dex-writer/src/main/java/com/googlecode/d2j/dex/writer/item/CallSiteIdItem.java delete mode 100644 dex-writer/src/main/java/com/googlecode/d2j/dex/writer/item/EncodedArrayItem.java diff --git a/d2j-smali/src/main/antlr4/com/googlecode/d2j/smali/antlr4/Smali.g4 b/d2j-smali/src/main/antlr4/com/googlecode/d2j/smali/antlr4/Smali.g4 index fdfb29062..506fd2a95 100644 --- a/d2j-smali/src/main/antlr4/com/googlecode/d2j/smali/antlr4/Smali.g4 +++ b/d2j-smali/src/main/antlr4/com/googlecode/d2j/smali/antlr4/Smali.g4 @@ -175,8 +175,7 @@ sAnnotationValue :sSubannotation |sBaseValue |sArrayValue - | ( '.iget' | '.iput' | '.sget' | '.sput' ) FIELD_FULL - | ( '.invoke-instance' | '.invoke-static' ) METHOD_FULL + | method_handler ;// field,method,array,subannotation sBaseValue :STRING @@ -199,6 +198,11 @@ method_handler | type=('invoke-static'|'invoke-instance'|'invoke-direct'|'invoke-interface'|'invoke-constructor') '@' mtd=METHOD_FULL ; +// FIXME samli syntax only write out method_handler's method field +call_site + : name=sAnnotationKeyName '(' method_name=STRING ',' method_type=METHOD_PROTO (',' sBaseValue)* ')' '@' bsm=METHOD_FULL + ; + sInstruction :fline |flocal @@ -415,9 +419,9 @@ fm45cc : op='invoke-polymorphic' '{' (REGISTER (',' REGISTER)* )? '}' ',' metho ; fm4rcc : op='invoke-polymorphic/range' '{' (rstart=REGISTER '..' rend=REGISTER)? '}' ',' method=METHOD_FULL ',' proto=METHOD_PROTO ; -fmcustomc : op='invoke-custom' '{' (REGISTER (',' REGISTER)* )? '}' ',' sArrayValue +fmcustomc : op='invoke-custom' '{' (REGISTER (',' REGISTER)* )? '}' ',' call_site ; -fmcustomrc : op='invoke-custom/range' '{' (rstart=REGISTER '..' rend=REGISTER)? '}' ',' sArrayValue +fmcustomrc : op='invoke-custom/range' '{' (rstart=REGISTER '..' rend=REGISTER)? '}' ',' call_site ; 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; diff --git a/d2j-smali/src/main/java/com/googlecode/d2j/smali/AntlrSmaliUtil.java b/d2j-smali/src/main/java/com/googlecode/d2j/smali/AntlrSmaliUtil.java index b5ef7b65f..6c3a85ea4 100644 --- a/d2j-smali/src/main/java/com/googlecode/d2j/smali/AntlrSmaliUtil.java +++ b/d2j-smali/src/main/java/com/googlecode/d2j/smali/AntlrSmaliUtil.java @@ -431,6 +431,65 @@ public Object visitFm5c(SmaliParser.Fm5cContext ctx) { return null; } + @Override + public Object visitFm4rcc(SmaliParser.Fm4rccContext ctx) { + if (ctx.rstart != null) { + int start = m.pareReg(ctx.rstart.getText()); + int end = m.pareReg(ctx.rend.getText()); + int size = end - start + 1; + int[] rs = new int[size]; + for (int i = 0; i < size; i++) { + rs[i] = start + i; + } + scv.visitMethodStmt(getOp(ctx.op), rs, parseMethodAndUnescape(ctx.method.getText()), parseProtoAndUnescape(ctx.proto.getText())); + } else { + scv.visitMethodStmt(getOp(ctx.op), new int[0], parseMethodAndUnescape(ctx.method.getText()), parseProtoAndUnescape(ctx.proto.getText())); + } + return null; + } + + @Override + public Object visitFm45cc(SmaliParser.Fm45ccContext ctx) { + Op op = getOp(ctx.op); + List ts = ctx.REGISTER(); + int[] rs = new int[ts.size()]; + for (int i = 0; i < ts.size(); i++) { + rs[i] = m.pareReg(ts.get(i).getSymbol().getText()); + } + scv.visitMethodStmt(op, rs, parseMethodAndUnescape(ctx.method.getText()), parseProtoAndUnescape(ctx.proto.getText())); + return null; + } + + @Override + public Object visitFmcustomc(SmaliParser.FmcustomcContext ctx) { + Op op = getOp(ctx.op); + + List ts = ctx.REGISTER(); + int[] rs = new int[ts.size()]; + for (int i = 0; i < ts.size(); i++) { + rs[i] = m.pareReg(ts.get(i).getSymbol().getText()); + } + scv.visitMethodStmt(op, rs, parseCallSite(ctx.call_site())); + return null; + } + + @Override + public Object visitFmcustomrc(SmaliParser.FmcustomrcContext ctx) { + if (ctx.rstart != null) { + int start = m.pareReg(ctx.rstart.getText()); + int end = m.pareReg(ctx.rend.getText()); + int size = end - start + 1; + int[] rs = new int[size]; + for (int i = 0; i < size; i++) { + rs[i] = start + i; + } + scv.visitMethodStmt(getOp(ctx.op), rs, parseCallSite(ctx.call_site())); + } else { + scv.visitMethodStmt(getOp(ctx.op), new int[0], parseCallSite(ctx.call_site())); + } + return null; + } + @Override public Object visitFmrc(SmaliParser.FmrcContext ctx) { if (ctx.rstart != null) { @@ -554,6 +613,25 @@ public Object visitFepiogue(SmaliParser.FepiogueContext ctx) { scv.visitEnd(); } + private static CallSite parseCallSite(SmaliParser.Call_siteContext callSiteContext) { + + List sBaseValueContexts = callSiteContext.sBaseValue(); + Object[] args = new Object[sBaseValueContexts.size()]; + int i = 0; + for (SmaliParser.SBaseValueContext baseValueContext : sBaseValueContexts) { + args[i] = parseBaseValue(baseValueContext); + i++; + } + + return new CallSite( + unEscapeId(callSiteContext.name.getText()), + new MethodHandle(MethodHandle.INVOKE_STATIC, parseMethodAndUnescape(callSiteContext.bsm.getText())), + unescapeStr(callSiteContext.method_name.getText()), + parseProtoAndUnescape(callSiteContext.method_type.getText()), + args + ); + } + private static MethodHandle parseMethodHandler(SmaliParser.Method_handlerContext methodHandlerContext) { MethodHandle value; switch (methodHandlerContext.type.getText()) { @@ -781,6 +859,10 @@ private static void acceptAnnotation(DexAnnotationVisitor dexAnnotationVisitor, Object value = parseBaseValue(baseValueContext); dexAnnotationVisitor.visit(name, value); break; + case SmaliParser.RULE_method_handler: + MethodHandle methodHandle = parseMethodHandler((SmaliParser.Method_handlerContext) t); + dexAnnotationVisitor.visit(name, methodHandle); + break; } } diff --git a/d2j-smali/src/main/java/com/googlecode/d2j/smali/BaksmaliCodeDumper.java b/d2j-smali/src/main/java/com/googlecode/d2j/smali/BaksmaliCodeDumper.java index 0bb5f9ce7..a4d911eeb 100644 --- a/d2j-smali/src/main/java/com/googlecode/d2j/smali/BaksmaliCodeDumper.java +++ b/d2j-smali/src/main/java/com/googlecode/d2j/smali/BaksmaliCodeDumper.java @@ -385,14 +385,25 @@ public void visitMethodStmt(Op op, int[] args, Method method, Proto proto) { } @Override - public void visitMethodStmt(Op op, int[] args, String name, Proto proto, MethodHandle bsm, Object... bsmArgs) { + public void visitMethodStmt(Op op, int[] args, CallSite callSite) { 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)); + Object[] extraArguments = callSite.getExtraArguments(); + + // invoke-custom/range {v0 .. v5}, call_site_1("runDynamic", (IIIIII)V, 0x378)@L038;->bsm(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;I)Ljava/lang/invoke/CallSite; + + sb + .append(BaksmaliDumper.escapeId(callSite.getName())) + .append('(') + .append(BaksmaliDumper.escapeValue(callSite.getMethodName())) + .append(", ") + .append(BaksmaliDumper.escapeMethodDesc(callSite.getMethodProto())); + if (extraArguments != null && extraArguments.length > 0) { + for (Object o : extraArguments) { + sb.append(", ").append(BaksmaliDumper.escapeValue(o)); + } } - sb.append("}"); - + // FIXME samli syntax only write out method_handler's method field + sb.append(")@").append(BaksmaliDumper.escapeMethod(callSite.getBootstrapMethodHandler().getMethod())); if (args.length > 0) { if (op.format == InstructionFormat.kFmt3rc) { // invoke-x/range diff --git a/d2j-smali/src/test/java/a/SmaliTest.java b/d2j-smali/src/test/java/a/SmaliTest.java index a01a5e588..b5bb0dbfe 100644 --- a/d2j-smali/src/test/java/a/SmaliTest.java +++ b/d2j-smali/src/test/java/a/SmaliTest.java @@ -72,14 +72,7 @@ public void test2() throws IOException { private void dotest(File dexFile) throws IOException { int dexVersion = new DexFileReader(dexFile).getDexVersion(); - Opcodes opcodes; - if (dexVersion >= DexConstants.DEX_039) { - opcodes = Opcodes.forApi(28); - } else if (dexVersion >= DexConstants.DEX_037) { - opcodes = Opcodes.forApi(26); - } else { - opcodes = Opcodes.forApi(0); - } + Opcodes opcodes = Opcodes.forApi(DexConstants.toMiniAndroidApiLevel(dexVersion)); DexBackedDexFile dex; try { dex = DexFileFactory.loadDexFile(dexFile, opcodes); diff --git a/dex-reader-api/src/main/java/com/googlecode/d2j/CallSite.java b/dex-reader-api/src/main/java/com/googlecode/d2j/CallSite.java new file mode 100644 index 000000000..ea8f92874 --- /dev/null +++ b/dex-reader-api/src/main/java/com/googlecode/d2j/CallSite.java @@ -0,0 +1,37 @@ +package com.googlecode.d2j; + +public class CallSite { + private String name; + private MethodHandle bootstrapMethodHandler; + private String methodName; + private Proto methodProto; + private Object[] extraArguments; + + public CallSite(String name, MethodHandle bootstrapMethodHandler, String methodName, Proto methodProto, Object... extraArguments) { + this.name = name; + this.bootstrapMethodHandler = bootstrapMethodHandler; + this.methodName = methodName; + this.methodProto = methodProto; + this.extraArguments = extraArguments; + } + + public String getName() { + return name; + } + + public MethodHandle getBootstrapMethodHandler() { + return bootstrapMethodHandler; + } + + public String getMethodName() { + return methodName; + } + + public Proto getMethodProto() { + return methodProto; + } + + public Object[] getExtraArguments() { + return extraArguments; + } +} diff --git a/dex-reader-api/src/main/java/com/googlecode/d2j/DexConstants.java b/dex-reader-api/src/main/java/com/googlecode/d2j/DexConstants.java index 2740833e4..430965cb3 100644 --- a/dex-reader-api/src/main/java/com/googlecode/d2j/DexConstants.java +++ b/dex-reader-api/src/main/java/com/googlecode/d2j/DexConstants.java @@ -52,10 +52,25 @@ public abstract interface DexConstants { String ANNOTATION_INNER_CLASS_TYPE = "Ldalvik/annotation/InnerClass;"; String ANNOTATION_MEMBER_CLASSES_TYPE = "Ldalvik/annotation/MemberClasses;"; + static int toMiniAndroidApiLevel(int dexVersion) { + if (dexVersion <= DEX_035 || dexVersion <= DEX_036) { + return 0; + } else if (dexVersion == DEX_037) { + return 24; + } else if (dexVersion == DEX_038) { + return 26; + } else { + return 28; + } + } int DEX_035 = 0x00303335; + @Deprecated int DEX_036 = 0x00303336; + // android 7.0, api 24 int DEX_037 = 0x00303337; + // android 8.0, api 26 int DEX_038 = 0x00303338; + // android 9.0, api 28 int DEX_039 = 0x00303339; int DEX_040 = 0x00303340; } diff --git a/dex-reader-api/src/main/java/com/googlecode/d2j/node/DexCodeNode.java b/dex-reader-api/src/main/java/com/googlecode/d2j/node/DexCodeNode.java index 044181734..7afbd6bed 100644 --- a/dex-reader-api/src/main/java/com/googlecode/d2j/node/DexCodeNode.java +++ b/dex-reader-api/src/main/java/com/googlecode/d2j/node/DexCodeNode.java @@ -110,8 +110,8 @@ public void visitMethodStmt(final Op op, final int[] args, final Method method) } @Override - public void visitMethodStmt(Op op, int[] args, String name, Proto proto, MethodHandle bsm, Object... bsmArgs) { - add(new MethodCustomStmtNode(op, args, name, proto, bsm, bsmArgs)); + public void visitMethodStmt(Op op, int[] args, CallSite callSite) { + add(new MethodCustomStmtNode(op, args, callSite)); } @Override diff --git a/dex-reader-api/src/main/java/com/googlecode/d2j/node/insn/MethodCustomStmtNode.java b/dex-reader-api/src/main/java/com/googlecode/d2j/node/insn/MethodCustomStmtNode.java index d11810e7d..2d84aa1d4 100644 --- a/dex-reader-api/src/main/java/com/googlecode/d2j/node/insn/MethodCustomStmtNode.java +++ b/dex-reader-api/src/main/java/com/googlecode/d2j/node/insn/MethodCustomStmtNode.java @@ -15,32 +15,26 @@ */ package com.googlecode.d2j.node.insn; -import com.googlecode.d2j.MethodHandle; +import com.googlecode.d2j.CallSite; import com.googlecode.d2j.Proto; import com.googlecode.d2j.reader.Op; import com.googlecode.d2j.visitors.DexCodeVisitor; public class MethodCustomStmtNode extends AbstractMethodStmtNode { - public final String name; - public final Proto proto; - public final MethodHandle bsm; - public final Object[] bsmArgs; + public final CallSite callSite; - public MethodCustomStmtNode(Op op, int[] args, String name, Proto proto, MethodHandle bsm, Object[] bsmArgs) { + public MethodCustomStmtNode(Op op, int[] args, CallSite callSite) { super(op, args); - this.proto = proto; - this.name = name; - this.bsm = bsm; - this.bsmArgs = bsmArgs; + this.callSite = callSite; } @Override public void accept(DexCodeVisitor cv) { - cv.visitMethodStmt(op, args, name, proto, bsm, bsmArgs); + cv.visitMethodStmt(op, args, callSite); } @Override public Proto getProto() { - return proto; + return callSite.getMethodProto(); } } diff --git a/dex-reader-api/src/main/java/com/googlecode/d2j/visitors/DexCodeVisitor.java b/dex-reader-api/src/main/java/com/googlecode/d2j/visitors/DexCodeVisitor.java index 64941574d..c15eda618 100644 --- a/dex-reader-api/src/main/java/com/googlecode/d2j/visitors/DexCodeVisitor.java +++ b/dex-reader-api/src/main/java/com/googlecode/d2j/visitors/DexCodeVisitor.java @@ -238,9 +238,9 @@ public void visitMethodStmt(Op op, int[] args, Method method) { * OP_INVOKE_CUSTOM * */ - public void visitMethodStmt(Op op, int[] args, String name, Proto proto, MethodHandle bsm, Object... bsmArgs) { + public void visitMethodStmt(Op op, int[] args, CallSite callSite) { if (visitor != null) { - visitor.visitMethodStmt(op, args, name, proto, bsm, bsmArgs); + visitor.visitMethodStmt(op, args, callSite); } } diff --git a/dex-reader/src/main/java/com/googlecode/d2j/reader/DexFileReader.java b/dex-reader/src/main/java/com/googlecode/d2j/reader/DexFileReader.java index be092cee1..9690ea901 100755 --- a/dex-reader/src/main/java/com/googlecode/d2j/reader/DexFileReader.java +++ b/dex-reader/src/main/java/com/googlecode/d2j/reader/DexFileReader.java @@ -205,7 +205,7 @@ public DexFileReader(ByteBuffer in) { int call_site_ids_size = 0; int method_handle_ids_off = 0; int method_handle_ids_size = 0; - if (dex_version > DEX_037) { + if (dex_version >= DEX_038) { in.position(map_off); int size = in.getInt(); for (int i = 0; i < size; i++) { @@ -1642,9 +1642,7 @@ private void acceptInsn(byte[] insns, DexCodeVisitor dcv, BitSet nextInsn, BitSe if (op.indexType == InstructionIndexType.kIndexTypeRef) { dcv.visitFilledNewArrayStmt(op, regs, getType(b)); } else if (op.indexType == InstructionIndexType.kIndexCallSiteRef) { - Object[] callsite = getCallSite(b); - Object[] constArgs = Arrays.copyOfRange(callsite, 3, callsite.length); - dcv.visitMethodStmt(op, regs, (String) callsite[1], (Proto) callsite[2], (MethodHandle) callsite[0], constArgs); + dcv.visitMethodStmt(op, regs, getCallSite(b)); } else { dcv.visitMethodStmt(op, regs, getMethod(b)); } @@ -1661,9 +1659,7 @@ private void acceptInsn(byte[] insns, DexCodeVisitor dcv, BitSet nextInsn, BitSe if (op.indexType == InstructionIndexType.kIndexTypeRef) { dcv.visitFilledNewArrayStmt(op, regs, getType(b)); } else if (op.indexType == InstructionIndexType.kIndexCallSiteRef) { - Object[] callsite = getCallSite(b); - Object[] constArgs = Arrays.copyOfRange(callsite, 3, callsite.length - 3); - dcv.visitMethodStmt(op, regs, (String) callsite[1], (Proto) callsite[2], (MethodHandle) callsite[0], constArgs); + dcv.visitMethodStmt(op, regs, getCallSite(b)); } else { dcv.visitMethodStmt(op, regs, getMethod(b)); } @@ -1785,11 +1781,24 @@ private void acceptInsn(byte[] insns, DexCodeVisitor dcv, BitSet nextInsn, BitSe } } - private Object[] getCallSite(int b) { + private CallSite getCallSite(int b) { callSiteIdIn.position(b * 4); int call_site_off = callSiteIdIn.getInt(); - return read_encoded_array_item(call_site_off); + Object[] call_site_items = read_encoded_array_item(call_site_off); + Object[] constArgs; + if (call_site_items.length > 3) { + constArgs = Arrays.copyOfRange(call_site_items, 3, call_site_items.length); + } else { + constArgs = new Object[0]; + } + + return new CallSite( + String.format("call_site_%d", b), + (MethodHandle) call_site_items[0], + (String) call_site_items[1], + (Proto) call_site_items[2], + constArgs); } /** diff --git a/dex-reader/src/main/java/com/googlecode/d2j/util/ASMifierCodeV.java b/dex-reader/src/main/java/com/googlecode/d2j/util/ASMifierCodeV.java index 7ad6ea541..796801e67 100644 --- a/dex-reader/src/main/java/com/googlecode/d2j/util/ASMifierCodeV.java +++ b/dex-reader/src/main/java/com/googlecode/d2j/util/ASMifierCodeV.java @@ -135,8 +135,8 @@ public void visitJumpStmt(Op op, int a, int b, DexLabel label) { } @Override - public void visitMethodStmt(Op op, int[] args, String name, Proto proto, MethodHandle bsm, Object... bsmArgs) { - m.s("code.visitMethodStmt(%s,%s,%s,%s,%s,%s);", op(op), Escape.v(args), Escape.v(name), Escape.v(proto), Escape.v(bsm), Escape.v(bsmArgs)); + public void visitMethodStmt(Op op, int[] args, CallSite callSite) { + m.s("code.visitMethodStmt(%s,%s,%s);", op(op), Escape.v(args), Escape.v(callSite)); } @Override diff --git a/dex-reader/src/main/java/com/googlecode/d2j/util/Escape.java b/dex-reader/src/main/java/com/googlecode/d2j/util/Escape.java index 5f349756d..aa63e6400 100644 --- a/dex-reader/src/main/java/com/googlecode/d2j/util/Escape.java +++ b/dex-reader/src/main/java/com/googlecode/d2j/util/Escape.java @@ -263,6 +263,26 @@ public static String v(Object[] vs) { return sb.append("}").toString(); } + public static String v(CallSite callSite) { + StringBuilder sb = new StringBuilder() + .append("new CallSite(") + .append(v(callSite.getName())) + .append(", ") + .append(v(callSite.getBootstrapMethodHandler())) + .append(", ") + .append(v(callSite.getMethodName())) + .append(", ") + .append(v(callSite.getMethodProto())); + Object[] extraArguments = callSite.getExtraArguments(); + if (extraArguments != null && extraArguments.length > 0) { + for (Object arg : extraArguments) { + sb.append(", ").append(v(arg)); + } + } + sb.append(")"); + return sb.toString(); + } + public static String v(Object obj) { if (obj == null) { return "null"; @@ -287,6 +307,9 @@ public static String v(Object obj) { if (obj instanceof MethodHandle) { return v((MethodHandle) obj); } + if (obj instanceof CallSite) { + return v((CallSite) obj); + } if (obj instanceof Integer) { return " Integer.valueOf(" + obj + ")"; diff --git a/dex-translator/src/main/java/com/googlecode/d2j/converter/Dex2IRConverter.java b/dex-translator/src/main/java/com/googlecode/d2j/converter/Dex2IRConverter.java index d70c8200a..8eede67d8 100644 --- a/dex-translator/src/main/java/com/googlecode/d2j/converter/Dex2IRConverter.java +++ b/dex-translator/src/main/java/com/googlecode/d2j/converter/Dex2IRConverter.java @@ -1135,7 +1135,11 @@ public DvmValue naryOperation(DexStmtNode insn, List values) vs[i] = getLocal(values.get(i)); } MethodCustomStmtNode n = (MethodCustomStmtNode) insn; - Value invoke = nInvokeCustom(vs, n.name, n.proto, n.bsm, n.bsmArgs); + Value invoke = nInvokeCustom(vs, + n.callSite.getMethodName(), + n.callSite.getMethodProto(), + n.callSite.getBootstrapMethodHandler(), + n.callSite.getExtraArguments()); if ("V".equals(n.getProto().getReturnType())) { emit(nVoidInvoke(invoke)); return null; diff --git a/dex-translator/src/test/java/com/googlecode/dex2jar/test/TestUtils.java b/dex-translator/src/test/java/com/googlecode/dex2jar/test/TestUtils.java index 30c4f1fb6..04907391b 100644 --- a/dex-translator/src/test/java/com/googlecode/dex2jar/test/TestUtils.java +++ b/dex-translator/src/test/java/com/googlecode/dex2jar/test/TestUtils.java @@ -47,12 +47,10 @@ import org.objectweb.asm.tree.analysis.BasicVerifier; import org.objectweb.asm.tree.analysis.Frame; import org.objectweb.asm.util.CheckClassAdapter; -import org.objectweb.asm.util.Printer; import org.objectweb.asm.util.Textifier; import org.objectweb.asm.util.TraceMethodVisitor; import java.io.*; -import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.net.URL; @@ -329,11 +327,7 @@ public ClassVisitor create(String classInternalName) { cfOptions.strictNameCheck = false; DexOptions dexOptions = new DexOptions(); if (fileNode != null) { - if (fileNode.dexVersion >= DexConstants.DEX_039) { - dexOptions.minSdkVersion = 28; - } else if (fileNode.dexVersion >= DexConstants.DEX_037) { - dexOptions.minSdkVersion = 26; - } + dexOptions.minSdkVersion = DexConstants.toMiniAndroidApiLevel(fileNode.dexVersion); } DirectClassFile dcf = new DirectClassFile(data, rca.getClassName() + ".class", true); diff --git a/dex-translator/src/test/resources/dexes/dex038.dex b/dex-translator/src/test/resources/dexes/dex038.dex new file mode 100644 index 0000000000000000000000000000000000000000..54ee2641c739d6096f44818ba30a547af42a1765 GIT binary patch literal 1376 zcmaKsJ!lj`6vyA}?e68<%U*JchG2?7>`u@^II++mIao=Na0FAtP3}lG+1p(%mvHF} zSO{WiXQ5!5E{KRWRw9-P7S~t^3Mnl@{QUp-gIoyuj^DjEZ{EzjH#;-cTC3;cr7L2- zc{X+Z@!rAB#dk9=Z_n?2-gUpuJbiuPjv*3?NUL($f{J8c7a4;^e;;UrF4_uziO}z% zP1k$;Eo2a*i5vk9wgLJ;4ivyRm;xm*3q0@;JO>}aC(s68z&G$4vvL+Xlf<*0Az&iQSR0YX5>d^pgYpML z{fNat?m<6D>_kO%a-WzRHHCd)j=RMQkA?o9QF9>LQ|3Y8ep)%Dl%_IDSH>@sGYz0V zRvHUqt=!Q>H+(w!x}f<@DEtoAU^Y~i%BvwYtO`G}+*bo}$63X-F(b~-HCbmCvoTZV zmfC3@X@2O6gns&{d&Ru!`fl@@sInL~u0TmN+ZNr1zyT>smtC#3qAtr`ceb6P=lH9| z+2!@xO0y)LzPV<@^;b(W))D9W+rdVyc*F6$Ik#CW$@$Zrw`$F`pgQCDRSyAE{}0%l zw1Z${D=f+QzXIoXLd>HoqE*V0t&}4{!BwDXKt}i`}Eq{8)cj}1E6lCPwa7HgEC}XmP z?`n#+dsn}&tL`V@1!#jqws|UINxw67`X2GTrEe0?NBS=D{-$qIdItC|@eFdz0c^(7 oK7_3%; max_out_reg_size) { + max_out_reg_size = args.length; + } + } + + @Override + public void visitMethodStmt(Op op, int[] args, Method bsm, Proto proto) { + cp.dex038(); + if (op.format == kFmt4rcc) { + ops.add(new CodeWriter.OP4rcc(op, args, cp.uniqMethod(bsm), cp.uniqProto(proto))); + } else if (op.format == kFmt45cc) { + ops.add(new CodeWriter.OP45cc(op, args, cp.uniqMethod(bsm), cp.uniqProto(proto))); + } + + if (args.length > max_out_reg_size) { + max_out_reg_size = args.length; + } + } + @Override public void visitPackedSwitchStmt(Op op, int aA, final int first_case, final DexLabel[] labels) { Label switch_data_location = new Label(); @@ -750,6 +782,95 @@ public void write(ByteBuffer out) { // A|G|op BBBB F|E|D|C } } + //A|G|op BBBB F|E|D|C HHHH + public static class OP45cc extends OpInsn { + final BaseItem mtd; + final BaseItem proto; + int A, C, D, E, F, G; + + public OP45cc(Op op, int[] args, BaseItem mtd, BaseItem proto) { + super(op); + int A = args.length; + if (A > 5) { + throw new CantNotFixContentException(op, "A", A); + } + this.A = A; + switch (A) { // [A=5] op {vC, vD, vE, vF, vG}, + case 5: + G = args[4]; + checkContentU4bit(op, "vG", G); + case 4: + F = args[3]; + checkContentU4bit(op, "vF", F); + case 3: + E = args[2]; + checkContentU4bit(op, "vE", E); + case 2: + D = args[1]; + checkContentU4bit(op, "vD", D); + case 1: + C = args[0]; + checkContentU4bit(op, "vC", C); + break; + } + this.mtd = mtd; + this.proto = proto; + } + + @Override + public void write(ByteBuffer out) { // A|G|op BBBB F|E|D|C HHHH + checkContentUShort(op, "@BBBB", mtd.index); + checkContentUShort(op, "@HHHH", proto.index); + out + .put((byte) op.opcode).put((byte) ((A << 4) | (G & 0xF))) // + .putShort((short) mtd.index) // + .put((byte) ((D << 4) | (C & 0xF))).put((byte) ((F << 4) | (E & 0xF))) // + .putShort((short) proto.index) // + + ; + } + } + // AA|op BBBB CCCC HHHH + public static class OP4rcc extends OpInsn { + final BaseItem mtd; + final BaseItem proto; + final int length; + final int start; + + public OP4rcc(Op op, int[] args, BaseItem mtd, BaseItem proto) { + super(op); + this.mtd = mtd; + this.proto = proto; + length = args.length; + checkContentUByte(op, "AA", length); + if (length > 0) { + start = args[0]; + checkContentUShort(op, "CCCC", start); + for (int i = 1; i < args.length; i++) { + if (start + i != args[i]) { + throw new CantNotFixContentException(op, "a", args[i]); + } + } + } else { + start = 0; + } + + } + + @Override + public void write(ByteBuffer out) { + checkContentUShort(op, "@BBBB", mtd.index); + checkContentUShort(op, "@HHHH", proto.index); + out + .put((byte) op.opcode).put((byte) length) // + .putShort((short) mtd.index) // + .putShort((short) start) // + .putShort((short) proto.index) // + ; + + } + } + // AA|op BBBB CCCC public static class OP3rc extends OpInsn { final BaseItem item; diff --git a/dex-writer/src/main/java/com/googlecode/d2j/dex/writer/DexFileWriter.java b/dex-writer/src/main/java/com/googlecode/d2j/dex/writer/DexFileWriter.java index f8aa6517b..235bd0c90 100644 --- a/dex-writer/src/main/java/com/googlecode/d2j/dex/writer/DexFileWriter.java +++ b/dex-writer/src/main/java/com/googlecode/d2j/dex/writer/DexFileWriter.java @@ -16,6 +16,7 @@ */ package com.googlecode.d2j.dex.writer; +import com.googlecode.d2j.dex.writer.ev.EncodedArray; import com.googlecode.d2j.dex.writer.io.ByteBufferOut; import com.googlecode.d2j.dex.writer.io.DataOut; import com.googlecode.d2j.dex.writer.item.*; @@ -124,6 +125,7 @@ void buildMapListItem() { mapItem = new MapListItem(); headItem = new HeadItem(); + headItem.version = cp.dexVersion; SectionItem headSection = new SectionItem<>(SectionType.TYPE_HEADER_ITEM); headSection.items.add(headItem); SectionItem mapSection = new SectionItem(SectionType.TYPE_MAP_LIST); @@ -160,8 +162,10 @@ void buildMapListItem() { SectionType.TYPE_DEBUG_INFO_ITEM, cp.debugInfoItems); SectionItem annotationItemSection = new SectionItem<>( SectionType.TYPE_ANNOTATION_ITEM, cp.annotationItems.values()); - SectionItem encodedArrayItemSection = new SectionItem<>( - SectionType.TYPE_ENCODED_ARRAY_ITEM, cp.encodedArrayItems); + SectionItem encodedArrayItemSection = new SectionItem<>( + SectionType.TYPE_ENCODED_ARRAY_ITEM, cp.encodedArrayItems.values()); + SectionItem callSiteIdItemSectionItem = new SectionItem<>( + SectionType.TYPE_CALL_SITE_ID_ITEM, cp.callSiteIdItems.values()); SectionItem annotationsDirectoryItemSection = new SectionItem<>( SectionType.TYPE_ANNOTATIONS_DIRECTORY_ITEM, cp.annotationsDirectoryItems); @@ -202,8 +206,13 @@ void buildMapListItem() { items.add(protoIdSection); items.add(fieldIdSection); items.add(methodIdSection); - items.add(methodHandlerSection); items.add(classDefSection); + if (callSiteIdItemSectionItem.items.size() > 0) { + items.add(callSiteIdItemSectionItem); + } + if (methodHandlerSection.items.size() > 0) { + items.add(methodHandlerSection); + } items.addAll(dataSectionItems); } diff --git a/dex-writer/src/main/java/com/googlecode/d2j/dex/writer/ev/EncodedAnnotation.java b/dex-writer/src/main/java/com/googlecode/d2j/dex/writer/ev/EncodedAnnotation.java index 724ec1a71..6d368acd4 100644 --- a/dex-writer/src/main/java/com/googlecode/d2j/dex/writer/ev/EncodedAnnotation.java +++ b/dex-writer/src/main/java/com/googlecode/d2j/dex/writer/ev/EncodedAnnotation.java @@ -25,7 +25,7 @@ import java.util.ArrayList; import java.util.List; -public class EncodedAnnotation { +public class EncodedAnnotation implements Comparable { @Override public boolean equals(Object o) { if (this == o) return true; @@ -46,7 +46,33 @@ public int hashCode() { return result; } - public static class AnnotationElement { + @Override + public int compareTo(EncodedAnnotation o) { + if (o == null) { + return 1; + } + + int x = type.compareTo(o.type); + if (x != 0) { + return x; + } + x = Integer.compare(elements.size(), o.elements.size()); + if (x != 0) { + return x; + } + for (int i = 0; i < elements.size(); i++) { + AnnotationElement a = elements.get(i); + AnnotationElement b = o.elements.get(i); + + x = a.compareTo(b); + if (x != 0) { + return x; + } + } + return 0; + } + + public static class AnnotationElement implements Comparable { public StringIdItem name; public EncodedValue value; @@ -69,6 +95,18 @@ public int hashCode() { result = 31 * result + value.hashCode(); return result; } + + @Override + public int compareTo(AnnotationElement o) { + if (o == null) { + return 1; + } + int x = name.compareTo(o.name); + if (x != 0) { + return x; + } + return value.compareTo(o.value); + } } @Idx diff --git a/dex-writer/src/main/java/com/googlecode/d2j/dex/writer/ev/EncodedArray.java b/dex-writer/src/main/java/com/googlecode/d2j/dex/writer/ev/EncodedArray.java index 9eaca2fc7..67e9192a7 100644 --- a/dex-writer/src/main/java/com/googlecode/d2j/dex/writer/ev/EncodedArray.java +++ b/dex-writer/src/main/java/com/googlecode/d2j/dex/writer/ev/EncodedArray.java @@ -20,9 +20,10 @@ import com.googlecode.d2j.dex.writer.item.BaseItem; import java.util.ArrayList; +import java.util.Collections; import java.util.List; -public class EncodedArray { +public class EncodedArray extends BaseItem implements Comparable { public List values = new ArrayList<>(5); @@ -57,4 +58,24 @@ public void write(DataOut out) { ev.write(out); } } + + @Override + public int compareTo(EncodedArray o) { + if (o == null) { + return 1; + } + int x = Integer.compare(values.size(), o.values.size()); + if (x != 0) { + return x; + } + for (int i = 0; i < values.size(); i++) { + EncodedValue a = values.get(i); + EncodedValue b = o.values.get(i); + x = a.compareTo(b); + if (x != 0) { + return x; + } + } + return 0; + } } diff --git a/dex-writer/src/main/java/com/googlecode/d2j/dex/writer/ev/EncodedValue.java b/dex-writer/src/main/java/com/googlecode/d2j/dex/writer/ev/EncodedValue.java index 4c144923a..b655fc386 100644 --- a/dex-writer/src/main/java/com/googlecode/d2j/dex/writer/ev/EncodedValue.java +++ b/dex-writer/src/main/java/com/googlecode/d2j/dex/writer/ev/EncodedValue.java @@ -17,9 +17,15 @@ package com.googlecode.d2j.dex.writer.ev; import com.googlecode.d2j.dex.writer.io.DataOut; -import com.googlecode.d2j.dex.writer.item.*; +import com.googlecode.d2j.dex.writer.item.BaseItem; +import com.googlecode.d2j.dex.writer.item.FieldIdItem; +import com.googlecode.d2j.dex.writer.item.MethodHandleItem; +import com.googlecode.d2j.dex.writer.item.MethodIdItem; +import com.googlecode.d2j.dex.writer.item.ProtoIdItem; +import com.googlecode.d2j.dex.writer.item.StringIdItem; +import com.googlecode.d2j.dex.writer.item.TypeIdItem; -public class EncodedValue { +public class EncodedValue implements Comparable { public final static int VALUE_ANNOTATION = 0x1d; public final static int VALUE_ARRAY = 0x1c; @@ -32,6 +38,8 @@ public class EncodedValue { public final static int VALUE_FLOAT = 0x10; public final static int VALUE_INT = 0x04; public final static int VALUE_LONG = 0x06; + public final static int VALUE_METHOD_TYPE = 0x15; + public final static int VALUE_METHOD_HANDLE = 0x16; public final static int VALUE_METHOD = 0x1a; public final static int VALUE_NULL = 0x1e; public final static int VALUE_SHORT = 0x02; @@ -118,6 +126,10 @@ public static EncodedValue wrap(Object v) { return new EncodedValue(VALUE_FIELD, v); } else if (v instanceof MethodIdItem) { return new EncodedValue(VALUE_METHOD, v); + } else if (v instanceof MethodHandleItem) { + return new EncodedValue(VALUE_METHOD_HANDLE, v); + } else if (v instanceof ProtoIdItem) { + return new EncodedValue(VALUE_METHOD_TYPE, v); } @@ -258,6 +270,8 @@ protected int doPlace(int offset) { case VALUE_FIELD: case VALUE_METHOD: case VALUE_ENUM: + case VALUE_METHOD_HANDLE: + case VALUE_METHOD_TYPE: default: return offset + getValueArg() + 1; } @@ -289,6 +303,8 @@ protected int getValueArg() { case VALUE_FIELD: case VALUE_METHOD: case VALUE_ENUM: + case VALUE_METHOD_HANDLE: + case VALUE_METHOD_TYPE: BaseItem bi = (BaseItem) value; return lengthOfUint(bi.index) - 1; } @@ -331,6 +347,8 @@ public void write(DataOut out) { case VALUE_FIELD: case VALUE_METHOD: case VALUE_ENUM: + case VALUE_METHOD_HANDLE: + case VALUE_METHOD_TYPE: out.bytes("value_xidx", encodeLong(valueArg + 1, ((BaseItem) value).index)); break; case VALUE_ARRAY: { @@ -363,4 +381,55 @@ private byte[] writeRightZeroExtendedValue(int requiredBytes, long value) { return s; } + @Override + public int compareTo(EncodedValue o) { + if (o == null) { + return 1; + } + int x = Integer.compare(valueType, o.valueType); + if (x != 0) { + return x; + } + switch (valueType) { + case VALUE_NULL: + return 0; + case VALUE_BOOLEAN: + return Boolean.compare((Boolean) value, (Boolean) o.value); + case VALUE_SHORT: + return ((Short) value).compareTo((Short) o.value); + case VALUE_CHAR: + return ((Character) value).compareTo((Character) o.value); + case VALUE_INT: + return ((Integer) value).compareTo((Integer) o.value); + case VALUE_LONG: + return ((Long) value).compareTo((Long) o.value); + case VALUE_DOUBLE: + return Long.compare(Double.doubleToLongBits((Double) value), Double.doubleToLongBits((Double) o.value)); + case VALUE_FLOAT: + return Integer.compare(Float.floatToIntBits((Float) value), Float.floatToIntBits((Float) o.value)); + case VALUE_STRING: + case VALUE_TYPE: + case VALUE_FIELD: + case VALUE_METHOD: + case VALUE_ENUM: + case VALUE_METHOD_HANDLE: + case VALUE_METHOD_TYPE: + if (value instanceof Comparable) { + return ((Comparable) value).compareTo(value); + } else { + throw new RuntimeException(); + } + case VALUE_ARRAY: { + return ((EncodedArray) value).compareTo((EncodedArray) o.value); + } + case VALUE_ANNOTATION: { + return ((EncodedAnnotation) value).compareTo((EncodedAnnotation) o.value); + } + case VALUE_BYTE: { + return Byte.compare((Byte) value, (Byte) o.value); + } + default: + throw new RuntimeException(); + } + } } diff --git a/dex-writer/src/main/java/com/googlecode/d2j/dex/writer/item/CallSiteIdItem.java b/dex-writer/src/main/java/com/googlecode/d2j/dex/writer/item/CallSiteIdItem.java new file mode 100644 index 000000000..432ddd81b --- /dev/null +++ b/dex-writer/src/main/java/com/googlecode/d2j/dex/writer/item/CallSiteIdItem.java @@ -0,0 +1,46 @@ +package com.googlecode.d2j.dex.writer.item; + +import com.googlecode.d2j.dex.writer.ev.EncodedArray; +import com.googlecode.d2j.dex.writer.io.DataOut; + +public class CallSiteIdItem extends BaseItem implements Comparable { + String name; + EncodedArray encodedArrayItem; + + public CallSiteIdItem(String name, EncodedArray encodedArrayItem) { + this.name = name; + this.encodedArrayItem = encodedArrayItem; + } + + @Override + public void write(DataOut out) { + out.uint("call_site_off", encodedArrayItem.offset); + } + + @Override + public int place(int offset) { + return offset + 4; + } + + @Override + public int compareTo(CallSiteIdItem o) { + if (o == null) { + return 1; + } + if (name != null) { + if (o.name == null) { + return 1; + } else { + int x = name.compareTo(o.name); + if (x != 0) { + return x; + } + } + } else { + if (o.name != null) { + return -1; + } + } + return encodedArrayItem.compareTo(o.encodedArrayItem); + } +} diff --git a/dex-writer/src/main/java/com/googlecode/d2j/dex/writer/item/ClassDefItem.java b/dex-writer/src/main/java/com/googlecode/d2j/dex/writer/item/ClassDefItem.java index 804c4f697..a10993788 100644 --- a/dex-writer/src/main/java/com/googlecode/d2j/dex/writer/item/ClassDefItem.java +++ b/dex-writer/src/main/java/com/googlecode/d2j/dex/writer/item/ClassDefItem.java @@ -45,7 +45,7 @@ public class ClassDefItem extends BaseItem { @Off private AnnotationsDirectoryItem annotations;// Build later @Off - private EncodedArrayItem staticValues; // Build later + private EncodedArray staticValues; // Build later @Override public int place(int offset) { @@ -77,8 +77,7 @@ private void prepareEncodedArrayItem(ConstPool cp) { } if (count >= 0) { - EncodedArrayItem encodedArrayItem = cp.putEnCodedArrayItem(); - EncodedArray array = encodedArrayItem.value; + EncodedArray array = new EncodedArray(); for (int i = 0; i <= count; i++) { EncodedField f = fs.get(i); EncodedValue ev = f.staticValue; @@ -88,7 +87,7 @@ private void prepareEncodedArrayItem(ConstPool cp) { array.values.add(ev); } } - staticValues = encodedArrayItem; + staticValues = cp.uniqEncodedArrayItem(array); } } diff --git a/dex-writer/src/main/java/com/googlecode/d2j/dex/writer/item/ConstPool.java b/dex-writer/src/main/java/com/googlecode/d2j/dex/writer/item/ConstPool.java index 8ee9c2f95..4148a0189 100644 --- a/dex-writer/src/main/java/com/googlecode/d2j/dex/writer/item/ConstPool.java +++ b/dex-writer/src/main/java/com/googlecode/d2j/dex/writer/item/ConstPool.java @@ -16,17 +16,24 @@ */ package com.googlecode.d2j.dex.writer.item; +import com.googlecode.d2j.CallSite; +import com.googlecode.d2j.DexConstants; import com.googlecode.d2j.DexType; import com.googlecode.d2j.Field; import com.googlecode.d2j.Method; import com.googlecode.d2j.MethodHandle; import com.googlecode.d2j.Proto; import com.googlecode.d2j.dex.writer.DexWriteException; +import com.googlecode.d2j.dex.writer.ev.EncodedArray; +import com.googlecode.d2j.dex.writer.ev.EncodedValue; import java.util.*; public class ConstPool { - public List encodedArrayItems = new ArrayList<>(); + public int dexVersion = DexConstants.DEX_035; + + public Map callSiteIdItems = new TreeMap<>(); + public Map encodedArrayItems = new TreeMap<>(); public Map annotationSetRefListItems = new HashMap<>(); public List codeItems = new ArrayList<>(); public List classDataItems = new ArrayList<>(); @@ -46,17 +53,17 @@ public class ConstPool { public Object wrapEncodedItem(Object value) { if (value instanceof DexType) { - value = uniqType(((DexType) value).desc); + return uniqType(((DexType) value).desc); } else if (value instanceof Field) { - value = uniqField((Field) value); + return uniqField((Field) value); } else if (value instanceof String) { - value = uniqString((String) value); + return uniqString((String) value); } else if (value instanceof Method) { - value = uniqMethod((Method) value); + return uniqMethod((Method) value); } else if (value instanceof MethodHandle) { - value = uniqMethodHandle((MethodHandle) value); + return uniqMethodHandle((MethodHandle) value); } else if (value instanceof Proto) { - value = uniqProto((Proto) value); + return uniqProto((Proto) value); } return value; } @@ -129,6 +136,18 @@ public void addDebugInfoItem(DebugInfoItem debugInfoItem) { debugInfoItems.add(debugInfoItem); } + public void dex039() { + if (dexVersion < DexConstants.DEX_039) { + dexVersion = DexConstants.DEX_039; + } + } + + public void dex038() { + if (dexVersion < DexConstants.DEX_038) { + dexVersion = DexConstants.DEX_038; + } + } + static class PE { final ClassDefItem owner; final Iterator it; @@ -249,7 +268,7 @@ public MethodIdItem uniqMethod(MethodIdItem key) { return key; } - private ProtoIdItem uniqProto(Proto method) { + public ProtoIdItem uniqProto(Proto method) { return uniqProto(method.getParameterTypes(), method.getReturnType()); } private ProtoIdItem uniqProto(Method method) { @@ -337,11 +356,31 @@ public ClassDataItem addClassDataItem(ClassDataItem dataItem) { return dataItem; } - // TODO change EncodedArrayItem to uniq - public EncodedArrayItem putEnCodedArrayItem() { - EncodedArrayItem arrayItem = new EncodedArrayItem(); - encodedArrayItems.add(arrayItem); - return arrayItem; + public CallSiteIdItem uniqCallSite(CallSite callSite) { + EncodedArray e = new EncodedArray(); + e.values.add(new EncodedValue(EncodedValue.VALUE_METHOD_HANDLE, uniqMethodHandle(callSite.getBootstrapMethodHandler()))); + e.values.add(new EncodedValue(EncodedValue.VALUE_STRING, uniqString(callSite.getMethodName()))); + e.values.add(new EncodedValue(EncodedValue.VALUE_METHOD_TYPE, uniqProto(callSite.getMethodProto()))); + for (Object arg : callSite.getExtraArguments()) { + e.values.add(EncodedValue.wrap(wrapEncodedItem(arg))); + } + CallSiteIdItem k = new CallSiteIdItem(callSite.getName(), uniqEncodedArrayItem(e)); + + CallSiteIdItem v = callSiteIdItems.get(k); + if (v == null) { + v = k; + callSiteIdItems.put(v, v); + } + return v; + } + + public EncodedArray uniqEncodedArrayItem(EncodedArray k) { + EncodedArray v = encodedArrayItems.get(k); + if (v == null) { + v = k; + encodedArrayItems.put(v, v); + } + return v; } public AnnotationSetItem uniqAnnotationSetItem(AnnotationSetItem key) { diff --git a/dex-writer/src/main/java/com/googlecode/d2j/dex/writer/item/EncodedArrayItem.java b/dex-writer/src/main/java/com/googlecode/d2j/dex/writer/item/EncodedArrayItem.java deleted file mode 100644 index c36530d2e..000000000 --- a/dex-writer/src/main/java/com/googlecode/d2j/dex/writer/item/EncodedArrayItem.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * dex2jar - Tools to work with android .dex and java .class files - * Copyright (c) 2009-2013 Panxiaobo - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.googlecode.d2j.dex.writer.item; - -import com.googlecode.d2j.dex.writer.ev.EncodedArray; -import com.googlecode.d2j.dex.writer.io.DataOut; - -public class EncodedArrayItem extends BaseItem { - public EncodedArray value = new EncodedArray(); - - @Override - public int place(int offset) { - return value.place(offset); - } - - @Override - public void write(DataOut out) { - value.write(out); - } -} diff --git a/dex-writer/src/main/java/com/googlecode/d2j/dex/writer/item/HeadItem.java b/dex-writer/src/main/java/com/googlecode/d2j/dex/writer/item/HeadItem.java index b7758f062..46906e7b1 100644 --- a/dex-writer/src/main/java/com/googlecode/d2j/dex/writer/item/HeadItem.java +++ b/dex-writer/src/main/java/com/googlecode/d2j/dex/writer/item/HeadItem.java @@ -16,13 +16,14 @@ */ package com.googlecode.d2j.dex.writer.item; +import com.googlecode.d2j.DexConstants; import com.googlecode.d2j.dex.writer.io.DataOut; -public class HeadItem extends BaseItem { +import java.nio.ByteBuffer; +import java.nio.ByteOrder; - public static final int V035 = 0x00353330; - public static final int V036 = 0x00363330; - public int version = V035; +public class HeadItem extends BaseItem { + public int version = DexConstants.DEX_035; public SectionItem mapSection; public SectionItem stringIdSection; public SectionItem typeIdSection; @@ -34,7 +35,9 @@ public class HeadItem extends BaseItem { public void write(DataOut out) { out.uint("magic", 0x0A786564); - out.uint("version", version); + + // version in DexConstants is big endian + out.bytes("version", writeBigEndian(version << 8)); out.skip4("checksum"); out.skip("signature", 20); out.uint("file_size", fileSize); @@ -64,6 +67,11 @@ public void write(DataOut out) { } + private static byte[] writeBigEndian(int value) { + return ByteBuffer.allocate(4).order(ByteOrder.BIG_ENDIAN) + .putInt(value).array(); + } + @Override public int place(int offset) { return offset + 0x70; diff --git a/dex-writer/src/main/java/com/googlecode/d2j/dex/writer/item/SectionItem.java b/dex-writer/src/main/java/com/googlecode/d2j/dex/writer/item/SectionItem.java index 38d3a88c6..0f89059ec 100644 --- a/dex-writer/src/main/java/com/googlecode/d2j/dex/writer/item/SectionItem.java +++ b/dex-writer/src/main/java/com/googlecode/d2j/dex/writer/item/SectionItem.java @@ -28,7 +28,6 @@ public class SectionItem extends BaseItem { final public SectionType sectionType; public final List items = new ArrayList<>(); - int size = 0; public SectionItem(SectionType typeCode) { super(); @@ -52,10 +51,6 @@ public static void main(String... strings) throws IllegalArgumentException, Ille } } - public int size() { - return size; - } - public int place(int offset) { final int startOffset = offset; int index = 0; @@ -66,7 +61,6 @@ public int place(int offset) { index++; offset = t.place(offset); } - size = offset - startOffset; return offset; }