summaryrefslogtreecommitdiffstats
path: root/dex
diff options
context:
space:
mode:
authorBenoit Lamarche <benoitlamarche@google.com>2012-09-05 12:23:20 +0200
committerBrian Carlstrom <bdc@google.com>2013-04-30 14:53:59 -0700
commit00a2d1ee4cfee1f33344c3798940bbae22f96187 (patch)
tree51b70ff64bf9d1fd31dc945a0817d35fc0c8a538 /dex
parentc8bc5f77ee2a996e771fb1814a47cc5c8bf93d5e (diff)
downloadlibcore-00a2d1ee4cfee1f33344c3798940bbae22f96187.zip
libcore-00a2d1ee4cfee1f33344c3798940bbae22f96187.tar.gz
libcore-00a2d1ee4cfee1f33344c3798940bbae22f96187.tar.bz2
Fix an ugly bug where try/catch offsets weren't being mapped properly
This CL comes from CL I3bdadf20899fdb5d4d074e69103b33c0404a31f8 in AOSP master. Modifications have been made to files that were in dalvik but are now in libcore. Here is the original commit message: In dex files, there are several places where one object refers to another object by its position in the file. The dex merger is generally very careful to adjust these mappings when combining dex files. Unfortunately one of these cases was broken. Each try_item refers to a corresponding encoded_catch_handler by its byte offset in a list. Most of the time this byte offset is the same in the input dex file and the output dex file. But encoded_catch_handlers are variable-length because they use a variable-length uleb128 encoding to address the type_idx being caught. When dex files are merged, some exception types may go from having a small index to having a large index, increasing the number of bytes required to encode that index. This breaks our ability to directly copy over offsets as we were doing previously. Change-Id: I61adb8fce6fa9b83cbfbe5eef7edea84664d7ea6 (cherry picked from commit b44450d600807ab130aa7c6d91b534fde52e0a21)
Diffstat (limited to 'dex')
-rw-r--r--dex/src/main/java/com/android/dex/Code.java22
-rw-r--r--dex/src/main/java/com/android/dex/Dex.java109
-rw-r--r--dex/src/main/java/com/android/dex/SizeOf.java7
3 files changed, 99 insertions, 39 deletions
diff --git a/dex/src/main/java/com/android/dex/Code.java b/dex/src/main/java/com/android/dex/Code.java
index 8a9b885..9258af7 100644
--- a/dex/src/main/java/com/android/dex/Code.java
+++ b/dex/src/main/java/com/android/dex/Code.java
@@ -67,12 +67,12 @@ public final class Code {
public static class Try {
final int startAddress;
final int instructionCount;
- final int handlerOffset;
+ final int catchHandlerIndex;
- Try(int startAddress, int instructionCount, int handlerOffset) {
+ Try(int startAddress, int instructionCount, int catchHandlerIndex) {
this.startAddress = startAddress;
this.instructionCount = instructionCount;
- this.handlerOffset = handlerOffset;
+ this.catchHandlerIndex = catchHandlerIndex;
}
public int getStartAddress() {
@@ -83,8 +83,12 @@ public final class Code {
return instructionCount;
}
- public int getHandlerOffset() {
- return handlerOffset;
+ /**
+ * Returns this try's catch handler <strong>index</strong>. Note that
+ * this is distinct from the its catch handler <strong>offset</strong>.
+ */
+ public int getCatchHandlerIndex() {
+ return catchHandlerIndex;
}
}
@@ -92,11 +96,13 @@ public final class Code {
final int[] typeIndexes;
final int[] addresses;
final int catchAllAddress;
+ final int offset;
- public CatchHandler(int[] typeIndexes, int[] addresses, int catchAllAddress) {
+ public CatchHandler(int[] typeIndexes, int[] addresses, int catchAllAddress, int offset) {
this.typeIndexes = typeIndexes;
this.addresses = addresses;
this.catchAllAddress = catchAllAddress;
+ this.offset = offset;
}
public int[] getTypeIndexes() {
@@ -110,5 +116,9 @@ public final class Code {
public int getCatchAllAddress() {
return catchAllAddress;
}
+
+ public int getOffset() {
+ return offset;
+ }
}
}
diff --git a/dex/src/main/java/com/android/dex/Dex.java b/dex/src/main/java/com/android/dex/Dex.java
index e6bee68..29cd30e 100644
--- a/dex/src/main/java/com/android/dex/Dex.java
+++ b/dex/src/main/java/com/android/dex/Dex.java
@@ -16,9 +16,12 @@
package com.android.dex;
+import com.android.dex.Code.CatchHandler;
+import com.android.dex.Code.Try;
import com.android.dex.util.ByteInput;
import com.android.dex.util.ByteOutput;
import com.android.dex.util.FileUtils;
+
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
@@ -546,41 +549,74 @@ public final class Dex {
int debugInfoOffset = readInt();
int instructionsSize = readInt();
short[] instructions = readShortArray(instructionsSize);
- Code.Try[] tries = new Code.Try[triesSize];
- Code.CatchHandler[] catchHandlers = new Code.CatchHandler[0];
+ Try[] tries;
+ CatchHandler[] catchHandlers;
if (triesSize > 0) {
- if (instructions.length % 2 == 1) {
- readShort(); // padding
- }
-
- for (int i = 0; i < triesSize; i++) {
- int startAddress = readInt();
- int instructionCount = readUnsignedShort();
- int handlerOffset = readUnsignedShort();
- tries[i] = new Code.Try(startAddress, instructionCount, handlerOffset);
- }
-
- int catchHandlersSize = readUleb128();
- catchHandlers = new Code.CatchHandler[catchHandlersSize];
- for (int i = 0; i < catchHandlersSize; i++) {
- catchHandlers[i] = readCatchHandler();
- }
- }
- return new Code(registersSize, insSize, outsSize, debugInfoOffset, instructions,
- tries, catchHandlers);
- }
-
- private Code.CatchHandler readCatchHandler() {
- int size = readSleb128();
- int handlersCount = Math.abs(size);
- int[] typeIndexes = new int[handlersCount];
- int[] addresses = new int[handlersCount];
- for (int i = 0; i < handlersCount; i++) {
- typeIndexes[i] = readUleb128();
- addresses[i] = readUleb128();
+ if (instructions.length % 2 == 1) {
+ readShort(); // padding
+ }
+
+ /*
+ * We can't read the tries until we've read the catch handlers.
+ * Unfortunately they're in the opposite order in the dex file
+ * so we need to read them out-of-order.
+ */
+ Section triesSection = open(data.position());
+ skip(triesSize * SizeOf.TRY_ITEM);
+ catchHandlers = readCatchHandlers();
+ tries = triesSection.readTries(triesSize, catchHandlers);
+ } else {
+ tries = new Try[0];
+ catchHandlers = new CatchHandler[0];
+ }
+ return new Code(registersSize, insSize, outsSize, debugInfoOffset, instructions,
+ tries, catchHandlers);
+ }
+
+ private CatchHandler[] readCatchHandlers() {
+ int baseOffset = data.position();
+ int catchHandlersSize = readUleb128();
+ CatchHandler[] result = new CatchHandler[catchHandlersSize];
+ for (int i = 0; i < catchHandlersSize; i++) {
+ int offset = data.position() - baseOffset;
+ result[i] = readCatchHandler(offset);
+ }
+ return result;
+ }
+
+ private Try[] readTries(int triesSize, CatchHandler[] catchHandlers) {
+ Try[] result = new Try[triesSize];
+ for (int i = 0; i < triesSize; i++) {
+ int startAddress = readInt();
+ int instructionCount = readUnsignedShort();
+ int handlerOffset = readUnsignedShort();
+ int catchHandlerIndex = findCatchHandlerIndex(catchHandlers, handlerOffset);
+ result[i] = new Try(startAddress, instructionCount, catchHandlerIndex);
+ }
+ return result;
+ }
+
+ private int findCatchHandlerIndex(CatchHandler[] catchHandlers, int offset) {
+ for (int i = 0; i < catchHandlers.length; i++) {
+ CatchHandler catchHandler = catchHandlers[i];
+ if (catchHandler.getOffset() == offset) {
+ return i;
}
- int catchAllAddress = size <= 0 ? readUleb128() : -1;
- return new Code.CatchHandler(typeIndexes, addresses, catchAllAddress);
+ }
+ throw new IllegalArgumentException();
+ }
+
+ private CatchHandler readCatchHandler(int offset) {
+ int size = readSleb128();
+ int handlersCount = Math.abs(size);
+ int[] typeIndexes = new int[handlersCount];
+ int[] addresses = new int[handlersCount];
+ for (int i = 0; i < handlersCount; i++) {
+ typeIndexes[i] = readUleb128();
+ addresses[i] = readUleb128();
+ }
+ int catchAllAddress = size <= 0 ? readUleb128() : -1;
+ return new CatchHandler(typeIndexes, addresses, catchAllAddress, offset);
}
private ClassData readClassData() {
@@ -643,6 +679,13 @@ public final class Dex {
return new EncodedValue(getBytesFrom(start));
}
+ public void skip(int count) {
+ if (count < 0) {
+ throw new IllegalArgumentException();
+ }
+ data.position(data.position() + count);
+ }
+
/**
* Skips bytes until the position is aligned to a multiple of 4.
*/
diff --git a/dex/src/main/java/com/android/dex/SizeOf.java b/dex/src/main/java/com/android/dex/SizeOf.java
index 03b40bd..65fab56 100644
--- a/dex/src/main/java/com/android/dex/SizeOf.java
+++ b/dex/src/main/java/com/android/dex/SizeOf.java
@@ -100,4 +100,11 @@ public final class SizeOf {
* offset uint
*/
public static final int MAP_ITEM = USHORT + USHORT + UINT + UINT;
+
+ /**
+ * start_addr uint
+ * insn_count ushort
+ * handler_off ushort
+ */
+ public static final int TRY_ITEM = UINT + USHORT + USHORT;
}