From 48d13b297fa3f1dbf38054bd8f9f4e294f09273f Mon Sep 17 00:00:00 2001 From: Ben Gruver Date: Mon, 21 May 2018 15:39:01 -0700 Subject: [PATCH] Add support for invoke-custom and related structures in baksmali --- .../EncodedValue/EncodedValueAdaptor.java | 12 ++++ .../Format/InstructionMethodItem.java | 59 ++++++++++++------- .../baksmali/Adaptors/ReferenceFormatter.java | 34 +++++++++++ 3 files changed, 84 insertions(+), 21 deletions(-) diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/EncodedValue/EncodedValueAdaptor.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/EncodedValue/EncodedValueAdaptor.java index bce1ff7a..880c7607 100644 --- a/baksmali/src/main/java/org/jf/baksmali/Adaptors/EncodedValue/EncodedValueAdaptor.java +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/EncodedValue/EncodedValueAdaptor.java @@ -30,6 +30,7 @@ package org.jf.baksmali.Adaptors.EncodedValue; import org.jf.baksmali.Adaptors.ReferenceFormatter; import org.jf.baksmali.Renderers.*; +import org.jf.dexlib2.ReferenceType; import org.jf.dexlib2.ValueType; import org.jf.dexlib2.iface.value.*; import org.jf.dexlib2.util.ReferenceUtil; @@ -107,6 +108,17 @@ public abstract class EncodedValueAdaptor { return; case ValueType.TYPE: writer.write(((TypeEncodedValue)encodedValue).getValue()); + return; + case ValueType.METHOD_TYPE: + ReferenceFormatter.writeReference(writer, ReferenceType.METHOD_PROTO, + ((MethodTypeEncodedValue)encodedValue).getValue()); + return; + case ValueType.METHOD_HANDLE: + ReferenceFormatter.writeReference(writer, ReferenceType.METHOD_HANDLE, + ((MethodHandleEncodedValue)encodedValue).getValue()); + return; + default: + throw new IllegalArgumentException("Unknown encoded value type: " + encodedValue.getValueType()); } } } diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/InstructionMethodItem.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/InstructionMethodItem.java index b69995df..d5b0bf34 100644 --- a/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/InstructionMethodItem.java +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/InstructionMethodItem.java @@ -31,6 +31,7 @@ package org.jf.baksmali.Adaptors.Format; import org.jf.baksmali.Adaptors.MethodDefinition; import org.jf.baksmali.Adaptors.MethodDefinition.InvalidSwitchPayload; import org.jf.baksmali.Adaptors.MethodItem; +import org.jf.baksmali.Adaptors.ReferenceFormatter; import org.jf.baksmali.Renderers.LongRenderer; import org.jf.baksmali.BaksmaliOptions; import org.jf.dexlib2.Opcode; @@ -41,6 +42,7 @@ import org.jf.dexlib2.iface.instruction.*; import org.jf.dexlib2.iface.instruction.formats.Instruction20bc; import org.jf.dexlib2.iface.instruction.formats.Instruction31t; import org.jf.dexlib2.iface.instruction.formats.UnknownInstruction; +import org.jf.dexlib2.iface.reference.CallSiteReference; import org.jf.dexlib2.iface.reference.Reference; import org.jf.dexlib2.util.ReferenceUtil; import org.jf.util.ExceptionWithContext; @@ -87,12 +89,16 @@ public class InstructionMethodItem extends MethodItem { return String.format("%s@%d", ReferenceType.toString(type), ex.getInvalidIndex()); } + private interface Writable { + void writeTo(IndentingWriter writer) throws IOException; + } + @Override public boolean writeTo(IndentingWriter writer) throws IOException { Opcode opcode = instruction.getOpcode(); String verificationErrorName = null; - String referenceString = null; - String referenceString2 = null; + Writable referenceWritable = null; + Writable referenceWritable2 = null; boolean commentOutInstruction = false; @@ -109,25 +115,34 @@ public class InstructionMethodItem extends MethodItem { if (instruction instanceof ReferenceInstruction) { ReferenceInstruction referenceInstruction = (ReferenceInstruction)instruction; - String classContext = null; + final String classContext; if (methodDef.classDef.options.implicitReferences) { classContext = methodDef.method.getDefiningClass(); + } else { + classContext = null; } try { Reference reference = referenceInstruction.getReference(); - referenceString = ReferenceUtil.getReferenceString(reference, classContext); - assert referenceString != null; + if (reference instanceof CallSiteReference) { + referenceWritable = indentingWriter -> { + ReferenceFormatter.writeCallSiteReference(indentingWriter, (CallSiteReference)reference); + }; + } else { + referenceWritable = indentingWriter -> { + indentingWriter.write(ReferenceUtil.getReferenceString(reference, classContext)); + }; + } } catch (InvalidItemIndex ex) { commentOutInstruction = true; - referenceString = writeInvalidItemIndex(ex, referenceInstruction.getReferenceType(), + String referenceString = writeInvalidItemIndex(ex, referenceInstruction.getReferenceType(), writer); + referenceWritable = indentingWriter -> writer.write(referenceString); } catch (ReferenceType.InvalidReferenceTypeException ex) { writer.write("#invalid reference type: "); writer.printSignedIntAsDec(ex.getReferenceType()); commentOutInstruction = true; - - referenceString = "invalid_reference"; + referenceWritable = indentingWriter -> writer.write("invalid_reference"); } if (instruction instanceof DualReferenceInstruction) { @@ -135,17 +150,19 @@ public class InstructionMethodItem extends MethodItem { (DualReferenceInstruction) instruction; try { Reference reference2 = dualReferenceInstruction.getReference2(); - referenceString2 = ReferenceUtil.getReferenceString(reference2, classContext); + referenceWritable2 = indentingWriter -> { + indentingWriter.write(ReferenceUtil.getReferenceString(reference2, classContext)); + }; } catch (InvalidItemIndex ex) { commentOutInstruction = true; - referenceString2 = writeInvalidItemIndex(ex, + String referenceString = writeInvalidItemIndex(ex, dualReferenceInstruction.getReferenceType2(), writer); + referenceWritable2 = indentingWriter -> indentingWriter.write(referenceString); } catch (ReferenceType.InvalidReferenceTypeException ex) { writer.write("#invalid reference type: "); writer.printSignedIntAsDec(ex.getReferenceType()); commentOutInstruction = true; - - referenceString2 = "invalid_reference"; + referenceWritable2 = indentingWriter -> indentingWriter.write("invalid reference"); } } } @@ -235,7 +252,7 @@ public class InstructionMethodItem extends MethodItem { writer.write(' '); writer.write(verificationErrorName); writer.write(", "); - writer.write(referenceString); + referenceWritable.writeTo(writer); break; case Format20t: case Format30t: @@ -249,7 +266,7 @@ public class InstructionMethodItem extends MethodItem { writer.write(' '); writeFirstRegister(writer); writer.write(", "); - writer.write(referenceString); + referenceWritable.writeTo(writer); break; case Format21ih: case Format21lh: @@ -293,7 +310,7 @@ public class InstructionMethodItem extends MethodItem { writer.write(", "); writeSecondRegister(writer); writer.write(", "); - writer.write(referenceString); + referenceWritable.writeTo(writer); break; case Format22cs: writeOpcode(writer); @@ -335,7 +352,7 @@ public class InstructionMethodItem extends MethodItem { writer.write(' '); writeInvokeRegisters(writer); writer.write(", "); - writer.write(referenceString); + referenceWritable.writeTo(writer); break; case Format35mi: writeOpcode(writer); @@ -356,7 +373,7 @@ public class InstructionMethodItem extends MethodItem { writer.write(' '); writeInvokeRangeRegisters(writer); writer.write(", "); - writer.write(referenceString); + referenceWritable.writeTo(writer); break; case Format3rmi: writeOpcode(writer); @@ -377,18 +394,18 @@ public class InstructionMethodItem extends MethodItem { writer.write(' '); writeInvokeRegisters(writer); writer.write(", "); - writer.write(referenceString); + referenceWritable.writeTo(writer); writer.write(", "); - writer.write(referenceString2); + referenceWritable2.writeTo(writer); break; case Format4rcc: writeOpcode(writer); writer.write(' '); writeInvokeRangeRegisters(writer); writer.write(", "); - writer.write(referenceString); + referenceWritable.writeTo(writer); writer.write(", "); - writer.write(referenceString2); + referenceWritable2.writeTo(writer); break; default: assert false; diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/ReferenceFormatter.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/ReferenceFormatter.java index 91d142a8..e609803b 100644 --- a/baksmali/src/main/java/org/jf/baksmali/Adaptors/ReferenceFormatter.java +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/ReferenceFormatter.java @@ -28,8 +28,11 @@ package org.jf.baksmali.Adaptors; +import org.jf.baksmali.Adaptors.EncodedValue.EncodedValueAdaptor; +import org.jf.dexlib2.MethodHandleType; import org.jf.dexlib2.ReferenceType; import org.jf.dexlib2.iface.reference.*; +import org.jf.dexlib2.iface.value.EncodedValue; import org.jf.dexlib2.util.ReferenceUtil; import org.jf.util.IndentingWriter; import org.jf.util.StringUtils; @@ -43,6 +46,26 @@ public class ReferenceFormatter { writer.write('"'); } + public static void writeCallSiteReference(IndentingWriter writer, CallSiteReference callSite) throws IOException { + writer.write(callSite.getName()); + writer.write('('); + writer.write('"'); + StringUtils.writeEscapedString(writer, callSite.getMethodName()); + writer.write("\", "); + writeReference(writer, ReferenceType.METHOD_PROTO, callSite.getMethodProto()); + + for (EncodedValue encodedValue : callSite.getExtraArguments()) { + writer.write(", "); + EncodedValueAdaptor.writeTo(writer, encodedValue, null); + } + writer.write(")@"); + MethodHandleReference methodHandle = callSite.getMethodHandle(); + if (methodHandle.getMethodHandleType() != MethodHandleType.STATIC_INVOKE) { + throw new IllegalArgumentException("The linker method handle for a call site must be of type static-invoke"); + } + writeReference(writer, ReferenceType.METHOD, callSite.getMethodHandle().getMemberReference()); + } + public static void writeReference(IndentingWriter writer, int referenceType, Reference reference) throws IOException { switch (referenceType) { @@ -58,6 +81,17 @@ public class ReferenceFormatter { case ReferenceType.FIELD: ReferenceUtil.writeFieldDescriptor(writer, (FieldReference)reference); return; + case ReferenceType.METHOD_PROTO: + ReferenceUtil.writeMethodProtoDescriptor(writer, (MethodProtoReference)reference); + return; + case ReferenceType.METHOD_HANDLE: + ReferenceUtil.writeMethodHandle(writer, (MethodHandleReference)reference); + return; + case ReferenceType.CALL_SITE: + // We can't use ReferenceUtil.writeCallSite here, because it doesn't write encoded values out in the + // exact format we need here. + writeCallSiteReference(writer, (CallSiteReference)reference); + return; default: throw new IllegalStateException("Unknown reference type"); }