diff --git a/dexlib/src/main/java/org/jf/dexlib/Debug/DebugInstructionIterator.java b/dexlib/src/main/java/org/jf/dexlib/Debug/DebugInstructionIterator.java index 1f910c78..a9085dfc 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Debug/DebugInstructionIterator.java +++ b/dexlib/src/main/java/org/jf/dexlib/Debug/DebugInstructionIterator.java @@ -71,33 +71,55 @@ public class DebugInstructionIterator { } case 0x03: { - int registerNum = in.readUnsignedLeb128(); + int registerNum = in.readUnsignedOrSignedLeb128(); + boolean isSignedRegister = false; + if (registerNum < 0) { + isSignedRegister = true; + registerNum = ~registerNum; + } int nameIndex = in.readUnsignedLeb128() - 1; int typeIndex = in.readUnsignedLeb128() - 1; processDebugInstruction.ProcessStartLocal(startOffset, in.getCursor() - startOffset, registerNum, - nameIndex, typeIndex); + nameIndex, typeIndex, isSignedRegister); break; } case 0x04: { - int registerNum = in.readUnsignedLeb128(); + int registerNum = in.readUnsignedOrSignedLeb128(); + boolean isSignedRegister = false; + if (registerNum < 0) { + isSignedRegister = true; + registerNum = ~registerNum; + } int nameIndex = in.readUnsignedLeb128() - 1; int typeIndex = in.readUnsignedLeb128() - 1; int signatureIndex = in.readUnsignedLeb128() - 1; processDebugInstruction.ProcessStartLocalExtended(startOffset, in.getCursor() - startOffset, - registerNum, nameIndex, typeIndex, signatureIndex); + registerNum, nameIndex, typeIndex, signatureIndex, isSignedRegister); break; } case 0x05: { - int registerNum = in.readUnsignedLeb128(); - processDebugInstruction.ProcessEndLocal(startOffset, in.getCursor() - startOffset, registerNum); + int registerNum = in.readUnsignedOrSignedLeb128(); + boolean isSignedRegister = false; + if (registerNum < 0) { + isSignedRegister = true; + registerNum = ~registerNum; + } + processDebugInstruction.ProcessEndLocal(startOffset, in.getCursor() - startOffset, registerNum, + isSignedRegister); break; } case 0x06: { - int registerNum = in.readUnsignedLeb128(); - processDebugInstruction.ProcessRestartLocal(startOffset, in.getCursor() - startOffset, registerNum); + int registerNum = in.readUnsignedOrSignedLeb128(); + boolean isSignedRegister = false; + if (registerNum < 0) { + isSignedRegister = true; + registerNum = ~registerNum; + } + processDebugInstruction.ProcessRestartLocal(startOffset, in.getCursor() - startOffset, registerNum, + isSignedRegister); break; } case 0x07: @@ -255,18 +277,19 @@ public class DebugInstructionIterator { ProcessStaticOpcode(startOffset, length); } - public void ProcessStartLocal(int startOffset, int length, int registerNum, int nameIndex, int typeIndex) { + public void ProcessStartLocal(int startOffset, int length, int registerNum, int nameIndex, int typeIndex, + boolean registerIsSigned) { } public void ProcessStartLocalExtended(int startOffset, int length, int registerNum, int nameIndex, - int typeIndex,int signatureIndex) { + int typeIndex,int signatureIndex, boolean registerIsSigned) { } - public void ProcessEndLocal(int startOffset, int length, int registerNum) { + public void ProcessEndLocal(int startOffset, int length, int registerNum, boolean registerIsSigned) { ProcessStaticOpcode(startOffset, length); } - public void ProcessRestartLocal(int startOffset, int length, int registerNum) { + public void ProcessRestartLocal(int startOffset, int length, int registerNum, boolean registerIsSigned) { ProcessStaticOpcode(startOffset, length); } diff --git a/dexlib/src/main/java/org/jf/dexlib/DebugInfoItem.java b/dexlib/src/main/java/org/jf/dexlib/DebugInfoItem.java index a0e86886..5bf477b6 100644 --- a/dexlib/src/main/java/org/jf/dexlib/DebugInfoItem.java +++ b/dexlib/src/main/java/org/jf/dexlib/DebugInfoItem.java @@ -116,7 +116,7 @@ public class DebugInfoItem extends Item { new DebugInstructionIterator.ProcessRawDebugInstructionDelegate() { @Override public void ProcessStartLocal(int startOffset, int length, int registerNum, int nameIndex, - int typeIndex) { + int typeIndex, boolean registerIsSigned) { if (nameIndex != -1) { referencedItemsList.add(dexFile.StringIdsSection.getItemByIndex(nameIndex)); } @@ -127,7 +127,8 @@ public class DebugInfoItem extends Item { @Override public void ProcessStartLocalExtended(int startOffset, int length, int registerNume, int nameIndex, - int typeIndex, int signatureIndex) { + int typeIndex, int signatureIndex, + boolean registerIsSigned) { if (nameIndex != -1) { referencedItemsList.add(dexFile.StringIdsSection.getItemByIndex(nameIndex)); } @@ -191,15 +192,20 @@ public class DebugInfoItem extends Item { @Override public void ProcessStartLocal(int startOffset, int length, int registerNum, int nameIndex, - int typeIndex) { - this.length+=Leb128Utils.unsignedLeb128Size(registerNum); - if (nameIndex != 0) { + int typeIndex, boolean registerIsSigned) { + this.length++; + if (dexFile.getPreserveSignedRegisters() && registerIsSigned) { + this.length += Leb128Utils.signedLeb128Size(registerNum); + } else { + this.length+=Leb128Utils.unsignedLeb128Size(registerNum); + } + if (nameIndex != -1) { this.length+= Leb128Utils.unsignedLeb128Size(referencedItems[referencedItemsPosition++].getIndex()+1); } else { this.length++; } - if (typeIndex != 0) { + if (typeIndex != -1) { this.length+= Leb128Utils.unsignedLeb128Size(referencedItems[referencedItemsPosition++].getIndex()+1); } else { @@ -210,21 +216,27 @@ public class DebugInfoItem extends Item { @Override public void ProcessStartLocalExtended(int startOffset, int length, int registerNum, int nameIndex, - int typeIndex, int signatureIndex) { - this.length+=Leb128Utils.unsignedLeb128Size(registerNum); - if (nameIndex != 0) { + int typeIndex, int signatureIndex, + boolean registerIsSigned) { + this.length++; + if (dexFile.getPreserveSignedRegisters() && registerIsSigned) { + this.length += Leb128Utils.signedLeb128Size(registerNum); + } else { + this.length+=Leb128Utils.unsignedLeb128Size(registerNum); + } + if (nameIndex != -1) { this.length+= Leb128Utils.unsignedLeb128Size(referencedItems[referencedItemsPosition++].getIndex()+1); } else { this.length++; } - if (typeIndex != 0) { + if (typeIndex != -1) { this.length+= Leb128Utils.unsignedLeb128Size(referencedItems[referencedItemsPosition++].getIndex()+1); } else { this.length++; } - if (signatureIndex != 0) { + if (signatureIndex != -1) { this.length+= Leb128Utils.unsignedLeb128Size(referencedItems[referencedItemsPosition++].getIndex()+1); } else { @@ -234,7 +246,8 @@ public class DebugInfoItem extends Item { @Override public void ProcessSetFile(int startOffset, int length, int nameIndex) { - if (nameIndex != 0) { + this.length++; + if (nameIndex != -1) { this.length+= Leb128Utils.unsignedLeb128Size(referencedItems[referencedItemsPosition++].getIndex()+1); } else { @@ -270,7 +283,12 @@ public class DebugInfoItem extends Item { @Override public void ProcessStartLocal(int startOffset, int length, int registerNum, int nameIndex, - int typeIndex) { + int typeIndex, boolean registerIsSigned) { + if (dexFile.getPreserveSignedRegisters() && registerIsSigned) { + out.writeSignedLeb128(registerNum); + } else { + out.writeUnsignedLeb128(registerNum); + } out.writeUnsignedLeb128(registerNum); if (nameIndex != -1) { out.writeUnsignedLeb128(referencedItems[referencedItemsPosition++].getIndex() + 1); @@ -286,8 +304,13 @@ public class DebugInfoItem extends Item { @Override public void ProcessStartLocalExtended(int startOffset, int length, int registerNum, int nameIndex, - int typeIndex, int signatureIndex) { - out.writeUnsignedLeb128(registerNum); + int typeIndex, int signatureIndex, + boolean registerIsSigned) { + if (dexFile.getPreserveSignedRegisters() && registerIsSigned) { + out.writeSignedLeb128(registerNum); + } else { + out.writeUnsignedLeb128(registerNum); + } if (nameIndex != -1) { out.writeUnsignedLeb128(referencedItems[referencedItemsPosition++].getIndex() + 1); } else { diff --git a/dexlib/src/main/java/org/jf/dexlib/Util/ByteArrayInput.java b/dexlib/src/main/java/org/jf/dexlib/Util/ByteArrayInput.java index 59b539df..63196198 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Util/ByteArrayInput.java +++ b/dexlib/src/main/java/org/jf/dexlib/Util/ByteArrayInput.java @@ -152,6 +152,52 @@ public class ByteArrayInput ((data[readAt + 7] & 0xffL) << 58); } + + /** {@inheritDoc} */ + public int readUnsignedOrSignedLeb128() { + int end = cursor; + int currentByteValue; + int result; + + result = data[end++] & 0xff; + if (result > 0x7f) { + currentByteValue = data[end++] & 0xff; + result = (result & 0x7f) | ((currentByteValue & 0x7f) << 7); + if (currentByteValue > 0x7f) { + currentByteValue = data[end++] & 0xff; + result |= (currentByteValue & 0x7f) << 14; + if (currentByteValue > 0x7f) { + currentByteValue = data[end++] & 0xff; + result |= (currentByteValue & 0x7f) << 21; + if (currentByteValue > 0x7f) { + currentByteValue = data[end++] & 0xff; + if (currentByteValue > 0x0f) { + throwInvalidLeb(); + } + result |= currentByteValue << 28; + } + } + } + } else { + cursor = end; + return result; + } + + cursor = end; + + //If the last byte is 0, then this was an unsigned value (incorrectly) written in a signed format + //The caller wants to know if this is the case, so we'll return the negated value instead + //If there was only a single byte that had a value of 0, then we would have returned in the above + //"else" + if (data[end-1] == 0) { + return ~result; + } + return result; + } + + + + /** {@inheritDoc} */ public int readUnsignedLeb128() { int end = cursor; diff --git a/dexlib/src/main/java/org/jf/dexlib/Util/Input.java b/dexlib/src/main/java/org/jf/dexlib/Util/Input.java index 6d52af66..463ed98b 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Util/Input.java +++ b/dexlib/src/main/java/org/jf/dexlib/Util/Input.java @@ -105,6 +105,17 @@ public interface Input { */ public int readUnsignedLeb128(); + + /** + * Reads a unsigned value as a DWARFv3-style LEB128 integer. It specifically + * checks for the case when the value was incorrectly formatted as a signed + * LEB128, and returns the appropriate unsigned value, but negated + * @return If the value was formatted as a ULEB128, it returns the actual unsigned + * value. Otherwise, if the value was formatted as a signed LEB128, it negates the + * "correct" unsigned value and returns that + */ + public int readUnsignedOrSignedLeb128(); + /** * reads a byte[] from this instance. *