Add support for writing code_items

This commit is contained in:
Izzat Bahadirov 2012-12-17 14:41:55 -05:00 committed by Ben Gruver
parent 56c7adde03
commit f3c33259dd
9 changed files with 681 additions and 84 deletions

View File

@ -40,10 +40,7 @@ import org.jf.dexlib2.iface.instruction.Instruction;
import org.jf.dexlib2.iface.instruction.OffsetInstruction;
import org.jf.dexlib2.iface.instruction.ReferenceInstruction;
import org.jf.dexlib2.iface.reference.MethodReference;
import org.jf.dexlib2.util.InstructionOffsetMap;
import org.jf.dexlib2.util.MethodUtil;
import org.jf.dexlib2.util.SyntheticAccessorResolver;
import org.jf.dexlib2.util.TypeUtils;
import org.jf.dexlib2.util.*;
import org.jf.util.IndentingWriter;
import org.jf.baksmali.baksmali;
import org.jf.util.ExceptionWithContext;
@ -103,7 +100,7 @@ public class MethodDefinition {
}catch (Exception ex) {
String methodString;
try {
methodString = MethodUtil.buildFullMethodString(classDef.classDef, method);
methodString = ReferenceUtil.getMethodDescriptor(method);
} catch (Exception ex2) {
throw ExceptionWithContext.withContext(ex, "Error while processing method");
}

View File

@ -37,6 +37,7 @@ import org.jf.dexlib2.iface.ExceptionHandler;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Comparator;
public abstract class BaseExceptionHandler implements ExceptionHandler {
@Override
@ -65,9 +66,31 @@ public abstract class BaseExceptionHandler implements ExceptionHandler {
return 1;
}
} else {
String otherExceptionType = o.getExceptionType();
if (otherExceptionType == null) {
return -1;
}
res = exceptionType.compareTo(o.getExceptionType());
if (res != 0) return res;
}
return Ints.compare(getHandlerCodeAddress(), o.getHandlerCodeAddress());
}
public static final Comparator<ExceptionHandler> BY_EXCEPTION = new Comparator<ExceptionHandler>() {
@Override public int compare(ExceptionHandler o1, ExceptionHandler o2) {
String exceptionType1 = o1.getExceptionType();
if (exceptionType1 == null) {
if (o2.getExceptionType() != null) {
return 1;
}
return 0;
} else {
String exceptionType2 = o2.getExceptionType();
if (exceptionType2 == null) {
return -1;
}
return exceptionType1.compareTo(o2.getExceptionType());
}
}
};
}

View File

@ -61,8 +61,8 @@ public interface TryBlock {
/**
* A list of the exception handlers associated with this try block.
*
* The exception handlers in the returned set will all have a unique type, including at most 1 with no type, which
* is the catch-all handler.
* The exception handlers in the returned list will all have a unique type, including at most 1 with no type, which
* is the catch-all handler. Catch-all handler is always the last item in the list.
*
* @return A list of ExceptionHandler objects
*/

View File

@ -0,0 +1,42 @@
/*
* Copyright 2012, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib2.util;
import org.jf.dexlib2.Opcode;
public final class InstructionUtil {
public static boolean isInvokeStatic(Opcode opcode) {
return opcode == Opcode.INVOKE_STATIC || opcode == Opcode.INVOKE_STATIC_RANGE;
}
private InstructionUtil() {}
}

View File

@ -32,31 +32,38 @@
package org.jf.dexlib2.util;
import org.jf.dexlib2.AccessFlags;
import org.jf.dexlib2.iface.ClassDef;
import org.jf.dexlib2.iface.Method;
import org.jf.dexlib2.iface.MethodParameter;
import org.jf.dexlib2.iface.reference.MethodReference;
import org.jf.dexlib2.iface.reference.TypeReference;
import javax.annotation.Nonnull;
public final class MethodUtil {
public static String buildFullMethodString(ClassDef classDef, Method method) {
//TODO: consider using a cached thread-local StringBuilder
StringBuilder sb = new StringBuilder();
sb.append(classDef.getType());
sb.append("->");
sb.append(method.getName());
sb.append("(");
for (MethodParameter methodParameter: method.getParameters()) {
sb.append(methodParameter.getType());
}
sb.append(")");
sb.append(method.getReturnType());
return sb.toString();
}
private static int directMask = AccessFlags.STATIC.getValue() | AccessFlags.PRIVATE.getValue() |
AccessFlags.CONSTRUCTOR.getValue();
public static boolean isDirect(Method method) {
return (method.getAccessFlags() | directMask) != 0;
public static boolean isDirect(@Nonnull Method method) {
return (method.getAccessFlags() & directMask) != 0;
}
public static boolean isStatic(@Nonnull Method method) {
return AccessFlags.STATIC.isSet(method.getAccessFlags());
}
public static int getParameterRegisterCount(@Nonnull MethodReference methodRef, boolean isStatic) {
int regCount = 0;
for (TypeReference param: methodRef.getParameters()) {
int firstChar = param.getType().charAt(0);
if (firstChar == 'J' || firstChar == 'D') {
regCount += 2;
} else {
regCount++;
}
}
if (!isStatic) {
regCount++;
}
return regCount;
}
private MethodUtil() {}

View File

@ -0,0 +1,552 @@
/*
* Copyright 2012, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib2.writer;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.jf.dexlib2.ReferenceType;
import org.jf.dexlib2.iface.ExceptionHandler;
import org.jf.dexlib2.iface.Method;
import org.jf.dexlib2.iface.MethodImplementation;
import org.jf.dexlib2.iface.TryBlock;
import org.jf.dexlib2.iface.instruction.Instruction;
import org.jf.dexlib2.iface.instruction.ReferenceInstruction;
import org.jf.dexlib2.iface.instruction.SwitchElement;
import org.jf.dexlib2.iface.instruction.formats.*;
import org.jf.dexlib2.iface.reference.*;
import org.jf.dexlib2.util.InstructionUtil;
import org.jf.dexlib2.util.MethodUtil;
import org.jf.dexlib2.util.ReferenceUtil;
import org.jf.util.ExceptionWithContext;
import javax.annotation.Nonnull;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
public class CodeItemPool {
@Nonnull private final Map<Method, Integer> codeItemOffsetMap = Maps.newHashMap();
@Nonnull private final DexFile dexFile;
private int sectionOffset = -1;
public CodeItemPool(@Nonnull DexFile dexFile) {
this.dexFile = dexFile;
}
public void intern(@Nonnull Method method) {
// TODO: can we have parameter names (in the debug_info_item), without having any other sort of method implementation
// this also handles parameter names, which aren't directly tied to the MethodImplementation, even though the debug items are
boolean hasDebugInfo = dexFile.debugInfoPool.intern(method);
boolean hasInstruction = false;
MethodImplementation methodImpl = method.getImplementation();
if (methodImpl != null) {
for (Instruction instruction: methodImpl.getInstructions()) {
hasInstruction = true;
if (instruction instanceof ReferenceInstruction) {
Reference reference = ((ReferenceInstruction)instruction).getReference();
switch (instruction.getOpcode().referenceType) {
case ReferenceType.STRING:
dexFile.stringPool.intern((StringReference) reference);
break;
case ReferenceType.TYPE:
dexFile.typePool.intern((TypeReference)reference);
break;
case ReferenceType.FIELD:
dexFile.fieldPool.intern((FieldReference) reference);
break;
case ReferenceType.METHOD:
dexFile.methodPool.intern((MethodReference)reference);
break;
default:
throw new ExceptionWithContext("Unrecognized reference type: %d",
instruction.getOpcode().referenceType);
}
}
}
List<? extends TryBlock> tryBlocks = methodImpl.getTryBlocks();
if (!hasInstruction && tryBlocks.size() > 0) {
throw new ExceptionWithContext("Method %s has no instructions, but has try blocks.",
ReferenceUtil.getMethodDescriptor(method));
}
for (TryBlock tryBlock: methodImpl.getTryBlocks()) {
for (ExceptionHandler handler: tryBlock.getExceptionHandlers()) {
dexFile.typePool.internNullable(handler.getExceptionType());
}
}
}
if (hasDebugInfo || hasInstruction) {
codeItemOffsetMap.put(method, 0);
}
}
public int getOffset(@Nonnull Method method) {
Integer offset = codeItemOffsetMap.get(method);
if (offset == null) {
return 0;
}
return offset;
}
public int getNumItems() {
return codeItemOffsetMap.size();
}
public int getSectionOffset() {
if (sectionOffset < 0) {
throw new ExceptionWithContext("Section offset has not been set yet!");
}
return sectionOffset;
}
public void write(@Nonnull DexWriter writer) throws IOException {
ByteArrayOutputStream ehBuf = new ByteArrayOutputStream();
writer.align();
sectionOffset = writer.getPosition();
List<Method> methods = Lists.newArrayList(codeItemOffsetMap.keySet());
Collections.sort(methods);
for (Method method: methods) {
writer.align();
codeItemOffsetMap.put(method, writer.getPosition());
MethodImplementation methodImpl = method.getImplementation();
if (methodImpl != null) {
writer.writeUshort(methodImpl.getRegisterCount());
writer.writeUshort(MethodUtil.getParameterRegisterCount(method, MethodUtil.isStatic(method)));
int maxOutParamCount = 0;
int codeUnitCount = 0;
for (Instruction instruction: methodImpl.getInstructions()) {
if (instruction.getOpcode().referenceType == ReferenceType.METHOD) {
codeUnitCount += instruction.getCodeUnits();
ReferenceInstruction refInsn = (ReferenceInstruction)instruction;
MethodReference methodRef = (MethodReference)refInsn.getReference();
int paramCount = MethodUtil.getParameterRegisterCount(methodRef,
InstructionUtil.isInvokeStatic(instruction.getOpcode()));
if (paramCount > maxOutParamCount) {
maxOutParamCount = paramCount;
}
}
}
writer.writeUshort(maxOutParamCount);
List<? extends TryBlock> tryBlocks = methodImpl.getTryBlocks();
writer.writeUshort(tryBlocks.size());
writer.writeInt(dexFile.debugInfoPool.getOffset(method));
writer.writeInt(codeUnitCount);
// TODO: need to fix up instructions. Add alignment nops, convert to const-string/jumbos, etc.
for (Instruction instruction: methodImpl.getInstructions()) {
switch (instruction.getOpcode().format) {
case Format10t:
writeFormat10t(writer, (Instruction10t)instruction);
break;
case Format10x:
writeFormat10x(writer, (Instruction10x)instruction);
break;
case Format11n:
writeFormat11n(writer, (Instruction11n)instruction);
break;
case Format11x:
writeFormat11x(writer, (Instruction11x)instruction);
break;
case Format12x:
writeFormat12x(writer, (Instruction12x)instruction);
break;
case Format20t:
writeFormat20t(writer, (Instruction20t)instruction);
break;
case Format21c:
writeFormat21c(writer, (Instruction21c)instruction);
break;
case Format21ih:
writeFormat21ih(writer, (Instruction21ih)instruction);
break;
case Format21lh:
writeFormat21lh(writer, (Instruction21lh)instruction);
break;
case Format21s:
writeFormat21s(writer, (Instruction21s)instruction);
break;
case Format21t:
writeFormat21t(writer, (Instruction21t)instruction);
break;
case Format22b:
writeFormat22b(writer, (Instruction22b)instruction);
break;
case Format22c:
writeFormat22c(writer, (Instruction22c)instruction);
break;
case Format22s:
writeFormat22s(writer, (Instruction22s)instruction);
break;
case Format22t:
writeFormat22t(writer, (Instruction22t)instruction);
break;
case Format22x:
writeFormat22x(writer, (Instruction22x)instruction);
break;
case Format23x:
writeFormat23x(writer, (Instruction23x)instruction);
break;
case Format30t:
writeFormat30t(writer, (Instruction30t)instruction);
break;
case Format31c:
writeFormat31c(writer, (Instruction31c)instruction);
break;
case Format31i:
writeFormat31i(writer, (Instruction31i)instruction);
break;
case Format31t:
writeFormat31t(writer, (Instruction31t)instruction);
break;
case Format32x:
writeFormat32x(writer, (Instruction32x)instruction);
break;
case Format35c:
writeFormat35c(writer, (Instruction35c)instruction);
break;
case Format3rc:
writeFormat3rc(writer, (Instruction3rc)instruction);
break;
case Format51l:
writeFormat51l(writer, (Instruction51l)instruction);
break;
case ArrayPayload:
writeArrayPayload(writer, (ArrayPayload)instruction);
break;
case SparseSwitchPayload:
writeSparseSwitchPayload(writer, (SparseSwitchPayload)instruction);
break;
case PackedSwitchPayload:
writePackedSwitchPayload(writer, (PackedSwitchPayload)instruction);
break;
default:
throw new ExceptionWithContext("Unexpected format: %s", instruction.getOpcode().format);
}
}
if (tryBlocks.size() > 0) {
writer.align();
// filter out unique lists of exception handlers
Map<List<? extends ExceptionHandler>, Integer> exceptionHandlerOffsetMap = Maps.newHashMap();
for (TryBlock tryBlock: tryBlocks) {
exceptionHandlerOffsetMap.put(tryBlock.getExceptionHandlers(), 0);
}
DexWriter.writeUleb128(ehBuf, exceptionHandlerOffsetMap.size());
for (TryBlock tryBlock: tryBlocks) {
writer.writeInt(tryBlock.getStartCodeAddress());
writer.writeUshort(tryBlock.getCodeUnitCount());
if (tryBlock.getExceptionHandlers().size() == 0) {
throw new ExceptionWithContext("No exception handlers for the try block!");
}
Integer offset = exceptionHandlerOffsetMap.get(tryBlock.getExceptionHandlers());
if (offset != 0) {
// exception handler has already been written out, just use it
writer.writeUshort(offset);
} else {
// if offset has not been set yet, we are about to write out a new exception handler
offset = ehBuf.size();
writer.writeUshort(offset);
exceptionHandlerOffsetMap.put(tryBlock.getExceptionHandlers(), offset);
// check if the last exception handler is a catch-all and adjust the size accordingly
int ehSize = tryBlock.getExceptionHandlers().size();
ExceptionHandler ehLast = tryBlock.getExceptionHandlers().get(ehSize-1);
if (ehLast.getExceptionType() == null) {
ehSize = ehSize * (-1) + 1;
}
// now let's layout the exception handlers, assuming that catch-all is always last
DexWriter.writeSleb128(ehBuf, ehSize);
for (ExceptionHandler eh : tryBlock.getExceptionHandlers()) {
String exceptionType = eh.getExceptionType();
int codeAddress = eh.getHandlerCodeAddress();
if (exceptionType != null) {
//regular exception handling
DexWriter.writeUleb128(ehBuf, dexFile.typePool.getIndex(exceptionType));
DexWriter.writeUleb128(ehBuf, codeAddress);
} else {
//catch-all
DexWriter.writeUleb128(ehBuf, codeAddress);
}
}
}
}
if (ehBuf.size() > 0) {
ehBuf.writeTo(writer);
ehBuf.reset();
}
}
}
}
}
private static int packNibbles(int a, int b) {
return (b << 4) | a;
}
private int getReferenceIndex(ReferenceInstruction referenceInstruction) {
switch (referenceInstruction.getOpcode().referenceType) {
case ReferenceType.FIELD:
return dexFile.fieldPool.getIndex((FieldReference)referenceInstruction.getReference());
case ReferenceType.METHOD:
return dexFile.methodPool.getIndex((MethodReference)referenceInstruction.getReference());
case ReferenceType.STRING:
return dexFile.stringPool.getIndex((StringReference)referenceInstruction.getReference());
case ReferenceType.TYPE:
return dexFile.typePool.getIndex((TypeReference)referenceInstruction.getReference());
default:
throw new ExceptionWithContext("Unknown reference type: %d",
referenceInstruction.getOpcode().referenceType);
}
}
public void writeFormat10t(@Nonnull DexWriter writer, @Nonnull Instruction10t instruction) throws IOException {
writer.write(instruction.getOpcode().value);
writer.write(instruction.getCodeOffset());
}
public void writeFormat10x(@Nonnull DexWriter writer, @Nonnull Instruction10x instruction) throws IOException {
writer.write(instruction.getOpcode().value);
writer.write(0);
}
public void writeFormat11n(@Nonnull DexWriter writer, @Nonnull Instruction11n instruction) throws IOException {
writer.write(instruction.getOpcode().value);
writer.write(packNibbles(instruction.getRegisterA(), instruction.getNarrowLiteral()));
}
public void writeFormat11x(@Nonnull DexWriter writer, @Nonnull Instruction11x instruction) throws IOException {
writer.write(instruction.getOpcode().value);
writer.write(instruction.getRegisterA());
}
public void writeFormat12x(@Nonnull DexWriter writer, @Nonnull Instruction12x instruction) throws IOException {
writer.write(instruction.getOpcode().value);
writer.write(packNibbles(instruction.getRegisterA(), instruction.getRegisterB()));
}
public void writeFormat20t(@Nonnull DexWriter writer, @Nonnull Instruction20t instruction) throws IOException {
writer.write(instruction.getOpcode().value);
writer.write(0);
writer.writeShort(instruction.getCodeOffset());
}
public void writeFormat21c(@Nonnull DexWriter writer, @Nonnull Instruction21c instruction) throws IOException {
writer.write(instruction.getOpcode().value);
writer.write(instruction.getRegisterA());
writer.writeUshort(getReferenceIndex(instruction));
}
public void writeFormat21ih(@Nonnull DexWriter writer, @Nonnull Instruction21ih instruction) throws IOException {
writer.write(instruction.getOpcode().value);
writer.write(instruction.getRegisterA());
writer.writeShort(instruction.getHatLiteral());
}
public void writeFormat21lh(@Nonnull DexWriter writer, @Nonnull Instruction21lh instruction) throws IOException {
writer.write(instruction.getOpcode().value);
writer.write(instruction.getRegisterA());
writer.writeShort(instruction.getHatLiteral());
}
public void writeFormat21s(@Nonnull DexWriter writer, @Nonnull Instruction21s instruction) throws IOException {
writer.write(instruction.getOpcode().value);
writer.write(instruction.getRegisterA());
writer.writeShort(instruction.getNarrowLiteral());
}
public void writeFormat21t(@Nonnull DexWriter writer, @Nonnull Instruction21t instruction) throws IOException {
writer.write(instruction.getOpcode().value);
writer.write(instruction.getRegisterA());
writer.writeShort(instruction.getCodeOffset());
}
public void writeFormat22b(@Nonnull DexWriter writer, @Nonnull Instruction22b instruction) throws IOException {
writer.write(instruction.getOpcode().value);
writer.write(instruction.getRegisterA());
writer.write(instruction.getRegisterB());
writer.write(instruction.getNarrowLiteral());
}
public void writeFormat22c(@Nonnull DexWriter writer, @Nonnull Instruction22c instruction) throws IOException {
writer.write(instruction.getOpcode().value);
writer.write(packNibbles(instruction.getRegisterA(), instruction.getRegisterB()));
writer.writeUshort(getReferenceIndex(instruction));
}
public void writeFormat22s(@Nonnull DexWriter writer, @Nonnull Instruction22s instruction) throws IOException {
writer.write(instruction.getOpcode().value);
writer.write(packNibbles(instruction.getRegisterA(), instruction.getRegisterB()));
writer.writeShort(instruction.getNarrowLiteral());
}
public void writeFormat22t(@Nonnull DexWriter writer, @Nonnull Instruction22t instruction) throws IOException {
writer.write(instruction.getOpcode().value);
writer.write(packNibbles(instruction.getRegisterA(), instruction.getRegisterB()));
writer.writeShort(instruction.getCodeOffset());
}
public void writeFormat22x(@Nonnull DexWriter writer, @Nonnull Instruction22x instruction) throws IOException {
writer.write(instruction.getOpcode().value);
writer.write(instruction.getRegisterA());
writer.writeUshort(instruction.getRegisterB());
}
public void writeFormat23x(@Nonnull DexWriter writer, @Nonnull Instruction23x instruction) throws IOException {
writer.write(instruction.getOpcode().value);
writer.write(instruction.getRegisterA());
writer.write(instruction.getRegisterB());
writer.write(instruction.getRegisterC());
}
public void writeFormat30t(@Nonnull DexWriter writer, @Nonnull Instruction30t instruction) throws IOException {
writer.write(instruction.getOpcode().value);
writer.write(0);
writer.writeInt(instruction.getCodeOffset());
}
public void writeFormat31c(@Nonnull DexWriter writer, @Nonnull Instruction31c instruction) throws IOException {
writer.write(instruction.getOpcode().value);
writer.write(instruction.getRegisterA());
writer.writeInt(getReferenceIndex(instruction));
}
public void writeFormat31i(@Nonnull DexWriter writer, @Nonnull Instruction31i instruction) throws IOException {
writer.write(instruction.getOpcode().value);
writer.write(instruction.getRegisterA());
writer.writeInt(instruction.getNarrowLiteral());
}
public void writeFormat31t(@Nonnull DexWriter writer, @Nonnull Instruction31t instruction) throws IOException {
writer.write(instruction.getOpcode().value);
writer.write(instruction.getRegisterA());
writer.writeInt(instruction.getCodeOffset());
}
public void writeFormat32x(@Nonnull DexWriter writer, @Nonnull Instruction32x instruction) throws IOException {
writer.write(instruction.getOpcode().value);
writer.write(0);
writer.writeUshort(instruction.getRegisterA());
writer.writeUshort(instruction.getRegisterB());
}
public void writeFormat35c(@Nonnull DexWriter writer, @Nonnull Instruction35c instruction) throws IOException {
writer.write(instruction.getOpcode().value);
writer.write(packNibbles(instruction.getRegisterG(), instruction.getRegisterCount()));
writer.write(getReferenceIndex(instruction));
writer.write(packNibbles(instruction.getRegisterC(), instruction.getRegisterD()));
writer.write(packNibbles(instruction.getRegisterE(), instruction.getRegisterF()));
}
public void writeFormat3rc(@Nonnull DexWriter writer, @Nonnull Instruction3rc instruction) throws IOException {
writer.write(instruction.getOpcode().value);
writer.write(instruction.getRegisterCount());
writer.write(getReferenceIndex(instruction));
writer.writeUshort(instruction.getStartRegister());
}
public void writeFormat51l(@Nonnull DexWriter writer, @Nonnull Instruction51l instruction) throws IOException {
writer.write(instruction.getOpcode().value);
writer.write(instruction.getRegisterA());
writer.writeLong(instruction.getWideLiteral());
}
public void writeArrayPayload(@Nonnull DexWriter writer, @Nonnull ArrayPayload instruction) throws IOException {
writer.writeUshort(instruction.getOpcode().value);
writer.writeUshort(instruction.getElementWidth());
List<Number> elements = instruction.getArrayElements();
writer.writeInt(elements.size());
// TODO: validate that dalvik only allows these element widths
switch (instruction.getElementWidth()) {
case 1:
for (Number element: elements) {
writer.write(element.byteValue());
}
return;
case 2:
for (Number element: elements) {
writer.writeShort(element.shortValue());
}
return;
case 4:
for (Number element: elements) {
writer.writeInt(element.intValue());
}
return;
case 8:
for (Number element: elements) {
writer.writeLong(element.longValue());
}
}
}
public void writeSparseSwitchPayload(@Nonnull DexWriter writer, @Nonnull SparseSwitchPayload instruction)
throws IOException {
writer.writeUshort(instruction.getOpcode().value);
List<? extends SwitchElement> elements = instruction.getSwitchElements();
writer.writeUshort(elements.size());
for (SwitchElement element: elements) {
writer.writeInt(element.getKey());
}
for (SwitchElement element: elements) {
writer.writeInt(element.getOffset());
}
}
public void writePackedSwitchPayload(@Nonnull DexWriter writer, @Nonnull PackedSwitchPayload instruction)
throws IOException {
writer.writeUshort(instruction.getOpcode().value);
List<? extends SwitchElement> elements = instruction.getSwitchElements();
writer.writeUshort(elements.size());
writer.writeInt(elements.get(0).getKey());
for (SwitchElement element: elements) {
writer.writeInt(element.getOffset());
}
}
}

View File

@ -54,7 +54,7 @@ public class DebugInfoPool {
this.dexFile = dexFile;
}
public void intern(@Nonnull Method method) {
public boolean intern(@Nonnull Method method) {
boolean hasDebugInfo = false;
for (MethodParameter param: method.getParameters()) {
String paramName = param.getName();
@ -85,6 +85,7 @@ public class DebugInfoPool {
if (hasDebugInfo) {
debugInfoOffsetMap.put(method, 0);
}
return hasDebugInfo;
}
public int getOffset(@Nonnull Method method) {

View File

@ -67,6 +67,7 @@ public class DexFile {
@Nonnull final AnnotationSetRefPool annotationSetRefPool = new AnnotationSetRefPool(this);
@Nonnull final AnnotationDirectoryPool annotationDirectoryPool = new AnnotationDirectoryPool(this);
@Nonnull final DebugInfoPool debugInfoPool = new DebugInfoPool(this);
@Nonnull final CodeItemPool codeItemPool = new CodeItemPool(this);
@Nonnull private final Set<? extends ClassDef> classes;
@ -197,10 +198,7 @@ public class DexFile {
public void internMethods(@Nonnull ClassDef classDef) {
for (Method method: classDef.getMethods()) {
methodPool.intern(method);
// TODO: can we have parameter names (in the debug_info_item), without having any other sort of method implementation
// this also handles parameter names, which aren't directly tied to the MethodImplementation, even though the debug items are
debugInfoPool.intern(method);
codeItemPool.intern(method);
MethodImplementation methodImpl = method.getImplementation();
if (methodImpl != null) {
@ -293,6 +291,7 @@ public class DexFile {
annotationSetRefPool.write(offsetWriter);
annotationDirectoryPool.write(offsetWriter);
debugInfoPool.write(offsetWriter);
codeItemPool.write(offsetWriter);
} finally {
indexWriter.close();
offsetWriter.close();

View File

@ -112,6 +112,11 @@ public class DexWriter extends OutputStream {
}
}
public void writeLong(long value) throws IOException {
writeInt((int)value);
writeInt((int)(value >> 32));
}
public void writeInt(int value) throws IOException {
write(value);
write(value >> 8);
@ -142,67 +147,38 @@ public class DexWriter extends OutputStream {
write(value);
}
public void writeUleb128(int value) throws IOException {
public static void writeUleb128(OutputStream out, int value) throws IOException {
while (value > 0x7f) {
write((value & 0x7f) | 0x80);
out.write((value & 0x7f) | 0x80);
value >>>= 7;
}
write(value);
out.write(value);
}
public void writeUleb128(int value) throws IOException {
writeUleb128(this, value);
}
public static void writeSleb128(OutputStream out, int value) throws IOException {
if (value >= 0) {
while (value > 0x3f) {
out.write((value & 0x7f) | 0x80);
value >>>= 7;
}
out.write(value & 0x7f);
} else {
while (value < -0x40) {
out.write((value & 0x7f) | 0x80);
value >>= 7;
}
out.write(value & 0x7f);
}
}
public void writeSleb128(int value) throws IOException {
if (value >= 0) {
while (value > 0x3f) {
write((value & 0x7f) | 0x80);
value >>>= 7;
}
write(value & 0x7f);
} else {
while (value < -0x40) {
write((value & 0x7f) | 0x80);
value >>= 7;
}
write(value & 0x7f);
}
writeSleb128(this, value);
}
/* public static byte[] encodeSignedIntegralValue(long value) {
int requiredBytes = getRequiredBytesForSignedIntegralValue(value);
byte[] bytes = new byte[requiredBytes];
for (int i = 0; i < requiredBytes; i++) {
bytes[i] = (byte) value;
value >>= 8;
}
return bytes;
}*/
/*
public static long decodeUnsignedIntegralValue(byte[] bytes) {
long value = 0;
for (int i = 0; i < bytes.length; i++) {
value |= (((long)(bytes[i] & 0xFF)) << i * 8);
}
return value;
}
*/
/*
public static byte[] encodeUnsignedIntegralValue(long value) {
int requiredBytes = getRequiredBytesForUnsignedIntegralValue(value);
byte[] bytes = new byte[requiredBytes];
for (int i = 0; i < requiredBytes; i++) {
bytes[i] = (byte) value;
value >>= 8;
}
return bytes;
}
*/
public void writeEncodedValueHeader(int valueType, int valueArg) throws IOException {
write(valueType | (valueArg << 5));
}