diff --git a/dexdump/DexDump.cpp b/dexdump/DexDump.cpp index fd7542e9de..157b661225 100644 --- a/dexdump/DexDump.cpp +++ b/dexdump/DexDump.cpp @@ -915,6 +915,9 @@ static char* indexString(DexFile* pDexFile, const DecodedInstruction* pDecInsn, free(protoInfo.parameterTypes); } break; + case kCallSiteRef: + outSize = snprintf(buf, bufSize, "call_site@%0*x", width, index); + break; default: outSize = snprintf(buf, bufSize, ""); break; @@ -1842,6 +1845,219 @@ void dumpRegisterMaps(DexFile* pDexFile) } } +static const DexMapItem* findMapItem(const DexFile* pDexFile, u4 type) +{ + u4 offset = pDexFile->pHeader->mapOff; + const DexMapList* list = (const DexMapList*)(pDexFile->baseAddr + offset); + for (u4 i = 0; i < list->size; ++i) { + if (list->list[i].type == type) { + return &list->list[i]; + } + } + return nullptr; +} + +static void dumpMethodHandles(DexFile* pDexFile) +{ + const DexMapItem* item = findMapItem(pDexFile, kDexTypeMethodHandleItem); + if (item == nullptr) return; + const DexMethodHandleItem* method_handles = + (const DexMethodHandleItem*)(pDexFile->baseAddr + item->offset); + for (u4 i = 0; i < item->size; ++i) { + const DexMethodHandleItem& mh = method_handles[i]; + bool is_invoke = false; + const char* type; + switch (mh.methodHandleType) { + case 0: + type = "put-static"; + break; + case 1: + type = "get-static"; + break; + case 2: + type = "put-instance"; + break; + case 3: + type = "get-instance"; + break; + case 4: + type = "invoke-static"; + is_invoke = true; + break; + case 5: + type = "invoke-instance"; + is_invoke = true; + break; + case 6: + type = "invoke-constructor"; + is_invoke = true; + break; + } + + FieldMethodInfo info; + memset(&info, 0, sizeof(info)); + if (is_invoke) { + getMethodInfo(pDexFile, mh.fieldOrMethodIdx, &info); + } else { + getFieldInfo(pDexFile, mh.fieldOrMethodIdx, &info); + } + + if (gOptions.outputFormat == OUTPUT_XML) { + printf("\n"); + } else { + printf("Method Handle #%u:\n", i); + printf(" type : %s\n", type); + printf(" target : %s %s\n", info.classDescriptor, info.name); + printf(" target_type : %s\n", info.signature); + } + } +} + +/* Helper for dumpCallSites(), which reads a 1- to 8- byte signed + * little endian value. */ +static u8 readSignedLittleEndian(const u1** pData, u4 size) { + const u1* data = *pData; + u8 result = 0; + u4 i; + + for (i = 0; i < size; i++) { + result = (result >> 8) | (((int64_t)*data++) << 56); + } + + result >>= (8 - size) * 8; + *pData = data; + return result; +} + +/* Helper for dumpCallSites(), which reads a 1- to 8- byte unsigned + * little endian value. */ +static u8 readUnsignedLittleEndian(const u1** pData, u4 size, bool fillOnRight = false) { + const u1* data = *pData; + u8 result = 0; + u4 i; + + for (i = 0; i < size; i++) { + result = (result >> 8) | (((u8)*data++) << 56); + } + + u8 oldResult = result; + if (!fillOnRight) { + result >>= (8u - size) * 8; + } + + *pData = data; + return result; +} + +static void dumpCallSites(DexFile* pDexFile) +{ + const DexMapItem* item = findMapItem(pDexFile, kDexTypeCallSiteIdItem); + if (item == nullptr) return; + const DexCallSiteId* ids = (const DexCallSiteId*)(pDexFile->baseAddr + item->offset); + for (u4 index = 0; index < item->size; ++index) { + bool doXml = (gOptions.outputFormat == OUTPUT_XML); + printf(doXml ? "\n" : "Call Site #%u\n", index); + const u1* data = pDexFile->baseAddr + ids[index].callSiteOff; + u4 count = readUnsignedLeb128(&data); + for (u4 i = 0; i < count; ++i) { + printf(doXml ? "> kDexAnnotationValueArgShift; + switch (valueType) { + case kDexAnnotationByte: { + printf(doXml ? "type=\"byte\" value=\"%d\"/>" : "%d (byte)", (int)*data++); + break; + } + case kDexAnnotationShort: { + printf(doXml ? "type=\"short\" value=\"%d\"/>" : "%d (short)", + (int)readSignedLittleEndian(&data, valueArg + 1)); + break; + } + case kDexAnnotationChar: { + printf(doXml ? "type=\"short\" value=\"%u\"/>" : "%u (char)", + (u2)readUnsignedLittleEndian(&data, valueArg + 1)); + break; + } + case kDexAnnotationInt: { + printf(doXml ? "type=\"int\" value=\"%d\"/>" : "%d (int)", + (int)readSignedLittleEndian(&data, valueArg + 1)); + break; + } + case kDexAnnotationLong: { + printf(doXml ? "type=\"long\" value=\"%" PRId64 "\"/>" : "%" PRId64 " (long)", + (int64_t)readSignedLittleEndian(&data, valueArg + 1)); + break; + } + case kDexAnnotationFloat: { + u4 rawValue = (u4)(readUnsignedLittleEndian(&data, valueArg + 1, true) >> 32); + printf(doXml ? "type=\"float\" value=\"%g\"/>" : "%g (float)", + *((float*)&rawValue)); + break; + } + case kDexAnnotationDouble: { + u8 rawValue = readUnsignedLittleEndian(&data, valueArg + 1, true); + printf(doXml ? "type=\"double\" value=\"%g\"/>" : "%g (double)", + *((double*)&rawValue)); + break; + } + case kDexAnnotationMethodType: { + u4 idx = (u4) readUnsignedLittleEndian(&data, valueArg + 1); + ProtoInfo protoInfo; + memset(&protoInfo, 0, sizeof(protoInfo)); + getProtoInfo(pDexFile, idx, &protoInfo); + printf(doXml ? "type=\"MethodType\" value=\"(%s)%s\"/>" : "(%s)%s (MethodType)", + protoInfo.parameterTypes, protoInfo.returnType); + free(protoInfo.parameterTypes); + break; + } + case kDexAnnotationMethodHandle: { + u4 idx = (u4) readUnsignedLittleEndian(&data, valueArg + 1); + printf(doXml ? "type=\"MethodHandle\" value=\"%u\"/>" : "%u (MethodHandle)", + idx); + break; + } + case kDexAnnotationString: { + u4 idx = (u4) readUnsignedLittleEndian(&data, valueArg + 1); + printf(doXml ? "type=\"String\" value=\"%s\"/>" : "%s (String)", + dexStringById(pDexFile, idx)); + break; + } + case kDexAnnotationType: { + u4 idx = (u4) readUnsignedLittleEndian(&data, valueArg + 1); + printf(doXml ? "type=\"Class\" value=\"%s\"/>" : "%s (Class)", + dexStringByTypeIdx(pDexFile, idx)); + break; + } + case kDexAnnotationNull: { + printf(doXml ? "type=\"null\" value=\"null\"/>" : "null (null)"); + break; + } + case kDexAnnotationBoolean: { + printf(doXml ? "type=\"boolean\" value=\"%s\"/>" : "%s (boolean)", + (valueArg & 1) == 0 ? "false" : "true"); + break; + } + default: + // Other types are not anticipated being reached here. + printf("Unexpected type found, bailing on call site info.\n"); + i = count; + break; + } + printf("\n"); + } + + if (doXml) { + printf("\n"); + } + } +} + /* * Dump the requested sections of the file. */ @@ -1875,6 +2091,9 @@ void processDexFile(const char* fileName, DexFile* pDexFile) dumpClass(pDexFile, i, &package); } + dumpMethodHandles(pDexFile); + dumpCallSites(pDexFile); + /* free the last one allocated */ if (package != NULL) { printf("\n"); diff --git a/dx/src/com/android/dx/dex/code/Dops.java b/dx/src/com/android/dx/dex/code/Dops.java index f3c2b496e7..cc87695630 100644 --- a/dx/src/com/android/dx/dex/code/Dops.java +++ b/dx/src/com/android/dx/dex/code/Dops.java @@ -501,10 +501,6 @@ public final class Dops { new Dop(Opcodes.INVOKE_INTERFACE, Opcodes.INVOKE_INTERFACE, Opcodes.INVOKE_INTERFACE_RANGE, Form35c.THE_ONE, false); - public static final Dop INVOKE_POLYMORPHIC = - new Dop(Opcodes.INVOKE_POLYMORPHIC, Opcodes.INVOKE_POLYMORPHIC, - Opcodes.INVOKE_POLYMORPHIC_RANGE, Form45cc.THE_ONE, false); - public static final Dop INVOKE_VIRTUAL_RANGE = new Dop(Opcodes.INVOKE_VIRTUAL_RANGE, Opcodes.INVOKE_VIRTUAL, Opcodes.NO_NEXT, Form3rc.THE_ONE, false); @@ -525,10 +521,6 @@ public final class Dops { new Dop(Opcodes.INVOKE_INTERFACE_RANGE, Opcodes.INVOKE_INTERFACE, Opcodes.NO_NEXT, Form3rc.THE_ONE, false); - public static final Dop INVOKE_POLYMORPHIC_RANGE = - new Dop(Opcodes.INVOKE_POLYMORPHIC_RANGE, Opcodes.INVOKE_POLYMORPHIC, - Opcodes.NO_NEXT, Form4rcc.THE_ONE, false); - public static final Dop NEG_INT = new Dop(Opcodes.NEG_INT, Opcodes.NEG_INT, Opcodes.NO_NEXT, Form12x.THE_ONE, true); @@ -945,6 +937,22 @@ public final class Dops { new Dop(Opcodes.USHR_INT_LIT8, Opcodes.USHR_INT, Opcodes.NO_NEXT, Form22b.THE_ONE, true); + public static final Dop INVOKE_POLYMORPHIC = + new Dop(Opcodes.INVOKE_POLYMORPHIC, Opcodes.INVOKE_POLYMORPHIC, + Opcodes.INVOKE_POLYMORPHIC_RANGE, Form45cc.THE_ONE, true); + + public static final Dop INVOKE_POLYMORPHIC_RANGE = + new Dop(Opcodes.INVOKE_POLYMORPHIC_RANGE, Opcodes.INVOKE_POLYMORPHIC, + Opcodes.NO_NEXT, Form4rcc.THE_ONE, true); + + public static final Dop INVOKE_CUSTOM = + new Dop(Opcodes.INVOKE_CUSTOM, Opcodes.INVOKE_CUSTOM, + Opcodes.INVOKE_CUSTOM_RANGE, Form35c.THE_ONE, true); + + public static final Dop INVOKE_CUSTOM_RANGE = + new Dop(Opcodes.INVOKE_CUSTOM_RANGE, Opcodes.INVOKE_CUSTOM, + Opcodes.NO_NEXT, Form3rc.THE_ONE, true); + // END(dops) // Static initialization. @@ -1174,6 +1182,8 @@ public final class Dops { set(USHR_INT_LIT8); set(INVOKE_POLYMORPHIC); set(INVOKE_POLYMORPHIC_RANGE); + set(INVOKE_CUSTOM); + set(INVOKE_CUSTOM_RANGE); // END(dops-init) } diff --git a/dx/src/com/android/dx/dex/code/RopToDop.java b/dx/src/com/android/dx/dex/code/RopToDop.java index affa9ebf24..927db3efcf 100644 --- a/dx/src/com/android/dx/dex/code/RopToDop.java +++ b/dx/src/com/android/dx/dex/code/RopToDop.java @@ -214,6 +214,7 @@ private RopToDop() { // Opcodes.SHR_INT_LIT8 // Opcodes.USHR_INT_LIT8 // Opcodes.INVOKE_POLYMORPHIC + // Opcodes.INVOKE_CUSTOM // END(first-opcodes) static { diff --git a/dx/src/com/android/dx/io/IndexType.java b/dx/src/com/android/dx/io/IndexType.java index d87389491b..0bd142a899 100644 --- a/dx/src/com/android/dx/io/IndexType.java +++ b/dx/src/com/android/dx/io/IndexType.java @@ -44,6 +44,9 @@ public enum IndexType { /** method index and a proto index */ METHOD_AND_PROTO_REF, + /** call site reference index */ + CALL_SITE_REF, + /** inline method index (for inline linked method invocations) */ INLINE_METHOD, diff --git a/dx/src/com/android/dx/io/OpcodeInfo.java b/dx/src/com/android/dx/io/OpcodeInfo.java index 60225f1f87..500abf7a25 100644 --- a/dx/src/com/android/dx/io/OpcodeInfo.java +++ b/dx/src/com/android/dx/io/OpcodeInfo.java @@ -939,6 +939,14 @@ public final class OpcodeInfo { new Info(Opcodes.INVOKE_POLYMORPHIC_RANGE, "invoke-polymorphic/range", InstructionCodec.FORMAT_4RCC, IndexType.METHOD_AND_PROTO_REF); + public static final Info INVOKE_CUSTOM = + new Info(Opcodes.INVOKE_CUSTOM, "invoke-custom", + InstructionCodec.FORMAT_35C, IndexType.CALL_SITE_REF); + + public static final Info INVOKE_CUSTOM_RANGE = + new Info(Opcodes.INVOKE_CUSTOM_RANGE, "invoke-custom/range", + InstructionCodec.FORMAT_3RC, IndexType.CALL_SITE_REF); + // END(opcode-info-defs) // Static initialization. @@ -1174,6 +1182,8 @@ public final class OpcodeInfo { set(USHR_INT_LIT8); set(INVOKE_POLYMORPHIC); set(INVOKE_POLYMORPHIC_RANGE); + set(INVOKE_CUSTOM); + set(INVOKE_CUSTOM_RANGE); // END(opcode-info-init) } diff --git a/dx/src/com/android/dx/io/Opcodes.java b/dx/src/com/android/dx/io/Opcodes.java index 6f135de9bc..9afee410b8 100644 --- a/dx/src/com/android/dx/io/Opcodes.java +++ b/dx/src/com/android/dx/io/Opcodes.java @@ -261,6 +261,8 @@ public final class Opcodes { public static final int USHR_INT_LIT8 = 0xe2; public static final int INVOKE_POLYMORPHIC = 0xfa; public static final int INVOKE_POLYMORPHIC_RANGE = 0xfb; + public static final int INVOKE_CUSTOM = 0xfc; + public static final int INVOKE_CUSTOM_RANGE = 0xfd; // END(opcodes) // TODO: Generate these payload opcodes with opcode-gen. diff --git a/libdex/DexFile.h b/libdex/DexFile.h index 6c4d0d8ab8..74fce3c495 100644 --- a/libdex/DexFile.h +++ b/libdex/DexFile.h @@ -92,6 +92,11 @@ typedef int64_t s8; */ #define DEX_MAGIC_VERS_37 "037\0" +/* The version for android O, encoded in 4 bytes of ASCII. This differentiates dex files that may + * contain invoke-custom, invoke-polymorphic, call-sites, and method handles. + */ +#define DEX_MAGIC_VERS_38 "038\0" + /* current version, encoded in 4 bytes of ASCII */ #define DEX_MAGIC_VERS "036\0" @@ -191,6 +196,8 @@ enum { kDexAnnotationLong = 0x06, kDexAnnotationFloat = 0x10, kDexAnnotationDouble = 0x11, + kDexAnnotationMethodType = 0x15, + kDexAnnotationMethodHandle = 0x16, kDexAnnotationString = 0x17, kDexAnnotationType = 0x18, kDexAnnotationField = 0x19, @@ -214,6 +221,8 @@ enum { kDexTypeFieldIdItem = 0x0004, kDexTypeMethodIdItem = 0x0005, kDexTypeClassDefItem = 0x0006, + kDexTypeCallSiteIdItem = 0x0007, + kDexTypeMethodHandleItem = 0x0008, kDexTypeMapList = 0x1000, kDexTypeTypeList = 0x1001, kDexTypeAnnotationSetRefList = 0x1002, @@ -354,6 +363,23 @@ struct DexClassDef { u4 staticValuesOff; /* file offset to DexEncodedArray */ }; +/* + * Direct-mapped "call_site_id_item" + */ +struct DexCallSiteId { + u4 callSiteOff; /* file offset to DexEncodedArray */ +}; + +/* + * Direct-mapped "method_handle_item" + */ +struct DexMethodHandleItem { + u2 methodHandleType; /* type of method handle */ + u2 reserved1; /* reserved for future use */ + u2 fieldOrMethodIdx; /* index of associated field or method */ + u2 reserved2; /* reserved for future use */ +}; + /* * Direct-mapped "type_item". */ diff --git a/libdex/DexOpcodes.cpp b/libdex/DexOpcodes.cpp index d8f850e1a8..8a98772391 100644 --- a/libdex/DexOpcodes.cpp +++ b/libdex/DexOpcodes.cpp @@ -282,8 +282,8 @@ static const char* gOpNames[kNumPackedOpcodes] = { "+invoke-virtual-quick/range", "invoke-polymorphic", "invoke-polymorphic/range", - "+iput-object-volatile", - "+sget-object-volatile", + "invoke-custom", + "invoke-custom/range", "+sput-object-volatile", "unused-ff", // END(libdex-opcode-names) diff --git a/libdex/DexOpcodes.h b/libdex/DexOpcodes.h index 09fdcdb8e7..625a2e875a 100644 --- a/libdex/DexOpcodes.h +++ b/libdex/DexOpcodes.h @@ -320,8 +320,8 @@ enum Opcode { OP_INVOKE_VIRTUAL_QUICK_RANGE = 0xf9, OP_INVOKE_POLYMORPHIC = 0xfa, OP_INVOKE_POLYMORPHIC_RANGE = 0xfb, - OP_IPUT_OBJECT_VOLATILE = 0xfc, - OP_SGET_OBJECT_VOLATILE = 0xfd, + OP_INVOKE_CUSTOM = 0xfc, + OP_INVOKE_CUSTOM_RANGE = 0xfd, OP_SPUT_OBJECT_VOLATILE = 0xfe, OP_UNUSED_FF = 0xff, // END(libdex-opcode-enum) @@ -586,8 +586,8 @@ enum Opcode { H(OP_INVOKE_VIRTUAL_QUICK_RANGE), \ H(OP_INVOKE_POLYMORPHIC), \ H(OP_INVOKE_POLYMORPHIC_RANGE), \ - H(OP_IPUT_OBJECT_VOLATILE), \ - H(OP_SGET_OBJECT_VOLATILE), \ + H(OP_INVOKE_CUSTOM), \ + H(OP_INVOKE_CUSTOM_RANGE), \ H(OP_SPUT_OBJECT_VOLATILE), \ H(OP_UNUSED_FF), \ /* END(libdex-goto-table) */ \ diff --git a/libdex/DexSwapVerify.cpp b/libdex/DexSwapVerify.cpp index 54d0c33e56..bd9140cd34 100644 --- a/libdex/DexSwapVerify.cpp +++ b/libdex/DexSwapVerify.cpp @@ -45,10 +45,12 @@ struct CheckState { const DexHeader* pHeader; const u1* fileStart; - const u1* fileEnd; // points to fileStart + fileLen + const u1* fileEnd; // points to fileStart + fileLen u4 fileLen; - DexDataMap* pDataMap; // set after map verification - const DexFile* pDexFile; // set after intraitem verification + DexDataMap* pDataMap; // set after map verification + const DexFile* pDexFile; // set after intraitem verification + const DexMapItem* pCallSiteIds; // set after intraitem verification + const DexMapItem* pMethodHandleItems; // set after intraitem verification /* * bitmap of type_id indices that have been used to define classes; @@ -335,6 +337,8 @@ static u4 mapTypeToBitMask(int mapType) { case kDexTypeAnnotationItem: return 1 << 15; case kDexTypeEncodedArrayItem: return 1 << 16; case kDexTypeAnnotationsDirectoryItem: return 1 << 17; + case kDexTypeCallSiteIdItem: return 1 << 18; + case kDexTypeMethodHandleItem: return 1 << 19; default: { ALOGE("Unknown map item type %04x", mapType); return 0; @@ -430,6 +434,12 @@ static bool swapMap(CheckState* state, DexMapList* pMap) return false; } + if (item->type == kDexTypeCallSiteIdItem) { + state->pCallSiteIds = item; + } else if (item->type == kDexTypeMethodHandleItem) { + state->pMethodHandleItems = item; + } + usedBits |= bit; lastOffset = item->offset; item++; @@ -1036,6 +1046,48 @@ static void* crossVerifyClassDefItem(const CheckState* state, void* ptr) { return (void*) (item + 1); } +/* Perform cross-item verification of call_site_id. */ +static void* crossVerifyCallSiteId(const CheckState* state, void* ptr) { + const DexCallSiteId* item = (const DexCallSiteId*) ptr; + if (state->pCallSiteIds == nullptr) { + ALOGE("Verifying call site but expecting none"); + return NULL; + } + if (item->callSiteOff < state->pHeader->dataOff || + item->callSiteOff >= state->pHeader->dataOff + state->pHeader->dataSize) { + ALOGE("Bad call site offset: %u", item->callSiteOff); + return NULL; + } + return (void*) (item + 1); +} + +/* Perform cross-item verification of method_handle_item. */ +static void* crossVerifyMethodHandleItem(const CheckState* state, void* ptr) { + const DexMethodHandleItem* item = (const DexMethodHandleItem*) ptr; + if (state->pMethodHandleItems == nullptr) { + ALOGE("Verifying method handle but expecting none"); + return NULL; + } + if (item->methodHandleType <= 3 && + item->fieldOrMethodIdx >= state->pHeader->fieldIdsSize) { + // 0-3 are field accessors. + ALOGE("Method handle has invalid field id: %u\n", item->fieldOrMethodIdx); + return NULL; + } + if (item->methodHandleType >= 4 && + item->methodHandleType <= 6 && + item->fieldOrMethodIdx >= state->pHeader->methodIdsSize) { + // 4-6 are method invocations. + ALOGE("Method handle has invalid method id: %u\n", item->fieldOrMethodIdx); + return NULL; + } + if (item->methodHandleType >= 7) { + ALOGE("Unknown method handle type: %u", item->methodHandleType); + return NULL; + } + return (void*) (item + 1); +} + /* Helper for swapAnnotationsDirectoryItem(), which performs * byte-swapping and intra-item verification on an * annotation_directory_item's field elements. */ @@ -1164,6 +1216,26 @@ static void* swapAnnotationsDirectoryItem(const CheckState* state, void* ptr) { return addr; } +static void* swapCallSiteId(const CheckState* state, void* ptr) { + DexCallSiteId* item = (DexCallSiteId*) ptr; + + CHECK_PTR_RANGE(item, item + 1); + SWAP_OFFSET4(item->callSiteOff); + + return (item + 1); +} + +static void* swapMethodHandleItem(const CheckState* state, void* ptr) { + DexMethodHandleItem* item = (DexMethodHandleItem*) ptr; + + CHECK_PTR_RANGE(item, item + 1); + SWAP_FIELD2(item->methodHandleType); + SWAP_FIELD2(item->fieldOrMethodIdx); + + return (item + 1); +} + + /* Helper for crossVerifyAnnotationsDirectoryItem(), which checks the * field elements. */ static const u1* crossVerifyFieldAnnotations(const CheckState* state, u4 count, @@ -2144,6 +2216,13 @@ static const u1* verifyEncodedArray(const CheckState* state, return data; } +static u4 numberOfMethodHandles(const CheckState* state) { + if (state->pMethodHandleItems != nullptr) { + return state->pMethodHandleItems->size; + } + return 0; +} + /* Helper for *VerifyAnnotationItem() and *VerifyEncodedArrayItem(), which * verifies an encoded_value. */ static const u1* verifyEncodedValue(const CheckState* state, @@ -2186,6 +2265,24 @@ static const u1* verifyEncodedValue(const CheckState* state, data += valueArg + 1; break; } + case kDexAnnotationMethodType: { + if (valueArg > 3) { + ALOGE("Bogus method type size %#x", valueArg); + return NULL; + } + u4 idx = readUnsignedLittleEndian(state, &data, valueArg + 1); + CHECK_INDEX(idx, state->pHeader->protoIdsSize); + break; + } + case kDexAnnotationMethodHandle: { + if (valueArg > 3) { + ALOGE("Bogus method type size %#x", valueArg); + return NULL; + } + u4 idx = readUnsignedLittleEndian(state, &data, valueArg + 1); + CHECK_INDEX(idx, numberOfMethodHandles(state)); + break; + } case kDexAnnotationString: { if (valueArg > 3) { ALOGE("Bogus string size %#x", valueArg); @@ -2595,6 +2692,18 @@ static bool swapEverythingButHeaderAndMap(CheckState* state, sizeof(u4), &lastOffset); break; } + case kDexTypeCallSiteIdItem: { + okay = checkBoundsAndIterateSection(state, sectionOffset, + sectionCount, sectionOffset, sectionCount, + swapCallSiteId, sizeof(u4), &lastOffset); + break; + } + case kDexTypeMethodHandleItem: { + okay = checkBoundsAndIterateSection(state, sectionOffset, + sectionCount, sectionOffset, sectionCount, + swapMethodHandleItem, sizeof(u4), &lastOffset); + break; + } case kDexTypeMapList: { /* * The map section was swapped early on, but do some @@ -2742,6 +2851,16 @@ static bool crossVerifyEverything(CheckState* state, DexMapList* pMap) state->pDefinedClassBits = NULL; break; } + case kDexTypeCallSiteIdItem: { + okay = iterateSection(state, sectionOffset, sectionCount, + crossVerifyCallSiteId, sizeof(u4), NULL); + break; + } + case kDexTypeMethodHandleItem: { + okay = iterateSection(state, sectionOffset, sectionCount, + crossVerifyMethodHandleItem, sizeof(u4), NULL); + break; + } case kDexTypeAnnotationSetRefList: { okay = iterateSection(state, sectionOffset, sectionCount, crossVerifyAnnotationSetRefList, sizeof(u4), NULL); @@ -2792,8 +2911,9 @@ bool dexHasValidMagic(const DexHeader* pHeader) } if ((memcmp(version, DEX_MAGIC_VERS, 4) != 0) && - (memcmp(version, DEX_MAGIC_VERS_API_13, 4) != 0) && - (memcmp(version, DEX_MAGIC_VERS_37, 4) != 0)) { + (memcmp(version, DEX_MAGIC_VERS_API_13, 4) != 0) && + (memcmp(version, DEX_MAGIC_VERS_37, 4) != 0) && + (memcmp(version, DEX_MAGIC_VERS_38, 4) != 0)) { /* * Magic was correct, but this is an unsupported older or * newer format variant. diff --git a/libdex/InstrUtils.cpp b/libdex/InstrUtils.cpp index 3b7d55278c..3e813984a8 100644 --- a/libdex/InstrUtils.cpp +++ b/libdex/InstrUtils.cpp @@ -47,7 +47,7 @@ static InstructionWidth gInstructionWidthTable[kNumPackedOpcodes] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 3, 3, - 3, 1, 2, 2, 2, 2, 2, 2, 3, 3, 4, 4, 2, 2, 2, 0, + 3, 1, 2, 2, 2, 2, 2, 2, 3, 3, 4, 4, 3, 3, 2, 0, // END(libdex-widths) }; @@ -309,8 +309,8 @@ static u1 gOpcodeFlagsTable[kNumPackedOpcodes] = { kInstrCanContinue|kInstrCanThrow|kInstrInvoke, kInstrCanContinue|kInstrCanThrow|kInstrInvoke, kInstrCanContinue|kInstrCanThrow|kInstrInvoke, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, + kInstrCanContinue|kInstrCanThrow|kInstrInvoke, + kInstrCanContinue|kInstrCanThrow|kInstrInvoke, kInstrCanContinue|kInstrCanThrow, 0, // END(libdex-flags) @@ -358,7 +358,7 @@ static u1 gInstructionFormatTable[kNumPackedOpcodes] = { kFmt22c, kFmt22c, kFmt22c, kFmt21c, kFmt21c, kFmt00x, kFmt20bc, kFmt35mi, kFmt3rmi, kFmt35c, kFmt10x, kFmt22cs, kFmt22cs, kFmt22cs, kFmt22cs, kFmt22cs, kFmt22cs, kFmt35ms, kFmt3rms, kFmt45cc, kFmt4rcc, - kFmt22c, kFmt21c, kFmt21c, kFmt00x, + kFmt35c, kFmt3rc, kFmt21c, kFmt00x, // END(libdex-formats) }; @@ -452,7 +452,7 @@ static u1 gInstructionIndexTypeTable[kNumPackedOpcodes] = { kIndexFieldOffset, kIndexFieldOffset, kIndexFieldOffset, kIndexFieldOffset, kIndexFieldOffset, kIndexVtableOffset, kIndexVtableOffset, kIndexMethodAndProtoRef, kIndexMethodAndProtoRef, - kIndexFieldRef, kIndexFieldRef, kIndexFieldRef, + kCallSiteRef, kCallSiteRef, kIndexFieldRef, kIndexUnknown, // END(libdex-index-types) }; diff --git a/libdex/InstrUtils.h b/libdex/InstrUtils.h index 2f34bd948f..e8ae4c8dc0 100644 --- a/libdex/InstrUtils.h +++ b/libdex/InstrUtils.h @@ -80,7 +80,8 @@ enum InstructionIndexType { kIndexInlineMethod, // inline method index (for inline linked methods) kIndexVtableOffset, // vtable offset (for static linked methods) kIndexFieldOffset, // field offset (for static linked fields) - kIndexMethodAndProtoRef // method index and proto index + kIndexMethodAndProtoRef, // method index and proto index + kCallSiteRef // call site index }; /* diff --git a/opcode-gen/bytecode.txt b/opcode-gen/bytecode.txt index dc0778d5fe..840d433b17 100644 --- a/opcode-gen/bytecode.txt +++ b/opcode-gen/bytecode.txt @@ -69,6 +69,7 @@ format 3rms # vtable-offset # field-offset # method-and-proto-ref +# call-site-ref # flags; pipe-combined combo of one or more of: # optimized -- optimized; not to be included in unoptimized dex files # branch -- might branch to an address @@ -343,11 +344,11 @@ op f9 +invoke-virtual-quick/range 3rms n vtable-offset optimized|continue|thro # Invoke-polymorphic op fa invoke-polymorphic 45cc y method-and-proto-ref continue|throw|invoke op fb invoke-polymorphic/range 4rcc y method-and-proto-ref continue|throw|invoke +op fc invoke-custom 35c y call-site-ref continue|throw|invoke +op fd invoke-custom/range 3rc y call-site-ref continue|throw|invoke # More optimized opcodes (not valid in an unoptimized dex file) -op fc +iput-object-volatile 22c n field-ref optimized|continue|throw -op fd +sget-object-volatile 21c y field-ref optimized|continue|throw op fe +sput-object-volatile 21c n field-ref optimized|continue|throw # unused: op ff diff --git a/opcode-gen/opcode-gen.awk b/opcode-gen/opcode-gen.awk index d1e9a088bb..baf774b6b5 100644 --- a/opcode-gen/opcode-gen.awk +++ b/opcode-gen/opcode-gen.awk @@ -485,6 +485,7 @@ function initIndexTypes() { indexTypeValues["vtable-offset"] = "kIndexVtableOffset"; indexTypeValues["field-offset"] = "kIndexFieldOffset"; indexTypeValues["method-and-proto-ref"] = "kIndexMethodAndProtoRef"; + indexTypeValues["call-site-ref"] = "kCallSiteRef"; } # Initialize the flags data.