diff --git a/dexlib/src/main/java/org/jf/dexlib/DexFile.java b/dexlib/src/main/java/org/jf/dexlib/DexFile.java index 95af0c36..cb07690a 100644 --- a/dexlib/src/main/java/org/jf/dexlib/DexFile.java +++ b/dexlib/src/main/java/org/jf/dexlib/DexFile.java @@ -48,6 +48,7 @@ public class DexFile private int fileSize; private int dataOffset; private int dataSize; + private boolean forDumping; private final DexFile dexFile = this; @@ -97,9 +98,15 @@ public class DexFile } public DexFile(File file) { + this(file, false); + } + + public DexFile(File file, boolean forDumping) { this(); Input in = new ByteArrayInput(FileUtils.readFile(file)); + this.forDumping = forDumping; + HeaderItemSection.readFrom(1, in); HeaderItem headerItem = HeaderItemSection.items.get(0); @@ -180,6 +187,10 @@ public class DexFile return dataSize; } + public boolean isForDumping() { + return forDumping; + } + public void place() { int offset = 0; @@ -316,7 +327,7 @@ public class DexFile public final OffsettedSection DebugInfoItemsSection = new OffsettedSection() { protected DebugInfoItem make(int offset) { - return new DebugInfoItem(dexFile, offset); + return new DebugInfoItem(dexFile, offset); } }; diff --git a/dexlib/src/main/java/org/jf/dexlib/Leb128Field.java b/dexlib/src/main/java/org/jf/dexlib/Leb128Field.java index c748b1d1..2ba58342 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Leb128Field.java +++ b/dexlib/src/main/java/org/jf/dexlib/Leb128Field.java @@ -41,7 +41,7 @@ public class Leb128Field extends CachedIntegerValueField { super(value, fieldName); } - public void readFrom(Input in) { + public void readFrom(Input in) { value = in.readUnsignedLeb128(); } @@ -52,4 +52,44 @@ public class Leb128Field extends CachedIntegerValueField { public void writeValue(Output out) { out.writeUnsignedLeb128(value); } + + /** + * dx had a bug where it would write registers in the debug + * info as signed leb 128 values instead of unsigned. This class + * is used when it is important to keep the same format as the + * file being read in - for example when the intent is to immediately + * write the file back out (typically for dumping/annotation purposes) + */ + public static class PossiblySignedLeb128Field extends Leb128Field { + private boolean signed = false; + + public PossiblySignedLeb128Field(String fieldName) { + super (fieldName); + } + + public void readFrom(Input in) { + int start = in.getCursor(); + value = in.readUnsignedLeb128(); + int end = in.getCursor(); + + if (Leb128Utils.unsignedLeb128Size(value) != (end - start)) { + signed = true; + } + } + + public int place(int offset) { + if (signed) { + return offset + Leb128Utils.signedLeb128Size(value); + } + return offset + Leb128Utils.unsignedLeb128Size(value); + } + + public void writeValue(Output out) { + if (signed) { + out.writeSignedLeb128(value); + } else { + out.writeUnsignedLeb128(value); + } + } + } } diff --git a/dexlib/src/main/java/org/jf/dexlib/debug/DebugInstructionFactory.java b/dexlib/src/main/java/org/jf/dexlib/debug/DebugInstructionFactory.java index 9527c7b1..bb72709a 100644 --- a/dexlib/src/main/java/org/jf/dexlib/debug/DebugInstructionFactory.java +++ b/dexlib/src/main/java/org/jf/dexlib/debug/DebugInstructionFactory.java @@ -57,7 +57,7 @@ public abstract class DebugInstructionFactory { case 0x05: return new EndLocal(); case 0x06: - return new RestartLocal(); + return new RestartLocal(dexFile.isForDumping()); case 0x07: return new SetPrologueEnd(); case 0x08: diff --git a/dexlib/src/main/java/org/jf/dexlib/debug/RestartLocal.java b/dexlib/src/main/java/org/jf/dexlib/debug/RestartLocal.java index 71d5fa73..0218b4b0 100644 --- a/dexlib/src/main/java/org/jf/dexlib/debug/RestartLocal.java +++ b/dexlib/src/main/java/org/jf/dexlib/debug/RestartLocal.java @@ -28,25 +28,23 @@ package org.jf.dexlib.debug; -import org.jf.dexlib.ByteField; -import org.jf.dexlib.CompositeField; -import org.jf.dexlib.Field; -import org.jf.dexlib.Leb128Field; +import org.jf.dexlib.*; public class RestartLocal extends CompositeField implements DebugInstruction { private final ByteField opcode; private final Leb128Field registerNumber; - public RestartLocal() { + public RestartLocal(boolean forDumping) { super("DBG_RESTART_LOCAL"); fields = new Field[] { opcode = new ByteField((byte)0x06, "opcode"), - registerNumber = new Leb128Field("register_num") + registerNumber = forDumping?new Leb128Field.PossiblySignedLeb128Field("register_num"): + new Leb128Field("register_num") }; } public RestartLocal(int registerNumber) { - this(); + this(false); this.registerNumber.cacheValue(registerNumber); } diff --git a/dexlib/src/main/java/org/jf/dexlib/debug/StartLocal.java b/dexlib/src/main/java/org/jf/dexlib/debug/StartLocal.java index 2e07b928..e3d09e84 100644 --- a/dexlib/src/main/java/org/jf/dexlib/debug/StartLocal.java +++ b/dexlib/src/main/java/org/jf/dexlib/debug/StartLocal.java @@ -40,7 +40,8 @@ public class StartLocal extends CompositeField implements DebugInstr super("DBG_START_LOCAL"); fields = new Field[] { opcodeField = new ByteField((byte)0x03, "opcode"), - registerNumber = new Leb128Field("register_num"), + registerNumber = dexFile.isForDumping()?new Leb128Field.PossiblySignedLeb128Field("register_num"): + new Leb128Field("register_num"), localName = new IndexedItemReference(dexFile.StringIdsSection, new Leb128p1Field(null), "name_idx"), localType = new IndexedItemReference(dexFile.TypeIdsSection, diff --git a/dexlib/src/main/java/org/jf/dexlib/debug/StartLocalExtended.java b/dexlib/src/main/java/org/jf/dexlib/debug/StartLocalExtended.java index 05e86773..f7ecc153 100644 --- a/dexlib/src/main/java/org/jf/dexlib/debug/StartLocalExtended.java +++ b/dexlib/src/main/java/org/jf/dexlib/debug/StartLocalExtended.java @@ -41,7 +41,8 @@ public class StartLocalExtended extends CompositeField imple super("DBG_START_LOCAL_EXTENDED"); fields = new Field[] { opcodeField = new ByteField((byte)0x04, "opcode"), - registerNumber = new Leb128Field("register_num"), + registerNumber = dexFile.isForDumping()?new Leb128Field.PossiblySignedLeb128Field("register_num"): + new Leb128Field("register_num"), localName = new IndexedItemReference(dexFile.StringIdsSection, new Leb128p1Field(null), "name_idx"), localType = new IndexedItemReference(dexFile.TypeIdsSection,