Add support for invoke-custom and related structures in baksmali

This commit is contained in:
Ben Gruver 2018-05-21 15:39:01 -07:00
parent e8760aa46b
commit 48d13b297f
3 changed files with 84 additions and 21 deletions

View File

@ -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());
}
}
}

View File

@ -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<T extends Instruction> 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<T extends Instruction> 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<T extends Instruction> 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<T extends Instruction> 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<T extends Instruction> 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<T extends Instruction> 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<T extends Instruction> 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<T extends Instruction> 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<T extends Instruction> 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;

View File

@ -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");
}