diff options
author | David Sehr <sehr@google.com> | 2019-04-04 19:42:15 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2019-04-04 19:42:15 +0000 |
commit | 8843541a211b388bd2d48037ea6595265d125730 (patch) | |
tree | 508eb8af457e6394312126b9c2941d35ba3911b9 | |
parent | 6bc54f7aedd7c8c526f4eed4cc67bc0c88703f3c (diff) | |
parent | f33b916861cf30ac51de7156ec4e69fa79d280b3 (diff) | |
download | dalvik-oreo-mr1-iot-release.tar.gz |
Merge "Remove dalvik/libdex"android-q-preview-6android-q-preview-5android-q-preview-4android-q-preview-2.5android-o-mr1-iot-release-1.0.12oreo-mr1-iot-release
35 files changed, 0 insertions, 10948 deletions
diff --git a/Android.bp b/Android.bp index afc34655c..702d27da4 100644 --- a/Android.bp +++ b/Android.bp @@ -1,5 +1,4 @@ subdirs = [ "dx", - "libdex", "tools/hprof-conv", ] diff --git a/libdex/Android.bp b/libdex/Android.bp deleted file mode 100644 index 737e097cd..000000000 --- a/libdex/Android.bp +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (C) 2008 The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -cc_library_static { - name: "libdex", - host_supported: true, - - srcs: [ - "CmdUtils.cpp", - "DexCatch.cpp", - "DexClass.cpp", - "DexDataMap.cpp", - "DexDebugInfo.cpp", - "DexFile.cpp", - "DexInlines.cpp", - "DexOptData.cpp", - "DexOpcodes.cpp", - "DexProto.cpp", - "DexSwapVerify.cpp", - "DexUtf.cpp", - "InstrUtils.cpp", - "Leb128.cpp", - "OptInvocation.cpp", - "sha1.cpp", - "SysUtil.cpp", - ], - include_dirs: [ - "dalvik", - "external/zlib", - ], - static_libs: ["liblog"], - whole_static_libs: ["libziparchive"], - - cflags: [ - "-Wall", - "-Werror", - "-Wimplicit-fallthrough", - ], - target: { - windows: { - enabled: true, - cflags: ["-Wno-unused-parameter"], - }, - }, -} diff --git a/libdex/CmdUtils.cpp b/libdex/CmdUtils.cpp deleted file mode 100644 index 8244a1189..000000000 --- a/libdex/CmdUtils.cpp +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* - * Some utility functions for use with command-line utilities. - */ -#include "DexFile.h" -#include "ZipArchive.h" -#include "CmdUtils.h" - -#include <stdlib.h> -#include <string.h> -#include <strings.h> -#include <fcntl.h> -#include <errno.h> - -#ifndef O_BINARY -#define O_BINARY 0 -#endif - -/* - * Extract "classes.dex" from archive file. - * - * If "quiet" is set, don't report common errors. - */ -UnzipToFileResult dexUnzipToFile(const char* zipFileName, - const char* outFileName, bool quiet) -{ - UnzipToFileResult result = kUTFRSuccess; - static const char* kFileToExtract = "classes.dex"; - ZipArchiveHandle archive; - ZipEntry entry; - bool unlinkOnFailure = false; - int fd = -1; - - if (dexZipOpenArchive(zipFileName, &archive) != 0) { - if (!quiet) { - fprintf(stderr, "Unable to open '%s' as zip archive\n", - zipFileName); - } - result = kUTFRNotZip; - goto bail; - } - - fd = open(outFileName, O_RDWR | O_CREAT | O_EXCL | O_BINARY, 0600); - if (fd < 0) { - fprintf(stderr, "Unable to create output file '%s': %s\n", - outFileName, strerror(errno)); - result = kUTFROutputFileProblem; - goto bail; - } - - unlinkOnFailure = true; - - if (dexZipFindEntry(archive, kFileToExtract, &entry) != 0) { - if (!quiet) { - fprintf(stderr, "Unable to find '%s' in '%s'\n", - kFileToExtract, zipFileName); - } - result = kUTFRNoClassesDex; - goto bail; - } - - if (dexZipExtractEntryToFile(archive, &entry, fd) != 0) { - fprintf(stderr, "Extract of '%s' from '%s' failed\n", - kFileToExtract, zipFileName); - result = kUTFRBadZip; - goto bail; - } - -bail: - if (fd >= 0) - close(fd); - if (unlinkOnFailure && result != kUTFRSuccess) - unlink(outFileName); - dexZipCloseArchive(archive); - return result; -} - -/* - * Map the specified DEX file read-only (possibly after expanding it into a - * temp file from a Jar). Pass in a MemMapping struct to hold the info. - * If the file is an unoptimized DEX file, then byte-swapping and structural - * verification are performed on it before the memory is made read-only. - * - * The temp file is deleted after the map succeeds. - * - * This is intended for use by tools (e.g. dexdump) that need to get a - * read-only copy of a DEX file that could be in a number of different states. - * - * If "tempFileName" is NULL, a default value is used. The temp file is - * deleted after the map succeeds. - * - * If "quiet" is set, don't report common errors. - * - * Returns 0 (kUTFRSuccess) on success. - */ -UnzipToFileResult dexOpenAndMap(const char* fileName, const char* tempFileName, - MemMapping* pMap, bool quiet) -{ - UnzipToFileResult result = kUTFRGenericFailure; - int len = strlen(fileName); - char tempNameBuf[32]; - bool removeTemp = false; - int fd = -1; - - if (len < 5) { - if (!quiet) { - fprintf(stderr, - "ERROR: filename must end in .dex, .zip, .jar, or .apk\n"); - } - result = kUTFRBadArgs; - goto bail; - } - - if (strcasecmp(fileName + len -3, "dex") != 0) { - if (tempFileName == NULL) { - /* - * Try .zip/.jar/.apk, all of which are Zip archives with - * "classes.dex" inside. We need to extract the compressed - * data to a temp file, the location of which varies. - * - * On the device we must use /sdcard because most other - * directories aren't writable (either because of permissions - * or because the volume is mounted read-only). On desktop - * it's nice to use the designated temp directory. - */ - if (access("/tmp", W_OK) == 0) { - sprintf(tempNameBuf, "/tmp/dex-temp-%d", getpid()); - } else if (access("/sdcard", W_OK) == 0) { - sprintf(tempNameBuf, "/sdcard/dex-temp-%d", getpid()); - } else { - fprintf(stderr, - "NOTE: /tmp and /sdcard unavailable for temp files\n"); - sprintf(tempNameBuf, "dex-temp-%d", getpid()); - } - - tempFileName = tempNameBuf; - } - - result = dexUnzipToFile(fileName, tempFileName, quiet); - - if (result == kUTFRSuccess) { - //printf("+++ Good unzip to '%s'\n", tempFileName); - fileName = tempFileName; - removeTemp = true; - } else if (result == kUTFRNotZip) { - if (!quiet) { - fprintf(stderr, "Not Zip, retrying as DEX\n"); - } - } else { - if (!quiet && result == kUTFRNoClassesDex) { - fprintf(stderr, "Zip has no classes.dex\n"); - } - goto bail; - } - } - - result = kUTFRGenericFailure; - - /* - * Pop open the (presumed) DEX file. - */ - fd = open(fileName, O_RDONLY | O_BINARY); - if (fd < 0) { - if (!quiet) { - fprintf(stderr, "ERROR: unable to open '%s': %s\n", - fileName, strerror(errno)); - } - goto bail; - } - - if (sysMapFileInShmemWritableReadOnly(fd, pMap) != 0) { - fprintf(stderr, "ERROR: Unable to map '%s'\n", fileName); - goto bail; - } - - /* - * This call will fail if the file exists on a filesystem that - * doesn't support mprotect(). If that's the case, then the file - * will have already been mapped private-writable by the previous - * call, so we don't need to do anything special if this call - * returns non-zero. - */ - sysChangeMapAccess(pMap->addr, pMap->length, true, pMap); - - if (dexSwapAndVerifyIfNecessary((u1*) pMap->addr, pMap->length)) { - fprintf(stderr, "ERROR: Failed structural verification of '%s'\n", - fileName); - goto bail; - } - - /* - * Similar to above, this call will fail if the file wasn't ever - * read-only to begin with. This is innocuous, though it is - * undesirable from a memory hygiene perspective. - */ - sysChangeMapAccess(pMap->addr, pMap->length, false, pMap); - - /* - * Success! Close the file and return with the start/length in pMap. - */ - result = kUTFRSuccess; - -bail: - if (fd >= 0) - close(fd); - if (removeTemp) { - /* this will fail if the OS doesn't allow removal of a mapped file */ - if (unlink(tempFileName) != 0) { - fprintf(stderr, "WARNING: unable to remove temp '%s'\n", - tempFileName); - } - } - return result; -} diff --git a/libdex/CmdUtils.h b/libdex/CmdUtils.h deleted file mode 100644 index 887eed9ba..000000000 --- a/libdex/CmdUtils.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* - * Access .dex (Dalvik Executable Format) files. The code here assumes that - * the DEX file has been rewritten (byte-swapped, word-aligned) and that - * the contents can be directly accessed as a collection of C arrays. Please - * see docs/dalvik/dex-format.html for a detailed description. - * - * The structure and field names were chosen to match those in the DEX spec. - * - * It's generally assumed that the DEX file will be stored in shared memory, - * obviating the need to copy code and constant pool entries into newly - * allocated storage. Maintaining local pointers to items in the shared area - * is valid and encouraged. - * - * All memory-mapped structures are 32-bit aligned unless otherwise noted. - */ -#ifndef LIBDEX_CMDUTILS_H_ -#define LIBDEX_CMDUTILS_H_ - -/* encode the result of unzipping to a file */ -enum UnzipToFileResult { - kUTFRSuccess = 0, - kUTFRGenericFailure, - kUTFRBadArgs, - kUTFRNotZip, - kUTFRNoClassesDex, - kUTFROutputFileProblem, - kUTFRBadZip, -}; - -/* - * Map the specified DEX file read-only (possibly after expanding it into a - * temp file from a Jar). Pass in a MemMapping struct to hold the info. - * If the file is an unoptimized DEX file, then byte-swapping and structural - * verification are performed on it before the memory is made read-only. - * - * The temp file is deleted after the map succeeds. - * - * This is intended for use by tools (e.g. dexdump) that need to get a - * read-only copy of a DEX file that could be in a number of different states. - * - * If "tempFileName" is NULL, a default value is used. The temp file is - * deleted after the map succeeds. - * - * If "quiet" is set, don't report common errors. - * - * Returns 0 (kUTFRSuccess) on success. - */ -UnzipToFileResult dexOpenAndMap(const char* fileName, const char* tempFileName, - MemMapping* pMap, bool quiet); - -/* - * Utility function to open a Zip archive, find "classes.dex", and extract - * it to a file. - */ -UnzipToFileResult dexUnzipToFile(const char* zipFileName, - const char* outFileName, bool quiet); - -#endif // LIBDEX_CMDUTILS_H_ diff --git a/libdex/DexCatch.cpp b/libdex/DexCatch.cpp deleted file mode 100644 index ed97e87d9..000000000 --- a/libdex/DexCatch.cpp +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * Functions for dealing with try-catch info. - */ - -#include "DexCatch.h" - -/* Get the first handler offset for the given DexCode. - * It's not 0 because the handlers list is prefixed with its size - * (in entries) as a uleb128. */ -u4 dexGetFirstHandlerOffset(const DexCode* pCode) { - if (pCode->triesSize == 0) { - return 0; - } - - const u1* baseData = dexGetCatchHandlerData(pCode); - const u1* data = baseData; - - readUnsignedLeb128(&data); - - return data - baseData; -} - -/* Get count of handler lists for the given DexCode. */ -u4 dexGetHandlersSize(const DexCode* pCode) { - if (pCode->triesSize == 0) { - return 0; - } - - const u1* data = dexGetCatchHandlerData(pCode); - - return readUnsignedLeb128(&data); -} - -/* Helper for dexFindCatchHandlerOffset(), which does an actual search - * in the tries table. Returns -1 if there is no applicable handler. */ -int dexFindCatchHandlerOffset0(u2 triesSize, const DexTry* pTries, - u4 address) { - // Note: Signed type is important for max and min. - int min = 0; - int max = triesSize - 1; - - while (max >= min) { - int guess = (min + max) >> 1; - const DexTry* pTry = &pTries[guess]; - u4 start = pTry->startAddr; - - if (address < start) { - max = guess - 1; - continue; - } - - u4 end = start + pTry->insnCount; - - if (address >= end) { - min = guess + 1; - continue; - } - - // We have a winner! - return (int) pTry->handlerOff; - } - - // No match. - return -1; -} - -/* Get the handler offset just past the end of the one just iterated over. - * This ends the iteration if it wasn't already. */ -u4 dexCatchIteratorGetEndOffset(DexCatchIterator* pIterator, - const DexCode* pCode) { - while (dexCatchIteratorNext(pIterator) != NULL) /* empty */ ; - - return (u4) (pIterator->pEncodedData - dexGetCatchHandlerData(pCode)); -} diff --git a/libdex/DexCatch.h b/libdex/DexCatch.h deleted file mode 100644 index cfea2d900..000000000 --- a/libdex/DexCatch.h +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * Functions for dealing with try-catch info. - */ - -#ifndef LIBDEX_DEXCATCH_H_ -#define LIBDEX_DEXCATCH_H_ - -#include "DexFile.h" -#include "Leb128.h" - -/* - * Catch handler entry, used while iterating over catch_handler_items. - */ -struct DexCatchHandler { - u4 typeIdx; /* type index of the caught exception type */ - u4 address; /* handler address */ -}; - -/* Get the first handler offset for the given DexCode. - * It's not 0 because the handlers list is prefixed with its size - * (in entries) as a uleb128. */ -u4 dexGetFirstHandlerOffset(const DexCode* pCode); - -/* Get count of handler lists for the given DexCode. */ -u4 dexGetHandlersSize(const DexCode* pCode); - -/* - * Iterator over catch handler data. This structure should be treated as - * opaque. - */ -struct DexCatchIterator { - const u1* pEncodedData; - bool catchesAll; - u4 countRemaining; - DexCatchHandler handler; -}; - -/* Initialize a DexCatchIterator to emptiness. This mostly exists to - * squelch innocuous warnings. */ -DEX_INLINE void dexCatchIteratorClear(DexCatchIterator* pIterator) { - pIterator->pEncodedData = NULL; - pIterator->catchesAll = false; - pIterator->countRemaining = 0; - pIterator->handler.typeIdx = 0; - pIterator->handler.address = 0; -} - -/* Initialize a DexCatchIterator with a direct pointer to encoded handlers. */ -DEX_INLINE void dexCatchIteratorInitToPointer(DexCatchIterator* pIterator, - const u1* pEncodedData) -{ - s4 count = readSignedLeb128(&pEncodedData); - - if (count <= 0) { - pIterator->catchesAll = true; - count = -count; - } else { - pIterator->catchesAll = false; - } - - pIterator->pEncodedData = pEncodedData; - pIterator->countRemaining = count; -} - -/* Initialize a DexCatchIterator to a particular handler offset. */ -DEX_INLINE void dexCatchIteratorInit(DexCatchIterator* pIterator, - const DexCode* pCode, u4 offset) -{ - dexCatchIteratorInitToPointer(pIterator, - dexGetCatchHandlerData(pCode) + offset); -} - -/* Get the next item from a DexCatchIterator. Returns NULL if at end. */ -DEX_INLINE DexCatchHandler* dexCatchIteratorNext(DexCatchIterator* pIterator) { - if (pIterator->countRemaining == 0) { - if (! pIterator->catchesAll) { - return NULL; - } - - pIterator->catchesAll = false; - pIterator->handler.typeIdx = kDexNoIndex; - } else { - u4 typeIdx = readUnsignedLeb128(&pIterator->pEncodedData); - pIterator->handler.typeIdx = typeIdx; - pIterator->countRemaining--; - } - - pIterator->handler.address = readUnsignedLeb128(&pIterator->pEncodedData); - return &pIterator->handler; -} - -/* Get the handler offset just past the end of the one just iterated over. - * This ends the iteration if it wasn't already. */ -u4 dexCatchIteratorGetEndOffset(DexCatchIterator* pIterator, - const DexCode* pCode); - -/* Helper for dexFindCatchHandler(). Do not call directly. */ -int dexFindCatchHandlerOffset0(u2 triesSize, const DexTry* pTries, - u4 address); - -/* Find the handler associated with a given address, if any. - * Initializes the given iterator and returns true if a match is - * found. Returns false if there is no applicable handler. */ -DEX_INLINE bool dexFindCatchHandler(DexCatchIterator *pIterator, - const DexCode* pCode, u4 address) { - u2 triesSize = pCode->triesSize; - int offset = -1; - - // Short-circuit the overwhelmingly common cases. - switch (triesSize) { - case 0: { - break; - } - case 1: { - const DexTry* tries = dexGetTries(pCode); - u4 start = tries[0].startAddr; - - if (address < start) { - break; - } - - u4 end = start + tries[0].insnCount; - - if (address >= end) { - break; - } - - offset = tries[0].handlerOff; - break; - } - default: { - offset = dexFindCatchHandlerOffset0(triesSize, dexGetTries(pCode), - address); - } - } - - if (offset < 0) { - dexCatchIteratorClear(pIterator); // This squelches warnings. - return false; - } else { - dexCatchIteratorInit(pIterator, pCode, offset); - return true; - } -} - -#endif // LIBDEX_DEXCATCH_H_ diff --git a/libdex/DexClass.cpp b/libdex/DexClass.cpp deleted file mode 100644 index a33906c94..000000000 --- a/libdex/DexClass.cpp +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * Functions to deal with class definition structures in DEX files - */ - -#include <stdlib.h> -#include <string.h> -#include "DexClass.h" -#include "Leb128.h" - -/* Helper for verification which reads and verifies a given number - * of uleb128 values. */ -static bool verifyUlebs(const u1* pData, const u1* pLimit, u4 count) { - bool okay = true; - - while (okay && (count-- != 0)) { - readAndVerifyUnsignedLeb128(&pData, pLimit, &okay); - } - - return okay; -} - -/* Read and verify the header of a class_data_item. This updates the - * given data pointer to point past the end of the read data and - * returns an "okay" flag (that is, false == failure). */ -bool dexReadAndVerifyClassDataHeader(const u1** pData, const u1* pLimit, - DexClassDataHeader *pHeader) { - if (! verifyUlebs(*pData, pLimit, 4)) { - return false; - } - - dexReadClassDataHeader(pData, pHeader); - return true; -} - -/* Read and verify an encoded_field. This updates the - * given data pointer to point past the end of the read data and - * returns an "okay" flag (that is, false == failure). - * - * The lastIndex value should be set to 0 before the first field in - * a list is read. It is updated as fields are read and used in the - * decode process. - * - * The verification done by this function is of the raw data format - * only; it does not verify that access flags or indices - * are valid. */ -bool dexReadAndVerifyClassDataField(const u1** pData, const u1* pLimit, - DexField* pField, u4* lastIndex) { - if (! verifyUlebs(*pData, pLimit, 2)) { - return false; - } - - dexReadClassDataField(pData, pField, lastIndex); - return true; -} - -/* Read and verify an encoded_method. This updates the - * given data pointer to point past the end of the read data and - * returns an "okay" flag (that is, false == failure). - * - * The lastIndex value should be set to 0 before the first method in - * a list is read. It is updated as fields are read and used in the - * decode process. - * - * The verification done by this function is of the raw data format - * only; it does not verify that access flags, indices, or offsets - * are valid. */ -bool dexReadAndVerifyClassDataMethod(const u1** pData, const u1* pLimit, - DexMethod* pMethod, u4* lastIndex) { - if (! verifyUlebs(*pData, pLimit, 3)) { - return false; - } - - dexReadClassDataMethod(pData, pMethod, lastIndex); - return true; -} - -/* Read, verify, and return an entire class_data_item. This updates - * the given data pointer to point past the end of the read data. This - * function allocates a single chunk of memory for the result, which - * must subsequently be free()d. This function returns NULL if there - * was trouble parsing the data. If this function is passed NULL, it - * returns an initialized empty DexClassData structure. - * - * The verification done by this function is of the raw data format - * only; it does not verify that access flags, indices, or offsets - * are valid. */ -DexClassData* dexReadAndVerifyClassData(const u1** pData, const u1* pLimit) { - DexClassDataHeader header; - u4 lastIndex; - - if (*pData == NULL) { - DexClassData* result = (DexClassData*) malloc(sizeof(DexClassData)); - memset(result, 0, sizeof(*result)); - return result; - } - - if (! dexReadAndVerifyClassDataHeader(pData, pLimit, &header)) { - return NULL; - } - - size_t resultSize = sizeof(DexClassData) + - (header.staticFieldsSize * sizeof(DexField)) + - (header.instanceFieldsSize * sizeof(DexField)) + - (header.directMethodsSize * sizeof(DexMethod)) + - (header.virtualMethodsSize * sizeof(DexMethod)); - - DexClassData* result = (DexClassData*) malloc(resultSize); - u1* ptr = ((u1*) result) + sizeof(DexClassData); - bool okay = true; - u4 i; - - if (result == NULL) { - return NULL; - } - - result->header = header; - - if (header.staticFieldsSize != 0) { - result->staticFields = (DexField*) ptr; - ptr += header.staticFieldsSize * sizeof(DexField); - } else { - result->staticFields = NULL; - } - - if (header.instanceFieldsSize != 0) { - result->instanceFields = (DexField*) ptr; - ptr += header.instanceFieldsSize * sizeof(DexField); - } else { - result->instanceFields = NULL; - } - - if (header.directMethodsSize != 0) { - result->directMethods = (DexMethod*) ptr; - ptr += header.directMethodsSize * sizeof(DexMethod); - } else { - result->directMethods = NULL; - } - - if (header.virtualMethodsSize != 0) { - result->virtualMethods = (DexMethod*) ptr; - } else { - result->virtualMethods = NULL; - } - - lastIndex = 0; - for (i = 0; okay && (i < header.staticFieldsSize); i++) { - okay = dexReadAndVerifyClassDataField(pData, pLimit, - &result->staticFields[i], &lastIndex); - } - - lastIndex = 0; - for (i = 0; okay && (i < header.instanceFieldsSize); i++) { - okay = dexReadAndVerifyClassDataField(pData, pLimit, - &result->instanceFields[i], &lastIndex); - } - - lastIndex = 0; - for (i = 0; okay && (i < header.directMethodsSize); i++) { - okay = dexReadAndVerifyClassDataMethod(pData, pLimit, - &result->directMethods[i], &lastIndex); - } - - lastIndex = 0; - for (i = 0; okay && (i < header.virtualMethodsSize); i++) { - okay = dexReadAndVerifyClassDataMethod(pData, pLimit, - &result->virtualMethods[i], &lastIndex); - } - - if (! okay) { - free(result); - return NULL; - } - - return result; -} diff --git a/libdex/DexClass.h b/libdex/DexClass.h deleted file mode 100644 index 11b3b0eee..000000000 --- a/libdex/DexClass.h +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * Functions to deal with class definition structures in DEX files - */ - -#ifndef LIBDEX_DEXCLASS_H_ -#define LIBDEX_DEXCLASS_H_ - -#include "DexFile.h" -#include "Leb128.h" - -/* expanded form of a class_data_item header */ -struct DexClassDataHeader { - u4 staticFieldsSize; - u4 instanceFieldsSize; - u4 directMethodsSize; - u4 virtualMethodsSize; -}; - -/* expanded form of encoded_field */ -struct DexField { - u4 fieldIdx; /* index to a field_id_item */ - u4 accessFlags; -}; - -/* expanded form of encoded_method */ -struct DexMethod { - u4 methodIdx; /* index to a method_id_item */ - u4 accessFlags; - u4 codeOff; /* file offset to a code_item */ -}; - -/* expanded form of class_data_item. Note: If a particular item is - * absent (e.g., no static fields), then the corresponding pointer - * is set to NULL. */ -struct DexClassData { - DexClassDataHeader header; - DexField* staticFields; - DexField* instanceFields; - DexMethod* directMethods; - DexMethod* virtualMethods; -}; - -/* Read and verify the header of a class_data_item. This updates the - * given data pointer to point past the end of the read data and - * returns an "okay" flag (that is, false == failure). */ -bool dexReadAndVerifyClassDataHeader(const u1** pData, const u1* pLimit, - DexClassDataHeader *pHeader); - -/* Read and verify an encoded_field. This updates the - * given data pointer to point past the end of the read data and - * returns an "okay" flag (that is, false == failure). - * - * The lastIndex value should be set to 0 before the first field in - * a list is read. It is updated as fields are read and used in the - * decode process. - * - * The verification done by this function is of the raw data format - * only; it does not verify that access flags or indices - * are valid. */ -bool dexReadAndVerifyClassDataField(const u1** pData, const u1* pLimit, - DexField* pField, u4* lastIndex); - -/* Read and verify an encoded_method. This updates the - * given data pointer to point past the end of the read data and - * returns an "okay" flag (that is, false == failure). - * - * The lastIndex value should be set to 0 before the first method in - * a list is read. It is updated as fields are read and used in the - * decode process. - * - * The verification done by this function is of the raw data format - * only; it does not verify that access flags, indices, or offsets - * are valid. */ -bool dexReadAndVerifyClassDataMethod(const u1** pData, const u1* pLimit, - DexMethod* pMethod, u4* lastIndex); - -/* Read, verify, and return an entire class_data_item. This updates - * the given data pointer to point past the end of the read data. This - * function allocates a single chunk of memory for the result, which - * must subsequently be free()d. This function returns NULL if there - * was trouble parsing the data. If this function is passed NULL, it - * returns an initialized empty DexClassData structure. - * - * The verification done by this function is of the raw data format - * only; it does not verify that access flags, indices, or offsets - * are valid. */ -DexClassData* dexReadAndVerifyClassData(const u1** pData, const u1* pLimit); - -/* - * Get the DexCode for a DexMethod. Returns NULL if the class is native - * or abstract. - */ -DEX_INLINE const DexCode* dexGetCode(const DexFile* pDexFile, - const DexMethod* pDexMethod) -{ - if (pDexMethod->codeOff == 0) - return NULL; - return (const DexCode*) (pDexFile->baseAddr + pDexMethod->codeOff); -} - - -/* Read the header of a class_data_item without verification. This - * updates the given data pointer to point past the end of the read - * data. */ -DEX_INLINE void dexReadClassDataHeader(const u1** pData, - DexClassDataHeader *pHeader) { - pHeader->staticFieldsSize = readUnsignedLeb128(pData); - pHeader->instanceFieldsSize = readUnsignedLeb128(pData); - pHeader->directMethodsSize = readUnsignedLeb128(pData); - pHeader->virtualMethodsSize = readUnsignedLeb128(pData); -} - -/* Read an encoded_field without verification. This updates the - * given data pointer to point past the end of the read data. - * - * The lastIndex value should be set to 0 before the first field in - * a list is read. It is updated as fields are read and used in the - * decode process. - */ -DEX_INLINE void dexReadClassDataField(const u1** pData, DexField* pField, - u4* lastIndex) { - u4 index = *lastIndex + readUnsignedLeb128(pData); - - pField->accessFlags = readUnsignedLeb128(pData); - pField->fieldIdx = index; - *lastIndex = index; -} - -/* Read an encoded_method without verification. This updates the - * given data pointer to point past the end of the read data. - * - * The lastIndex value should be set to 0 before the first method in - * a list is read. It is updated as fields are read and used in the - * decode process. - */ -DEX_INLINE void dexReadClassDataMethod(const u1** pData, DexMethod* pMethod, - u4* lastIndex) { - u4 index = *lastIndex + readUnsignedLeb128(pData); - - pMethod->accessFlags = readUnsignedLeb128(pData); - pMethod->codeOff = readUnsignedLeb128(pData); - pMethod->methodIdx = index; - *lastIndex = index; -} - -#endif // LIBDEX_DEXCLASS_H_ diff --git a/libdex/DexDataMap.cpp b/libdex/DexDataMap.cpp deleted file mode 100644 index 18e4a4519..000000000 --- a/libdex/DexDataMap.cpp +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * Verification-time map of data section items - */ - -#include "DexDataMap.h" -#include <stdlib.h> - -/* - * Allocate and initialize a DexDataMap. Returns NULL on failure. - */ -DexDataMap* dexDataMapAlloc(u4 maxCount) { - /* - * Allocate a single chunk for the DexDataMap itself as well as the - * two arrays. - */ - size_t size = 0; - DexDataMap* map = NULL; - - const u4 sizeOfItems = (u4) (sizeof(u4) + sizeof(u2)); - if (__builtin_mul_overflow(maxCount, sizeOfItems, &size) || - __builtin_add_overflow(size, sizeof(DexDataMap), &size)) { - return NULL; - } - - map = (DexDataMap*) malloc(size); - - if (map == NULL) { - return NULL; - } - - map->count = 0; - map->max = maxCount; - map->offsets = (u4*) (map + 1); - map->types = (u2*) (map->offsets + maxCount); - - return map; -} - -/* - * Free a DexDataMap. - */ -void dexDataMapFree(DexDataMap* map) { - /* - * Since everything got allocated together, everything can be freed - * in one fell swoop. Also, free(NULL) is a nop (per spec), so we - * don't have to worry about an explicit test for that. - */ - free(map); -} - -/* - * Add a new element to the map. The offset must be greater than the - * all previously added offsets. - */ -void dexDataMapAdd(DexDataMap* map, u4 offset, u2 type) { - assert(map != NULL); - assert(map->count < map->max); - - if ((map->count != 0) && - (map->offsets[map->count - 1] >= offset)) { - ALOGE("Out-of-order data map offset: %#x then %#x", - map->offsets[map->count - 1], offset); - return; - } - - map->offsets[map->count] = offset; - map->types[map->count] = type; - map->count++; -} - -/* - * Get the type associated with the given offset. This returns -1 if - * there is no entry for the given offset. - */ -int dexDataMapGet(DexDataMap* map, u4 offset) { - assert(map != NULL); - - // Note: Signed type is important for max and min. - int min = 0; - int max = map->count - 1; - u4* offsets = map->offsets; - - while (max >= min) { - int guessIdx = (min + max) >> 1; - u4 guess = offsets[guessIdx]; - - if (offset < guess) { - max = guessIdx - 1; - } else if (offset > guess) { - min = guessIdx + 1; - } else { - // We have a winner! - return map->types[guessIdx]; - } - } - - // No match. - return -1; -} - -/* - * Verify that there is an entry in the map, mapping the given offset to - * the given type. This will return true if such an entry exists and - * return false as well as log an error if not. - */ -bool dexDataMapVerify(DexDataMap* map, u4 offset, u2 type) { - int found = dexDataMapGet(map, offset); - - if (found == type) { - return true; - } - - if (found < 0) { - ALOGE("No data map entry found @ %#x; expected %x", - offset, type); - } else { - ALOGE("Unexpected data map entry @ %#x: expected %x, found %x", - offset, type, found); - } - - return false; -} diff --git a/libdex/DexDataMap.h b/libdex/DexDataMap.h deleted file mode 100644 index 7e43dc934..000000000 --- a/libdex/DexDataMap.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * Verification-time map of data section items - */ - -#ifndef LIBDEX_DEXDATAMAP_H_ -#define LIBDEX_DEXDATAMAP_H_ - -#include "DexFile.h" - -struct DexDataMap { - u4 count; /* number of items currently in the map */ - u4 max; /* maximum number of items that may be held */ - u4* offsets; /* array of item offsets */ - u2* types; /* corresponding array of item types */ -}; - -/* - * Allocate and initialize a DexDataMap. Returns NULL on failure. - */ -DexDataMap* dexDataMapAlloc(u4 maxCount); - -/* - * Free a DexDataMap. - */ -void dexDataMapFree(DexDataMap* map); - -/* - * Add a new element to the map. The offset must be greater than the - * all previously added offsets. - */ -void dexDataMapAdd(DexDataMap* map, u4 offset, u2 type); - -/* - * Get the type associated with the given offset. This returns -1 if - * there is no entry for the given offset. - */ -int dexDataMapGet(DexDataMap* map, u4 offset); - -/* - * Verify that there is an entry in the map, mapping the given offset to - * the given type. This will return true if such an entry exists and - * return false as well as log an error if not. - */ -bool dexDataMapVerify(DexDataMap* map, u4 offset, u2 type); - -/* - * Like dexDataMapVerify(), but also accept a 0 offset as valid. - */ -DEX_INLINE bool dexDataMapVerify0Ok(DexDataMap* map, u4 offset, u2 type) { - if (offset == 0) { - return true; - } - - return dexDataMapVerify(map, offset, type); -} - -#endif // LIBDEX_DEXDATAMAP_H_ diff --git a/libdex/DexDebugInfo.cpp b/libdex/DexDebugInfo.cpp deleted file mode 100644 index 5f9ffbe0f..000000000 --- a/libdex/DexDebugInfo.cpp +++ /dev/null @@ -1,281 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * Handling of method debug info in a .dex file. - */ - -#include "DexDebugInfo.h" -#include "DexProto.h" -#include "Leb128.h" - -#include <stdlib.h> -#include <string.h> - -/* - * Reads a string index as encoded for the debug info format, - * returning a string pointer or NULL as appropriate. - */ -static const char* readStringIdx(const DexFile* pDexFile, - const u1** pStream) { - u4 stringIdx = readUnsignedLeb128(pStream); - - // Remember, encoded string indicies have 1 added to them. - if (stringIdx == 0) { - return NULL; - } else { - return dexStringById(pDexFile, stringIdx - 1); - } -} - -/* - * Reads a type index as encoded for the debug info format, returning - * a string pointer for its descriptor or NULL as appropriate. - */ -static const char* readTypeIdx(const DexFile* pDexFile, - const u1** pStream) { - u4 typeIdx = readUnsignedLeb128(pStream); - - // Remember, encoded type indicies have 1 added to them. - if (typeIdx == 0) { - return NULL; - } else { - return dexStringByTypeIdx(pDexFile, typeIdx - 1); - } -} - -struct LocalInfo { - const char *name; - const char *descriptor; - const char *signature; - u2 startAddress; - bool live; -}; - -static void emitLocalCbIfLive(void *cnxt, int reg, u4 endAddress, - LocalInfo *localInReg, DexDebugNewLocalCb localCb) -{ - if (localCb != NULL && localInReg[reg].live) { - localCb(cnxt, reg, localInReg[reg].startAddress, endAddress, - localInReg[reg].name, - localInReg[reg].descriptor, - localInReg[reg].signature == NULL - ? "" : localInReg[reg].signature ); - } -} - -static void invalidStream(const char* classDescriptor, const DexProto* proto) { - IF_ALOGE() { - char* methodDescriptor = dexProtoCopyMethodDescriptor(proto); - ALOGE("Invalid debug info stream. class %s; proto %s", - classDescriptor, methodDescriptor); - free(methodDescriptor); - } -} - -static void dexDecodeDebugInfo0( - const DexFile* pDexFile, - const DexCode* pCode, - const char* classDescriptor, - u4 protoIdx, - u4 accessFlags, - DexDebugNewPositionCb posCb, DexDebugNewLocalCb localCb, - void* cnxt, - const u1* stream, - LocalInfo* localInReg) -{ - DexProto proto = { pDexFile, protoIdx }; - u4 line = readUnsignedLeb128(&stream); - u4 parametersSize = readUnsignedLeb128(&stream); - u2 argReg = pCode->registersSize - pCode->insSize; - u4 address = 0; - - if ((accessFlags & ACC_STATIC) == 0) { - /* - * The code is an instance method, which means that there is - * an initial this parameter. Also, the proto list should - * contain exactly one fewer argument word than the insSize - * indicates. - */ - assert(pCode->insSize == (dexProtoComputeArgsSize(&proto) + 1)); - localInReg[argReg].name = "this"; - localInReg[argReg].descriptor = classDescriptor; - localInReg[argReg].startAddress = 0; - localInReg[argReg].live = true; - argReg++; - } else { - assert(pCode->insSize == dexProtoComputeArgsSize(&proto)); - } - - DexParameterIterator iterator; - dexParameterIteratorInit(&iterator, &proto); - - while (parametersSize-- != 0) { - const char* descriptor = dexParameterIteratorNextDescriptor(&iterator); - const char *name; - int reg; - - if ((argReg >= pCode->registersSize) || (descriptor == NULL)) { - invalidStream(classDescriptor, &proto); - return; - } - - name = readStringIdx(pDexFile, &stream); - reg = argReg; - - switch (descriptor[0]) { - case 'D': - case 'J': - argReg += 2; - break; - default: - argReg += 1; - break; - } - - if (name != NULL) { - localInReg[reg].name = name; - localInReg[reg].descriptor = descriptor; - localInReg[reg].signature = NULL; - localInReg[reg].startAddress = address; - localInReg[reg].live = true; - } - } - - for (;;) { - u1 opcode = *stream++; - u2 reg; - - switch (opcode) { - case DBG_END_SEQUENCE: - return; - - case DBG_ADVANCE_PC: - address += readUnsignedLeb128(&stream); - break; - - case DBG_ADVANCE_LINE: - line += readSignedLeb128(&stream); - break; - - case DBG_START_LOCAL: - case DBG_START_LOCAL_EXTENDED: - reg = readUnsignedLeb128(&stream); - if (reg > pCode->registersSize) { - invalidStream(classDescriptor, &proto); - return; - } - - // Emit what was previously there, if anything - emitLocalCbIfLive(cnxt, reg, address, - localInReg, localCb); - - localInReg[reg].name = readStringIdx(pDexFile, &stream); - localInReg[reg].descriptor = readTypeIdx(pDexFile, &stream); - if (opcode == DBG_START_LOCAL_EXTENDED) { - localInReg[reg].signature - = readStringIdx(pDexFile, &stream); - } else { - localInReg[reg].signature = NULL; - } - localInReg[reg].startAddress = address; - localInReg[reg].live = true; - break; - - case DBG_END_LOCAL: - reg = readUnsignedLeb128(&stream); - if (reg > pCode->registersSize) { - invalidStream(classDescriptor, &proto); - return; - } - - emitLocalCbIfLive (cnxt, reg, address, localInReg, localCb); - localInReg[reg].live = false; - break; - - case DBG_RESTART_LOCAL: - reg = readUnsignedLeb128(&stream); - if (reg > pCode->registersSize) { - invalidStream(classDescriptor, &proto); - return; - } - - if (localInReg[reg].name == NULL - || localInReg[reg].descriptor == NULL) { - invalidStream(classDescriptor, &proto); - return; - } - - /* - * If the register is live, the "restart" is superfluous, - * and we don't want to mess with the existing start address. - */ - if (!localInReg[reg].live) { - localInReg[reg].startAddress = address; - localInReg[reg].live = true; - } - break; - - case DBG_SET_PROLOGUE_END: - case DBG_SET_EPILOGUE_BEGIN: - case DBG_SET_FILE: - break; - - default: { - int adjopcode = opcode - DBG_FIRST_SPECIAL; - - address += adjopcode / DBG_LINE_RANGE; - line += DBG_LINE_BASE + (adjopcode % DBG_LINE_RANGE); - - if (posCb != NULL) { - int done; - done = posCb(cnxt, address, line); - - if (done) { - // early exit - return; - } - } - break; - } - } - } -} - -// TODO optimize localCb == NULL case -void dexDecodeDebugInfo( - const DexFile* pDexFile, - const DexCode* pCode, - const char* classDescriptor, - u4 protoIdx, - u4 accessFlags, - DexDebugNewPositionCb posCb, DexDebugNewLocalCb localCb, - void* cnxt) -{ - const u1* stream = dexGetDebugInfoStream(pDexFile, pCode); - LocalInfo localInReg[pCode->registersSize]; - - memset(localInReg, 0, sizeof(LocalInfo) * pCode->registersSize); - - if (stream != NULL) { - dexDecodeDebugInfo0(pDexFile, pCode, classDescriptor, protoIdx, accessFlags, - posCb, localCb, cnxt, stream, localInReg); - } - - for (int reg = 0; reg < pCode->registersSize; reg++) { - emitLocalCbIfLive(cnxt, reg, pCode->insnsSize, localInReg, localCb); - } -} diff --git a/libdex/DexDebugInfo.h b/libdex/DexDebugInfo.h deleted file mode 100644 index bd0954c8c..000000000 --- a/libdex/DexDebugInfo.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * Handling of method debug info in a .dex file. - */ - -#ifndef LIBDEX_DEXDEBUGINFO_H_ -#define LIBDEX_DEXDEBUGINFO_H_ - -#include "DexFile.h" - -/* - * Callback for "new position table entry". - * Returning non-0 causes the decoder to stop early. - */ -typedef int (*DexDebugNewPositionCb)(void *cnxt, u4 address, u4 lineNum); - -/* - * Callback for "new locals table entry". "signature" is an empty string - * if no signature is available for an entry. - */ -typedef void (*DexDebugNewLocalCb)(void *cnxt, u2 reg, u4 startAddress, - u4 endAddress, const char *name, const char *descriptor, - const char *signature); - -/* - * Decode debug info for method. - * - * posCb is called in ascending address order. - * localCb is called in order of ascending end address. - */ -void dexDecodeDebugInfo( - const DexFile* pDexFile, - const DexCode* pDexCode, - const char* classDescriptor, - u4 protoIdx, - u4 accessFlags, - DexDebugNewPositionCb posCb, DexDebugNewLocalCb localCb, - void* cnxt); - -#endif // LIBDEX_DEXDEBUGINFO_H_ diff --git a/libdex/DexFile.cpp b/libdex/DexFile.cpp deleted file mode 100644 index d9acd5188..000000000 --- a/libdex/DexFile.cpp +++ /dev/null @@ -1,539 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * Access the contents of a .dex file. - */ - -#include "DexFile.h" -#include "DexOptData.h" -#include "DexProto.h" -#include "DexCatch.h" -#include "Leb128.h" -#include "sha1.h" -#include "ZipArchive.h" - -#include <zlib.h> - -#include <stdlib.h> -#include <stddef.h> -#include <string.h> -#include <fcntl.h> -#include <errno.h> - - -/* - * Verifying checksums is good, but it slows things down and causes us to - * touch every page. In the "optimized" world, it doesn't work at all, - * because we rewrite the contents. - */ -static const bool kVerifySignature = false; - -/* (documented in header) */ -char dexGetPrimitiveTypeDescriptorChar(PrimitiveType type) { - const char* string = dexGetPrimitiveTypeDescriptor(type); - - return (string == NULL) ? '\0' : string[0]; -} - -/* (documented in header) */ -const char* dexGetPrimitiveTypeDescriptor(PrimitiveType type) { - switch (type) { - case PRIM_VOID: return "V"; - case PRIM_BOOLEAN: return "Z"; - case PRIM_BYTE: return "B"; - case PRIM_SHORT: return "S"; - case PRIM_CHAR: return "C"; - case PRIM_INT: return "I"; - case PRIM_LONG: return "J"; - case PRIM_FLOAT: return "F"; - case PRIM_DOUBLE: return "D"; - default: return NULL; - } - - return NULL; -} - -/* (documented in header) */ -const char* dexGetBoxedTypeDescriptor(PrimitiveType type) { - switch (type) { - case PRIM_VOID: return NULL; - case PRIM_BOOLEAN: return "Ljava/lang/Boolean;"; - case PRIM_BYTE: return "Ljava/lang/Byte;"; - case PRIM_SHORT: return "Ljava/lang/Short;"; - case PRIM_CHAR: return "Ljava/lang/Character;"; - case PRIM_INT: return "Ljava/lang/Integer;"; - case PRIM_LONG: return "Ljava/lang/Long;"; - case PRIM_FLOAT: return "Ljava/lang/Float;"; - case PRIM_DOUBLE: return "Ljava/lang/Double;"; - default: return NULL; - } -} - -/* (documented in header) */ -PrimitiveType dexGetPrimitiveTypeFromDescriptorChar(char descriptorChar) { - switch (descriptorChar) { - case 'V': return PRIM_VOID; - case 'Z': return PRIM_BOOLEAN; - case 'B': return PRIM_BYTE; - case 'S': return PRIM_SHORT; - case 'C': return PRIM_CHAR; - case 'I': return PRIM_INT; - case 'J': return PRIM_LONG; - case 'F': return PRIM_FLOAT; - case 'D': return PRIM_DOUBLE; - default: return PRIM_NOT; - } -} - -/* Return the UTF-8 encoded string with the specified string_id index, - * also filling in the UTF-16 size (number of 16-bit code points).*/ -const char* dexStringAndSizeById(const DexFile* pDexFile, u4 idx, - u4* utf16Size) { - const DexStringId* pStringId = dexGetStringId(pDexFile, idx); - const u1* ptr = pDexFile->baseAddr + pStringId->stringDataOff; - - *utf16Size = readUnsignedLeb128(&ptr); - return (const char*) ptr; -} - -/* - * Format an SHA-1 digest for printing. tmpBuf must be able to hold at - * least kSHA1DigestOutputLen bytes. - */ -const char* dvmSHA1DigestToStr(const unsigned char digest[], char* tmpBuf); - -/* - * Compute a SHA-1 digest on a range of bytes. - */ -static void dexComputeSHA1Digest(const unsigned char* data, size_t length, - unsigned char digest[]) -{ - SHA1_CTX context; - SHA1Init(&context); - SHA1Update(&context, data, length); - SHA1Final(digest, &context); -} - -/* - * Format the SHA-1 digest into the buffer, which must be able to hold at - * least kSHA1DigestOutputLen bytes. Returns a pointer to the buffer, - */ -static const char* dexSHA1DigestToStr(const unsigned char digest[],char* tmpBuf) -{ - static const char hexDigit[] = "0123456789abcdef"; - char* cp; - int i; - - cp = tmpBuf; - for (i = 0; i < kSHA1DigestLen; i++) { - *cp++ = hexDigit[digest[i] >> 4]; - *cp++ = hexDigit[digest[i] & 0x0f]; - } - *cp++ = '\0'; - - assert(cp == tmpBuf + kSHA1DigestOutputLen); - - return tmpBuf; -} - -/* - * Compute a hash code on a UTF-8 string, for use with internal hash tables. - * - * This may or may not be compatible with UTF-8 hash functions used inside - * the Dalvik VM. - * - * The basic "multiply by 31 and add" approach does better on class names - * than most other things tried (e.g. adler32). - */ -static u4 classDescriptorHash(const char* str) -{ - u4 hash = 1; - - while (*str != '\0') - hash = hash * 31 + *str++; - - return hash; -} - -/* - * Add an entry to the class lookup table. We hash the string and probe - * until we find an open slot. - */ -static void classLookupAdd(DexFile* pDexFile, DexClassLookup* pLookup, - int stringOff, int classDefOff, int* pNumProbes) -{ - const char* classDescriptor = - (const char*) (pDexFile->baseAddr + stringOff); - u4 hash = classDescriptorHash(classDescriptor); - int mask = pLookup->numEntries-1; - int idx = hash & mask; - - /* - * Find the first empty slot. We oversized the table, so this is - * guaranteed to finish. - */ - int probes = 0; - while (pLookup->table[idx].classDescriptorOffset != 0) { - idx = (idx + 1) & mask; - probes++; - } - //if (probes > 1) - // ALOGW("classLookupAdd: probes=%d", probes); - - pLookup->table[idx].classDescriptorHash = hash; - pLookup->table[idx].classDescriptorOffset = stringOff; - pLookup->table[idx].classDefOffset = classDefOff; - *pNumProbes = probes; -} - -/* - * Create the class lookup hash table. - * - * Returns newly-allocated storage. - */ -DexClassLookup* dexCreateClassLookup(DexFile* pDexFile) -{ - DexClassLookup* pLookup; - int allocSize; - int i, numEntries; - int numProbes, totalProbes, maxProbes; - - numProbes = totalProbes = maxProbes = 0; - - assert(pDexFile != NULL); - - /* - * Using a factor of 3 results in far less probing than a factor of 2, - * but almost doubles the flash storage requirements for the bootstrap - * DEX files. The overall impact on class loading performance seems - * to be minor. We could probably get some performance improvement by - * using a secondary hash. - */ - numEntries = dexRoundUpPower2(pDexFile->pHeader->classDefsSize * 2); - allocSize = offsetof(DexClassLookup, table) - + numEntries * sizeof(pLookup->table[0]); - - pLookup = (DexClassLookup*) calloc(1, allocSize); - if (pLookup == NULL) - return NULL; - pLookup->size = allocSize; - pLookup->numEntries = numEntries; - - for (i = 0; i < (int)pDexFile->pHeader->classDefsSize; i++) { - const DexClassDef* pClassDef; - const char* pString; - - pClassDef = dexGetClassDef(pDexFile, i); - pString = dexStringByTypeIdx(pDexFile, pClassDef->classIdx); - - classLookupAdd(pDexFile, pLookup, - (u1*)pString - pDexFile->baseAddr, - (u1*)pClassDef - pDexFile->baseAddr, &numProbes); - - if (numProbes > maxProbes) - maxProbes = numProbes; - totalProbes += numProbes; - } - - ALOGV("Class lookup: classes=%d slots=%d (%d%% occ) alloc=%d" - " total=%d max=%d", - pDexFile->pHeader->classDefsSize, numEntries, - (100 * pDexFile->pHeader->classDefsSize) / numEntries, - allocSize, totalProbes, maxProbes); - - return pLookup; -} - - -/* - * Set up the basic raw data pointers of a DexFile. This function isn't - * meant for general use. - */ -void dexFileSetupBasicPointers(DexFile* pDexFile, const u1* data) { - DexHeader *pHeader = (DexHeader*) data; - - pDexFile->baseAddr = data; - pDexFile->pHeader = pHeader; - pDexFile->pStringIds = (const DexStringId*) (data + pHeader->stringIdsOff); - pDexFile->pTypeIds = (const DexTypeId*) (data + pHeader->typeIdsOff); - pDexFile->pFieldIds = (const DexFieldId*) (data + pHeader->fieldIdsOff); - pDexFile->pMethodIds = (const DexMethodId*) (data + pHeader->methodIdsOff); - pDexFile->pProtoIds = (const DexProtoId*) (data + pHeader->protoIdsOff); - pDexFile->pClassDefs = (const DexClassDef*) (data + pHeader->classDefsOff); - pDexFile->pLinkData = (const DexLink*) (data + pHeader->linkOff); -} - -/* - * Parse an optimized or unoptimized .dex file sitting in memory. This is - * called after the byte-ordering and structure alignment has been fixed up. - * - * On success, return a newly-allocated DexFile. - */ -DexFile* dexFileParse(const u1* data, size_t length, int flags) -{ - DexFile* pDexFile = NULL; - const DexHeader* pHeader; - const u1* magic; - int result = -1; - - if (length < sizeof(DexHeader)) { - ALOGE("too short to be a valid .dex"); - goto bail; /* bad file format */ - } - - pDexFile = (DexFile*) malloc(sizeof(DexFile)); - if (pDexFile == NULL) - goto bail; /* alloc failure */ - memset(pDexFile, 0, sizeof(DexFile)); - - /* - * Peel off the optimized header. - */ - if (memcmp(data, DEX_OPT_MAGIC, 4) == 0) { - magic = data; - if (memcmp(magic+4, DEX_OPT_MAGIC_VERS, 4) != 0) { - ALOGE("bad opt version (0x%02x %02x %02x %02x)", - magic[4], magic[5], magic[6], magic[7]); - goto bail; - } - - pDexFile->pOptHeader = (const DexOptHeader*) data; - ALOGV("Good opt header, DEX offset is %d, flags=0x%02x", - pDexFile->pOptHeader->dexOffset, pDexFile->pOptHeader->flags); - - /* parse the optimized dex file tables */ - if (!dexParseOptData(data, length, pDexFile)) - goto bail; - - /* ignore the opt header and appended data from here on out */ - data += pDexFile->pOptHeader->dexOffset; - length -= pDexFile->pOptHeader->dexOffset; - if (pDexFile->pOptHeader->dexLength > length) { - ALOGE("File truncated? stored len=%d, rem len=%d", - pDexFile->pOptHeader->dexLength, (int) length); - goto bail; - } - length = pDexFile->pOptHeader->dexLength; - } - - dexFileSetupBasicPointers(pDexFile, data); - pHeader = pDexFile->pHeader; - - if (!dexHasValidMagic(pHeader)) { - goto bail; - } - - /* - * Verify the checksum(s). This is reasonably quick, but does require - * touching every byte in the DEX file. The base checksum changes after - * byte-swapping and DEX optimization. - */ - if (flags & kDexParseVerifyChecksum) { - u4 adler = dexComputeChecksum(pHeader); - if (adler != pHeader->checksum) { - ALOGE("ERROR: bad checksum (%08x vs %08x)", - adler, pHeader->checksum); - if (!(flags & kDexParseContinueOnError)) - goto bail; - } else { - ALOGV("+++ adler32 checksum (%08x) verified", adler); - } - - const DexOptHeader* pOptHeader = pDexFile->pOptHeader; - if (pOptHeader != NULL) { - adler = dexComputeOptChecksum(pOptHeader); - if (adler != pOptHeader->checksum) { - ALOGE("ERROR: bad opt checksum (%08x vs %08x)", - adler, pOptHeader->checksum); - if (!(flags & kDexParseContinueOnError)) - goto bail; - } else { - ALOGV("+++ adler32 opt checksum (%08x) verified", adler); - } - } - } - - /* - * Verify the SHA-1 digest. (Normally we don't want to do this -- - * the digest is used to uniquely identify the original DEX file, and - * can't be computed for verification after the DEX is byte-swapped - * and optimized.) - */ - if (kVerifySignature) { - unsigned char sha1Digest[kSHA1DigestLen]; - const int nonSum = sizeof(pHeader->magic) + sizeof(pHeader->checksum) + - kSHA1DigestLen; - - dexComputeSHA1Digest(data + nonSum, length - nonSum, sha1Digest); - if (memcmp(sha1Digest, pHeader->signature, kSHA1DigestLen) != 0) { - char tmpBuf1[kSHA1DigestOutputLen]; - char tmpBuf2[kSHA1DigestOutputLen]; - ALOGE("ERROR: bad SHA1 digest (%s vs %s)", - dexSHA1DigestToStr(sha1Digest, tmpBuf1), - dexSHA1DigestToStr(pHeader->signature, tmpBuf2)); - if (!(flags & kDexParseContinueOnError)) - goto bail; - } else { - ALOGV("+++ sha1 digest verified"); - } - } - - if (pHeader->fileSize != length) { - ALOGE("ERROR: stored file size (%d) != expected (%d)", - (int) pHeader->fileSize, (int) length); - if (!(flags & kDexParseContinueOnError)) - goto bail; - } - - if (pHeader->classDefsSize == 0) { - ALOGE("ERROR: DEX file has no classes in it, failing"); - goto bail; - } - - /* - * Success! - */ - result = 0; - -bail: - if (result != 0 && pDexFile != NULL) { - dexFileFree(pDexFile); - pDexFile = NULL; - } - return pDexFile; -} - -/* - * Free up the DexFile and any associated data structures. - * - * Note we may be called with a partially-initialized DexFile. - */ -void dexFileFree(DexFile* pDexFile) -{ - if (pDexFile == NULL) - return; - - free(pDexFile); -} - -/* - * Look up a class definition entry by descriptor. - * - * "descriptor" should look like "Landroid/debug/Stuff;". - */ -const DexClassDef* dexFindClass(const DexFile* pDexFile, - const char* descriptor) -{ - const DexClassLookup* pLookup = pDexFile->pClassLookup; - u4 hash; - int idx, mask; - - hash = classDescriptorHash(descriptor); - mask = pLookup->numEntries - 1; - idx = hash & mask; - - /* - * Search until we find a matching entry or an empty slot. - */ - while (true) { - int offset; - - offset = pLookup->table[idx].classDescriptorOffset; - if (offset == 0) - return NULL; - - if (pLookup->table[idx].classDescriptorHash == hash) { - const char* str; - - str = (const char*) (pDexFile->baseAddr + offset); - if (strcmp(str, descriptor) == 0) { - return (const DexClassDef*) - (pDexFile->baseAddr + pLookup->table[idx].classDefOffset); - } - } - - idx = (idx + 1) & mask; - } -} - - -/* - * Compute the DEX file checksum for a memory-mapped DEX file. - */ -u4 dexComputeChecksum(const DexHeader* pHeader) -{ - const u1* start = (const u1*) pHeader; - - uLong adler = adler32(0L, Z_NULL, 0); - const int nonSum = sizeof(pHeader->magic) + sizeof(pHeader->checksum); - - return (u4) adler32(adler, start + nonSum, pHeader->fileSize - nonSum); -} - -/* - * Compute the size, in bytes, of a DexCode. - */ -size_t dexGetDexCodeSize(const DexCode* pCode) -{ - /* - * The catch handler data is the last entry. It has a variable number - * of variable-size pieces, so we need to create an iterator. - */ - u4 handlersSize; - u4 offset; - u4 ui; - - if (pCode->triesSize != 0) { - handlersSize = dexGetHandlersSize(pCode); - offset = dexGetFirstHandlerOffset(pCode); - } else { - handlersSize = 0; - offset = 0; - } - - for (ui = 0; ui < handlersSize; ui++) { - DexCatchIterator iterator; - dexCatchIteratorInit(&iterator, pCode, offset); - offset = dexCatchIteratorGetEndOffset(&iterator, pCode); - } - - const u1* handlerData = dexGetCatchHandlerData(pCode); - - //ALOGD("+++ pCode=%p handlerData=%p last offset=%d", - // pCode, handlerData, offset); - - /* return the size of the catch handler + everything before it */ - return (handlerData - (u1*) pCode) + offset; -} - -/* - * Round up to the next highest power of 2. - * - * Found on http://graphics.stanford.edu/~seander/bithacks.html. - */ -u4 dexRoundUpPower2(u4 val) -{ - val--; - val |= val >> 1; - val |= val >> 2; - val |= val >> 4; - val |= val >> 8; - val |= val >> 16; - val++; - - return val; -} diff --git a/libdex/DexFile.h b/libdex/DexFile.h deleted file mode 100644 index 7fc7d051c..000000000 --- a/libdex/DexFile.h +++ /dev/null @@ -1,1084 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * Access .dex (Dalvik Executable Format) files. The code here assumes that - * the DEX file has been rewritten (byte-swapped, word-aligned) and that - * the contents can be directly accessed as a collection of C arrays. Please - * see docs/dalvik/dex-format.html for a detailed description. - * - * The structure and field names were chosen to match those in the DEX spec. - * - * It's generally assumed that the DEX file will be stored in shared memory, - * obviating the need to copy code and constant pool entries into newly - * allocated storage. Maintaining local pointers to items in the shared area - * is valid and encouraged. - * - * All memory-mapped structures are 32-bit aligned unless otherwise noted. - */ - -#ifndef LIBDEX_DEXFILE_H_ -#define LIBDEX_DEXFILE_H_ - -/* - * Annotation to tell clang that we intend to fall through from one case to - * another in a switch. Sourced from android-base/macros.h. - */ -#define FALLTHROUGH_INTENDED [[clang::fallthrough]] - -#ifndef LOG_TAG -# define LOG_TAG "libdex" -#endif -#include <log/log.h> - -#include <stdbool.h> -#include <stdint.h> -#include <stdio.h> -#include <assert.h> - -/* - * If "very verbose" logging is enabled, make it equivalent to ALOGV. - * Otherwise, make it disappear. - * - * Define this above the #include "Dalvik.h" to enable for only a - * single file. - */ -/* #define VERY_VERBOSE_LOG */ -#if defined(VERY_VERBOSE_LOG) -# define LOGVV ALOGV -# define IF_LOGVV() IF_ALOGV() -#else -# define LOGVV(...) ((void)0) -# define IF_LOGVV() if (false) -#endif - -/* - * These match the definitions in the VM specification. - */ -typedef uint8_t u1; -typedef uint16_t u2; -typedef uint32_t u4; -typedef uint64_t u8; -typedef int8_t s1; -typedef int16_t s2; -typedef int32_t s4; -typedef int64_t s8; - -#include "libdex/SysUtil.h" - -/* - * gcc-style inline management -- ensures we have a copy of all functions - * in the library, so code that links against us will work whether or not - * it was built with optimizations enabled. - */ -#ifndef _DEX_GEN_INLINES /* only defined by DexInlines.c */ -# define DEX_INLINE extern __inline__ -#else -# define DEX_INLINE -#endif - -/* DEX file magic number */ -#define DEX_MAGIC "dex\n" - -/* The version for android N, encoded in 4 bytes of ASCII. This differentiates dex files that may - * use default methods. - */ -#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" - -/* The version for android P, encoded in 4 bytes of ASCII. This differentiates dex files that may - * contain const-method-handle and const-proto. - */ -#define DEX_MAGIC_VERS_39 "039\0" - -/* current version, encoded in 4 bytes of ASCII */ -#define DEX_MAGIC_VERS "036\0" - -/* - * older but still-recognized version (corresponding to Android API - * levels 13 and earlier - */ -#define DEX_MAGIC_VERS_API_13 "035\0" - -/* same, but for optimized DEX header */ -#define DEX_OPT_MAGIC "dey\n" -#define DEX_OPT_MAGIC_VERS "036\0" - -#define DEX_DEP_MAGIC "deps" - -/* - * 160-bit SHA-1 digest. - */ -enum { kSHA1DigestLen = 20, - kSHA1DigestOutputLen = kSHA1DigestLen*2 +1 }; - -/* general constants */ -enum { - kDexEndianConstant = 0x12345678, /* the endianness indicator */ - kDexNoIndex = 0xffffffff, /* not a valid index value */ -}; - -/* - * Enumeration of all the primitive types. - */ -enum PrimitiveType { - PRIM_NOT = 0, /* value is a reference type, not a primitive type */ - PRIM_VOID = 1, - PRIM_BOOLEAN = 2, - PRIM_BYTE = 3, - PRIM_SHORT = 4, - PRIM_CHAR = 5, - PRIM_INT = 6, - PRIM_LONG = 7, - PRIM_FLOAT = 8, - PRIM_DOUBLE = 9, -}; - -/* - * access flags and masks; the "standard" ones are all <= 0x4000 - * - * Note: There are related declarations in vm/oo/Object.h in the ClassFlags - * enum. - */ -enum { - ACC_PUBLIC = 0x00000001, // class, field, method, ic - ACC_PRIVATE = 0x00000002, // field, method, ic - ACC_PROTECTED = 0x00000004, // field, method, ic - ACC_STATIC = 0x00000008, // field, method, ic - ACC_FINAL = 0x00000010, // class, field, method, ic - ACC_SYNCHRONIZED = 0x00000020, // method (only allowed on natives) - ACC_SUPER = 0x00000020, // class (not used in Dalvik) - ACC_VOLATILE = 0x00000040, // field - ACC_BRIDGE = 0x00000040, // method (1.5) - ACC_TRANSIENT = 0x00000080, // field - ACC_VARARGS = 0x00000080, // method (1.5) - ACC_NATIVE = 0x00000100, // method - ACC_INTERFACE = 0x00000200, // class, ic - ACC_ABSTRACT = 0x00000400, // class, method, ic - ACC_STRICT = 0x00000800, // method - ACC_SYNTHETIC = 0x00001000, // field, method, ic - ACC_ANNOTATION = 0x00002000, // class, ic (1.5) - ACC_ENUM = 0x00004000, // class, field, ic (1.5) - ACC_CONSTRUCTOR = 0x00010000, // method (Dalvik only) - ACC_DECLARED_SYNCHRONIZED = - 0x00020000, // method (Dalvik only) - ACC_CLASS_MASK = - (ACC_PUBLIC | ACC_FINAL | ACC_INTERFACE | ACC_ABSTRACT - | ACC_SYNTHETIC | ACC_ANNOTATION | ACC_ENUM), - ACC_INNER_CLASS_MASK = - (ACC_CLASS_MASK | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC), - ACC_FIELD_MASK = - (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC | ACC_FINAL - | ACC_VOLATILE | ACC_TRANSIENT | ACC_SYNTHETIC | ACC_ENUM), - ACC_METHOD_MASK = - (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC | ACC_FINAL - | ACC_SYNCHRONIZED | ACC_BRIDGE | ACC_VARARGS | ACC_NATIVE - | ACC_ABSTRACT | ACC_STRICT | ACC_SYNTHETIC | ACC_CONSTRUCTOR - | ACC_DECLARED_SYNCHRONIZED), -}; - -/* annotation constants */ -enum { - kDexVisibilityBuild = 0x00, /* annotation visibility */ - kDexVisibilityRuntime = 0x01, - kDexVisibilitySystem = 0x02, - - kDexAnnotationByte = 0x00, - kDexAnnotationShort = 0x02, - kDexAnnotationChar = 0x03, - kDexAnnotationInt = 0x04, - kDexAnnotationLong = 0x06, - kDexAnnotationFloat = 0x10, - kDexAnnotationDouble = 0x11, - kDexAnnotationMethodType = 0x15, - kDexAnnotationMethodHandle = 0x16, - kDexAnnotationString = 0x17, - kDexAnnotationType = 0x18, - kDexAnnotationField = 0x19, - kDexAnnotationMethod = 0x1a, - kDexAnnotationEnum = 0x1b, - kDexAnnotationArray = 0x1c, - kDexAnnotationAnnotation = 0x1d, - kDexAnnotationNull = 0x1e, - kDexAnnotationBoolean = 0x1f, - - kDexAnnotationValueTypeMask = 0x1f, /* low 5 bits */ - kDexAnnotationValueArgShift = 5, -}; - -/* map item type codes */ -enum { - kDexTypeHeaderItem = 0x0000, - kDexTypeStringIdItem = 0x0001, - kDexTypeTypeIdItem = 0x0002, - kDexTypeProtoIdItem = 0x0003, - kDexTypeFieldIdItem = 0x0004, - kDexTypeMethodIdItem = 0x0005, - kDexTypeClassDefItem = 0x0006, - kDexTypeCallSiteIdItem = 0x0007, - kDexTypeMethodHandleItem = 0x0008, - kDexTypeMapList = 0x1000, - kDexTypeTypeList = 0x1001, - kDexTypeAnnotationSetRefList = 0x1002, - kDexTypeAnnotationSetItem = 0x1003, - kDexTypeClassDataItem = 0x2000, - kDexTypeCodeItem = 0x2001, - kDexTypeStringDataItem = 0x2002, - kDexTypeDebugInfoItem = 0x2003, - kDexTypeAnnotationItem = 0x2004, - kDexTypeEncodedArrayItem = 0x2005, - kDexTypeAnnotationsDirectoryItem = 0x2006, -}; - -/* auxillary data section chunk codes */ -enum { - kDexChunkClassLookup = 0x434c4b50, /* CLKP */ - kDexChunkRegisterMaps = 0x524d4150, /* RMAP */ - - kDexChunkEnd = 0x41454e44, /* AEND */ -}; - -/* debug info opcodes and constants */ -enum { - DBG_END_SEQUENCE = 0x00, - DBG_ADVANCE_PC = 0x01, - DBG_ADVANCE_LINE = 0x02, - DBG_START_LOCAL = 0x03, - DBG_START_LOCAL_EXTENDED = 0x04, - DBG_END_LOCAL = 0x05, - DBG_RESTART_LOCAL = 0x06, - DBG_SET_PROLOGUE_END = 0x07, - DBG_SET_EPILOGUE_BEGIN = 0x08, - DBG_SET_FILE = 0x09, - DBG_FIRST_SPECIAL = 0x0a, - DBG_LINE_BASE = -4, - DBG_LINE_RANGE = 15, -}; - -/* - * Direct-mapped "header_item" struct. - */ -struct DexHeader { - u1 magic[8]; /* includes version number */ - u4 checksum; /* adler32 checksum */ - u1 signature[kSHA1DigestLen]; /* SHA-1 hash */ - u4 fileSize; /* length of entire file */ - u4 headerSize; /* offset to start of next section */ - u4 endianTag; - u4 linkSize; - u4 linkOff; - u4 mapOff; - u4 stringIdsSize; - u4 stringIdsOff; - u4 typeIdsSize; - u4 typeIdsOff; - u4 protoIdsSize; - u4 protoIdsOff; - u4 fieldIdsSize; - u4 fieldIdsOff; - u4 methodIdsSize; - u4 methodIdsOff; - u4 classDefsSize; - u4 classDefsOff; - u4 dataSize; - u4 dataOff; -}; - -/* - * Direct-mapped "map_item". - */ -struct DexMapItem { - u2 type; /* type code (see kDexType* above) */ - u2 unused; - u4 size; /* count of items of the indicated type */ - u4 offset; /* file offset to the start of data */ -}; - -/* - * Direct-mapped "map_list". - */ -struct DexMapList { - u4 size; /* #of entries in list */ - DexMapItem list[1]; /* entries */ -}; - -/* - * Direct-mapped "string_id_item". - */ -struct DexStringId { - u4 stringDataOff; /* file offset to string_data_item */ -}; - -/* - * Direct-mapped "type_id_item". - */ -struct DexTypeId { - u4 descriptorIdx; /* index into stringIds list for type descriptor */ -}; - -/* - * Direct-mapped "field_id_item". - */ -struct DexFieldId { - u2 classIdx; /* index into typeIds list for defining class */ - u2 typeIdx; /* index into typeIds for field type */ - u4 nameIdx; /* index into stringIds for field name */ -}; - -/* - * Direct-mapped "method_id_item". - */ -struct DexMethodId { - u2 classIdx; /* index into typeIds list for defining class */ - u2 protoIdx; /* index into protoIds for method prototype */ - u4 nameIdx; /* index into stringIds for method name */ -}; - -/* - * Direct-mapped "proto_id_item". - */ -struct DexProtoId { - u4 shortyIdx; /* index into stringIds for shorty descriptor */ - u4 returnTypeIdx; /* index into typeIds list for return type */ - u4 parametersOff; /* file offset to type_list for parameter types */ -}; - -/* - * Direct-mapped "class_def_item". - */ -struct DexClassDef { - u4 classIdx; /* index into typeIds for this class */ - u4 accessFlags; - u4 superclassIdx; /* index into typeIds for superclass */ - u4 interfacesOff; /* file offset to DexTypeList */ - u4 sourceFileIdx; /* index into stringIds for source file name */ - u4 annotationsOff; /* file offset to annotations_directory_item */ - u4 classDataOff; /* file offset to class_data_item */ - u4 staticValuesOff; /* file offset to DexEncodedArray */ -}; - -/* - * Direct-mapped "call_site_id_item" - */ -struct DexCallSiteId { - u4 callSiteOff; /* file offset to DexEncodedArray */ -}; - -/* - * Enumeration of method handle type codes. - */ -enum MethodHandleType { - STATIC_PUT = 0x00, - STATIC_GET = 0x01, - INSTANCE_PUT = 0x02, - INSTANCE_GET = 0x03, - INVOKE_STATIC = 0x04, - INVOKE_INSTANCE = 0x05, - INVOKE_CONSTRUCTOR = 0x06, - INVOKE_DIRECT = 0x07, - INVOKE_INTERFACE = 0x08 -}; - -/* - * 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". - */ -struct DexTypeItem { - u2 typeIdx; /* index into typeIds */ -}; - -/* - * Direct-mapped "type_list". - */ -struct DexTypeList { - u4 size; /* #of entries in list */ - DexTypeItem list[1]; /* entries */ -}; - -/* - * Direct-mapped "code_item". - * - * The "catches" table is used when throwing an exception, - * "debugInfo" is used when displaying an exception stack trace or - * debugging. An offset of zero indicates that there are no entries. - */ -struct DexCode { - u2 registersSize; - u2 insSize; - u2 outsSize; - u2 triesSize; - u4 debugInfoOff; /* file offset to debug info stream */ - u4 insnsSize; /* size of the insns array, in u2 units */ - u2 insns[1]; - /* followed by optional u2 padding */ - /* followed by try_item[triesSize] */ - /* followed by uleb128 handlersSize */ - /* followed by catch_handler_item[handlersSize] */ -}; - -/* - * Direct-mapped "try_item". - */ -struct DexTry { - u4 startAddr; /* start address, in 16-bit code units */ - u2 insnCount; /* instruction count, in 16-bit code units */ - u2 handlerOff; /* offset in encoded handler data to handlers */ -}; - -/* - * Link table. Currently undefined. - */ -struct DexLink { - u1 bleargh; -}; - - -/* - * Direct-mapped "annotations_directory_item". - */ -struct DexAnnotationsDirectoryItem { - u4 classAnnotationsOff; /* offset to DexAnnotationSetItem */ - u4 fieldsSize; /* count of DexFieldAnnotationsItem */ - u4 methodsSize; /* count of DexMethodAnnotationsItem */ - u4 parametersSize; /* count of DexParameterAnnotationsItem */ - /* followed by DexFieldAnnotationsItem[fieldsSize] */ - /* followed by DexMethodAnnotationsItem[methodsSize] */ - /* followed by DexParameterAnnotationsItem[parametersSize] */ -}; - -/* - * Direct-mapped "field_annotations_item". - */ -struct DexFieldAnnotationsItem { - u4 fieldIdx; - u4 annotationsOff; /* offset to DexAnnotationSetItem */ -}; - -/* - * Direct-mapped "method_annotations_item". - */ -struct DexMethodAnnotationsItem { - u4 methodIdx; - u4 annotationsOff; /* offset to DexAnnotationSetItem */ -}; - -/* - * Direct-mapped "parameter_annotations_item". - */ -struct DexParameterAnnotationsItem { - u4 methodIdx; - u4 annotationsOff; /* offset to DexAnotationSetRefList */ -}; - -/* - * Direct-mapped "annotation_set_ref_item". - */ -struct DexAnnotationSetRefItem { - u4 annotationsOff; /* offset to DexAnnotationSetItem */ -}; - -/* - * Direct-mapped "annotation_set_ref_list". - */ -struct DexAnnotationSetRefList { - u4 size; - DexAnnotationSetRefItem list[1]; -}; - -/* - * Direct-mapped "annotation_set_item". - */ -struct DexAnnotationSetItem { - u4 size; - u4 entries[1]; /* offset to DexAnnotationItem */ -}; - -/* - * Direct-mapped "annotation_item". - * - * NOTE: this structure is byte-aligned. - */ -struct DexAnnotationItem { - u1 visibility; - u1 annotation[1]; /* data in encoded_annotation format */ -}; - -/* - * Direct-mapped "encoded_array". - * - * NOTE: this structure is byte-aligned. - */ -struct DexEncodedArray { - u1 array[1]; /* data in encoded_array format */ -}; - -/* - * Lookup table for classes. It provides a mapping from class name to - * class definition. Used by dexFindClass(). - * - * We calculate this at DEX optimization time and embed it in the file so we - * don't need the same hash table in every VM. This is slightly slower than - * a hash table with direct pointers to the items, but because it's shared - * there's less of a penalty for using a fairly sparse table. - */ -struct DexClassLookup { - int size; // total size, including "size" - int numEntries; // size of table[]; always power of 2 - struct { - u4 classDescriptorHash; // class descriptor hash code - int classDescriptorOffset; // in bytes, from start of DEX - int classDefOffset; // in bytes, from start of DEX - } table[1]; -}; - -/* - * Header added by DEX optimization pass. Values are always written in - * local byte and structure padding. The first field (magic + version) - * is guaranteed to be present and directly readable for all expected - * compiler configurations; the rest is version-dependent. - * - * Try to keep this simple and fixed-size. - */ -struct DexOptHeader { - u1 magic[8]; /* includes version number */ - - u4 dexOffset; /* file offset of DEX header */ - u4 dexLength; - u4 depsOffset; /* offset of optimized DEX dependency table */ - u4 depsLength; - u4 optOffset; /* file offset of optimized data tables */ - u4 optLength; - - u4 flags; /* some info flags */ - u4 checksum; /* adler32 checksum covering deps/opt */ - - /* pad for 64-bit alignment if necessary */ -}; - -#define DEX_OPT_FLAG_BIG (1<<1) /* swapped to big-endian */ - -#define DEX_INTERFACE_CACHE_SIZE 128 /* must be power of 2 */ - -/* - * Structure representing a DEX file. - * - * Code should regard DexFile as opaque, using the API calls provided here - * to access specific structures. - */ -struct DexFile { - /* directly-mapped "opt" header */ - const DexOptHeader* pOptHeader; - - /* pointers to directly-mapped structs and arrays in base DEX */ - const DexHeader* pHeader; - const DexStringId* pStringIds; - const DexTypeId* pTypeIds; - const DexFieldId* pFieldIds; - const DexMethodId* pMethodIds; - const DexProtoId* pProtoIds; - const DexClassDef* pClassDefs; - const DexLink* pLinkData; - - /* - * These are mapped out of the "auxillary" section, and may not be - * included in the file. - */ - const DexClassLookup* pClassLookup; - const void* pRegisterMapPool; // RegisterMapClassPool - - /* points to start of DEX file data */ - const u1* baseAddr; - - /* track memory overhead for auxillary structures */ - int overhead; - - /* additional app-specific data structures associated with the DEX */ - //void* auxData; -}; - -/* - * Utility function -- rounds up to the nearest power of 2. - */ -u4 dexRoundUpPower2(u4 val); - -/* - * Parse an optimized or unoptimized .dex file sitting in memory. - * - * On success, return a newly-allocated DexFile. - */ -DexFile* dexFileParse(const u1* data, size_t length, int flags); - -/* bit values for "flags" argument to dexFileParse */ -enum { - kDexParseDefault = 0, - kDexParseVerifyChecksum = 1, - kDexParseContinueOnError = (1 << 1), -}; - -/* - * Fix the byte ordering of all fields in the DEX file, and do - * structural verification. This is only required for code that opens - * "raw" DEX files, such as the DEX optimizer. - * - * Return 0 on success. - */ -int dexSwapAndVerify(u1* addr, int len); - -/* - * Detect the file type of the given memory buffer via magic number. - * Call dexSwapAndVerify() on an unoptimized DEX file, do nothing - * but return successfully on an optimized DEX file, and report an - * error for all other cases. - * - * Return 0 on success. - */ -int dexSwapAndVerifyIfNecessary(u1* addr, size_t len); - -/* - * Check to see if the file magic and format version in the given - * header are recognized as valid. Returns true if they are - * acceptable. - */ -bool dexHasValidMagic(const DexHeader* pHeader); - -/* - * Compute DEX checksum. - */ -u4 dexComputeChecksum(const DexHeader* pHeader); - -/* - * Free a DexFile structure, along with any associated structures. - */ -void dexFileFree(DexFile* pDexFile); - -/* - * Create class lookup table. - */ -DexClassLookup* dexCreateClassLookup(DexFile* pDexFile); - -/* - * Find a class definition by descriptor. - */ -const DexClassDef* dexFindClass(const DexFile* pFile, const char* descriptor); - -/* - * Set up the basic raw data pointers of a DexFile. This function isn't - * meant for general use. - */ -void dexFileSetupBasicPointers(DexFile* pDexFile, const u1* data); - -/* return the DexMapList of the file, if any */ -DEX_INLINE const DexMapList* dexGetMap(const DexFile* pDexFile) { - u4 mapOff = pDexFile->pHeader->mapOff; - - if (mapOff == 0) { - return NULL; - } else { - return (const DexMapList*) (pDexFile->baseAddr + mapOff); - } -} - -/* return the const char* string data referred to by the given string_id */ -DEX_INLINE const char* dexGetStringData(const DexFile* pDexFile, - const DexStringId* pStringId) { - const u1* ptr = pDexFile->baseAddr + pStringId->stringDataOff; - - // Skip the uleb128 length. - while (*(ptr++) > 0x7f) /* empty */ ; - - return (const char*) ptr; -} -/* return the StringId with the specified index */ -DEX_INLINE const DexStringId* dexGetStringId(const DexFile* pDexFile, u4 idx) { - assert(idx < pDexFile->pHeader->stringIdsSize); - return &pDexFile->pStringIds[idx]; -} -/* return the UTF-8 encoded string with the specified string_id index */ -DEX_INLINE const char* dexStringById(const DexFile* pDexFile, u4 idx) { - const DexStringId* pStringId = dexGetStringId(pDexFile, idx); - return dexGetStringData(pDexFile, pStringId); -} - -/* Return the UTF-8 encoded string with the specified string_id index, - * also filling in the UTF-16 size (number of 16-bit code points).*/ -const char* dexStringAndSizeById(const DexFile* pDexFile, u4 idx, - u4* utf16Size); - -/* return the TypeId with the specified index */ -DEX_INLINE const DexTypeId* dexGetTypeId(const DexFile* pDexFile, u4 idx) { - assert(idx < pDexFile->pHeader->typeIdsSize); - return &pDexFile->pTypeIds[idx]; -} - -/* - * Get the descriptor string associated with a given type index. - * The caller should not free() the returned string. - */ -DEX_INLINE const char* dexStringByTypeIdx(const DexFile* pDexFile, u4 idx) { - const DexTypeId* typeId = dexGetTypeId(pDexFile, idx); - return dexStringById(pDexFile, typeId->descriptorIdx); -} - -/* return the MethodId with the specified index */ -DEX_INLINE const DexMethodId* dexGetMethodId(const DexFile* pDexFile, u4 idx) { - assert(idx < pDexFile->pHeader->methodIdsSize); - return &pDexFile->pMethodIds[idx]; -} - -/* return the FieldId with the specified index */ -DEX_INLINE const DexFieldId* dexGetFieldId(const DexFile* pDexFile, u4 idx) { - assert(idx < pDexFile->pHeader->fieldIdsSize); - return &pDexFile->pFieldIds[idx]; -} - -/* return the ProtoId with the specified index */ -DEX_INLINE const DexProtoId* dexGetProtoId(const DexFile* pDexFile, u4 idx) { - assert(idx < pDexFile->pHeader->protoIdsSize); - return &pDexFile->pProtoIds[idx]; -} - -/* - * Get the parameter list from a ProtoId. The returns NULL if the ProtoId - * does not have a parameter list. - */ -DEX_INLINE const DexTypeList* dexGetProtoParameters( - const DexFile *pDexFile, const DexProtoId* pProtoId) { - if (pProtoId->parametersOff == 0) { - return NULL; - } - return (const DexTypeList*) - (pDexFile->baseAddr + pProtoId->parametersOff); -} - -/* return the ClassDef with the specified index */ -DEX_INLINE const DexClassDef* dexGetClassDef(const DexFile* pDexFile, u4 idx) { - assert(idx < pDexFile->pHeader->classDefsSize); - return &pDexFile->pClassDefs[idx]; -} - -/* given a ClassDef pointer, recover its index */ -DEX_INLINE u4 dexGetIndexForClassDef(const DexFile* pDexFile, - const DexClassDef* pClassDef) -{ - assert(pClassDef >= pDexFile->pClassDefs && - pClassDef < pDexFile->pClassDefs + pDexFile->pHeader->classDefsSize); - return pClassDef - pDexFile->pClassDefs; -} - -/* get the interface list for a DexClass */ -DEX_INLINE const DexTypeList* dexGetInterfacesList(const DexFile* pDexFile, - const DexClassDef* pClassDef) -{ - if (pClassDef->interfacesOff == 0) - return NULL; - return (const DexTypeList*) - (pDexFile->baseAddr + pClassDef->interfacesOff); -} -/* return the Nth entry in a DexTypeList. */ -DEX_INLINE const DexTypeItem* dexGetTypeItem(const DexTypeList* pList, - u4 idx) -{ - assert(idx < pList->size); - return &pList->list[idx]; -} -/* return the type_idx for the Nth entry in a TypeList */ -DEX_INLINE u4 dexTypeListGetIdx(const DexTypeList* pList, u4 idx) { - const DexTypeItem* pItem = dexGetTypeItem(pList, idx); - return pItem->typeIdx; -} - -/* get the static values list for a DexClass */ -DEX_INLINE const DexEncodedArray* dexGetStaticValuesList( - const DexFile* pDexFile, const DexClassDef* pClassDef) -{ - if (pClassDef->staticValuesOff == 0) - return NULL; - return (const DexEncodedArray*) - (pDexFile->baseAddr + pClassDef->staticValuesOff); -} - -/* get the annotations directory item for a DexClass */ -DEX_INLINE const DexAnnotationsDirectoryItem* dexGetAnnotationsDirectoryItem( - const DexFile* pDexFile, const DexClassDef* pClassDef) -{ - if (pClassDef->annotationsOff == 0) - return NULL; - return (const DexAnnotationsDirectoryItem*) - (pDexFile->baseAddr + pClassDef->annotationsOff); -} - -/* get the source file string */ -DEX_INLINE const char* dexGetSourceFile( - const DexFile* pDexFile, const DexClassDef* pClassDef) -{ - if (pClassDef->sourceFileIdx == 0xffffffff) - return NULL; - return dexStringById(pDexFile, pClassDef->sourceFileIdx); -} - -/* get the size, in bytes, of a DexCode */ -size_t dexGetDexCodeSize(const DexCode* pCode); - -/* Get the list of "tries" for the given DexCode. */ -DEX_INLINE const DexTry* dexGetTries(const DexCode* pCode) { - const u2* insnsEnd = &pCode->insns[pCode->insnsSize]; - - // Round to four bytes. - if ((((uintptr_t) insnsEnd) & 3) != 0) { - insnsEnd++; - } - - return (const DexTry*) insnsEnd; -} - -/* Get the base of the encoded data for the given DexCode. */ -DEX_INLINE const u1* dexGetCatchHandlerData(const DexCode* pCode) { - const DexTry* pTries = dexGetTries(pCode); - return (const u1*) &pTries[pCode->triesSize]; -} - -/* get a pointer to the start of the debugging data */ -DEX_INLINE const u1* dexGetDebugInfoStream(const DexFile* pDexFile, - const DexCode* pCode) -{ - if (pCode->debugInfoOff == 0) { - return NULL; - } else { - return pDexFile->baseAddr + pCode->debugInfoOff; - } -} - -/* DexClassDef convenience - get class descriptor */ -DEX_INLINE const char* dexGetClassDescriptor(const DexFile* pDexFile, - const DexClassDef* pClassDef) -{ - return dexStringByTypeIdx(pDexFile, pClassDef->classIdx); -} - -/* DexClassDef convenience - get superclass descriptor */ -DEX_INLINE const char* dexGetSuperClassDescriptor(const DexFile* pDexFile, - const DexClassDef* pClassDef) -{ - if (pClassDef->superclassIdx == 0) - return NULL; - return dexStringByTypeIdx(pDexFile, pClassDef->superclassIdx); -} - -/* DexClassDef convenience - get class_data_item pointer */ -DEX_INLINE const u1* dexGetClassData(const DexFile* pDexFile, - const DexClassDef* pClassDef) -{ - if (pClassDef->classDataOff == 0) - return NULL; - return (const u1*) (pDexFile->baseAddr + pClassDef->classDataOff); -} - -/* Get an annotation set at a particular offset. */ -DEX_INLINE const DexAnnotationSetItem* dexGetAnnotationSetItem( - const DexFile* pDexFile, u4 offset) -{ - if (offset == 0) { - return NULL; - } - return (const DexAnnotationSetItem*) (pDexFile->baseAddr + offset); -} -/* get the class' annotation set */ -DEX_INLINE const DexAnnotationSetItem* dexGetClassAnnotationSet( - const DexFile* pDexFile, const DexAnnotationsDirectoryItem* pAnnoDir) -{ - return dexGetAnnotationSetItem(pDexFile, pAnnoDir->classAnnotationsOff); -} - -/* get the class' field annotation list */ -DEX_INLINE const DexFieldAnnotationsItem* dexGetFieldAnnotations( - const DexFile* pDexFile, const DexAnnotationsDirectoryItem* pAnnoDir) -{ - (void) pDexFile; - if (pAnnoDir->fieldsSize == 0) - return NULL; - - // Skip past the header to the start of the field annotations. - return (const DexFieldAnnotationsItem*) &pAnnoDir[1]; -} - -/* get field annotation list size */ -DEX_INLINE int dexGetFieldAnnotationsSize(const DexFile* pDexFile, - const DexAnnotationsDirectoryItem* pAnnoDir) -{ - (void) pDexFile; - return pAnnoDir->fieldsSize; -} - -/* return a pointer to the field's annotation set */ -DEX_INLINE const DexAnnotationSetItem* dexGetFieldAnnotationSetItem( - const DexFile* pDexFile, const DexFieldAnnotationsItem* pItem) -{ - return dexGetAnnotationSetItem(pDexFile, pItem->annotationsOff); -} - -/* get the class' method annotation list */ -DEX_INLINE const DexMethodAnnotationsItem* dexGetMethodAnnotations( - const DexFile* pDexFile, const DexAnnotationsDirectoryItem* pAnnoDir) -{ - (void) pDexFile; - if (pAnnoDir->methodsSize == 0) - return NULL; - - /* - * Skip past the header and field annotations to the start of the - * method annotations. - */ - const u1* addr = (const u1*) &pAnnoDir[1]; - addr += pAnnoDir->fieldsSize * sizeof (DexFieldAnnotationsItem); - return (const DexMethodAnnotationsItem*) addr; -} - -/* get method annotation list size */ -DEX_INLINE int dexGetMethodAnnotationsSize(const DexFile* pDexFile, - const DexAnnotationsDirectoryItem* pAnnoDir) -{ - (void) pDexFile; - return pAnnoDir->methodsSize; -} - -/* return a pointer to the method's annotation set */ -DEX_INLINE const DexAnnotationSetItem* dexGetMethodAnnotationSetItem( - const DexFile* pDexFile, const DexMethodAnnotationsItem* pItem) -{ - return dexGetAnnotationSetItem(pDexFile, pItem->annotationsOff); -} - -/* get the class' parameter annotation list */ -DEX_INLINE const DexParameterAnnotationsItem* dexGetParameterAnnotations( - const DexFile* pDexFile, const DexAnnotationsDirectoryItem* pAnnoDir) -{ - (void) pDexFile; - if (pAnnoDir->parametersSize == 0) - return NULL; - - /* - * Skip past the header, field annotations, and method annotations - * to the start of the parameter annotations. - */ - const u1* addr = (const u1*) &pAnnoDir[1]; - addr += pAnnoDir->fieldsSize * sizeof (DexFieldAnnotationsItem); - addr += pAnnoDir->methodsSize * sizeof (DexMethodAnnotationsItem); - return (const DexParameterAnnotationsItem*) addr; -} - -/* get method annotation list size */ -DEX_INLINE int dexGetParameterAnnotationsSize(const DexFile* pDexFile, - const DexAnnotationsDirectoryItem* pAnnoDir) -{ - (void) pDexFile; - return pAnnoDir->parametersSize; -} - -/* return the parameter annotation ref list */ -DEX_INLINE const DexAnnotationSetRefList* dexGetParameterAnnotationSetRefList( - const DexFile* pDexFile, const DexParameterAnnotationsItem* pItem) -{ - if (pItem->annotationsOff == 0) { - return NULL; - } - return (const DexAnnotationSetRefList*) (pDexFile->baseAddr + pItem->annotationsOff); -} - -/* get method annotation list size */ -DEX_INLINE int dexGetParameterAnnotationSetRefSize(const DexFile* pDexFile, - const DexParameterAnnotationsItem* pItem) -{ - if (pItem->annotationsOff == 0) { - return 0; - } - return dexGetParameterAnnotationSetRefList(pDexFile, pItem)->size; -} - -/* return the Nth entry from an annotation set ref list */ -DEX_INLINE const DexAnnotationSetRefItem* dexGetParameterAnnotationSetRef( - const DexAnnotationSetRefList* pList, u4 idx) -{ - assert(idx < pList->size); - return &pList->list[idx]; -} - -/* given a DexAnnotationSetRefItem, return the DexAnnotationSetItem */ -DEX_INLINE const DexAnnotationSetItem* dexGetSetRefItemItem( - const DexFile* pDexFile, const DexAnnotationSetRefItem* pItem) -{ - return dexGetAnnotationSetItem(pDexFile, pItem->annotationsOff); -} - -/* return the Nth annotation offset from a DexAnnotationSetItem */ -DEX_INLINE u4 dexGetAnnotationOff( - const DexAnnotationSetItem* pAnnoSet, u4 idx) -{ - assert(idx < pAnnoSet->size); - return pAnnoSet->entries[idx]; -} - -/* return the Nth annotation item from a DexAnnotationSetItem */ -DEX_INLINE const DexAnnotationItem* dexGetAnnotationItem( - const DexFile* pDexFile, const DexAnnotationSetItem* pAnnoSet, u4 idx) -{ - u4 offset = dexGetAnnotationOff(pAnnoSet, idx); - if (offset == 0) { - return NULL; - } - return (const DexAnnotationItem*) (pDexFile->baseAddr + offset); -} - -/* - * Get the type descriptor character associated with a given primitive - * type. This returns '\0' if the type is invalid. - */ -char dexGetPrimitiveTypeDescriptorChar(PrimitiveType type); - -/* - * Get the type descriptor string associated with a given primitive - * type. - */ -const char* dexGetPrimitiveTypeDescriptor(PrimitiveType type); - -/* - * Get the boxed type descriptor string associated with a given - * primitive type. This returns NULL for an invalid type, including - * particularly for type "void". In the latter case, even though there - * is a class Void, there's no such thing as a boxed instance of it. - */ -const char* dexGetBoxedTypeDescriptor(PrimitiveType type); - -/* - * Get the primitive type constant from the given descriptor character. - * This returns PRIM_NOT (note: this is a 0) if the character is invalid - * as a primitive type descriptor. - */ -PrimitiveType dexGetPrimitiveTypeFromDescriptorChar(char descriptorChar); - -#endif // LIBDEX_DEXFILE_H_ diff --git a/libdex/DexInlines.cpp b/libdex/DexInlines.cpp deleted file mode 100644 index cbedb6267..000000000 --- a/libdex/DexInlines.cpp +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * Generate non-inline copies of inline functions in header files. - */ - -#define _DEX_GEN_INLINES - -#include "DexFile.h" - -#include "DexCatch.h" -#include "DexClass.h" -#include "DexDataMap.h" -#include "DexUtf.h" -#include "DexOpcodes.h" -#include "DexProto.h" -#include "InstrUtils.h" -#include "Leb128.h" -#include "ZipArchive.h" diff --git a/libdex/DexOpcodes.cpp b/libdex/DexOpcodes.cpp deleted file mode 100644 index d3db79b67..000000000 --- a/libdex/DexOpcodes.cpp +++ /dev/null @@ -1,299 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * Table of Dalvik opcode names. - * - * IMPORTANT NOTE: The contents of this file are mostly generated - * automatically by the opcode-gen tool. Any edits to the generated - * sections will get wiped out the next time the tool is run. - */ - -#include "DexOpcodes.h" -#include <assert.h> - -/* - * Dalvik opcode names. - */ -static const char* gOpNames[kNumPackedOpcodes] = { - // BEGIN(libdex-opcode-names); GENERATED AUTOMATICALLY BY opcode-gen - "nop", - "move", - "move/from16", - "move/16", - "move-wide", - "move-wide/from16", - "move-wide/16", - "move-object", - "move-object/from16", - "move-object/16", - "move-result", - "move-result-wide", - "move-result-object", - "move-exception", - "return-void", - "return", - "return-wide", - "return-object", - "const/4", - "const/16", - "const", - "const/high16", - "const-wide/16", - "const-wide/32", - "const-wide", - "const-wide/high16", - "const-string", - "const-string/jumbo", - "const-class", - "monitor-enter", - "monitor-exit", - "check-cast", - "instance-of", - "array-length", - "new-instance", - "new-array", - "filled-new-array", - "filled-new-array/range", - "fill-array-data", - "throw", - "goto", - "goto/16", - "goto/32", - "packed-switch", - "sparse-switch", - "cmpl-float", - "cmpg-float", - "cmpl-double", - "cmpg-double", - "cmp-long", - "if-eq", - "if-ne", - "if-lt", - "if-ge", - "if-gt", - "if-le", - "if-eqz", - "if-nez", - "if-ltz", - "if-gez", - "if-gtz", - "if-lez", - "unused-3e", - "unused-3f", - "unused-40", - "unused-41", - "unused-42", - "unused-43", - "aget", - "aget-wide", - "aget-object", - "aget-boolean", - "aget-byte", - "aget-char", - "aget-short", - "aput", - "aput-wide", - "aput-object", - "aput-boolean", - "aput-byte", - "aput-char", - "aput-short", - "iget", - "iget-wide", - "iget-object", - "iget-boolean", - "iget-byte", - "iget-char", - "iget-short", - "iput", - "iput-wide", - "iput-object", - "iput-boolean", - "iput-byte", - "iput-char", - "iput-short", - "sget", - "sget-wide", - "sget-object", - "sget-boolean", - "sget-byte", - "sget-char", - "sget-short", - "sput", - "sput-wide", - "sput-object", - "sput-boolean", - "sput-byte", - "sput-char", - "sput-short", - "invoke-virtual", - "invoke-super", - "invoke-direct", - "invoke-static", - "invoke-interface", - "unused-73", - "invoke-virtual/range", - "invoke-super/range", - "invoke-direct/range", - "invoke-static/range", - "invoke-interface/range", - "unused-79", - "unused-7a", - "neg-int", - "not-int", - "neg-long", - "not-long", - "neg-float", - "neg-double", - "int-to-long", - "int-to-float", - "int-to-double", - "long-to-int", - "long-to-float", - "long-to-double", - "float-to-int", - "float-to-long", - "float-to-double", - "double-to-int", - "double-to-long", - "double-to-float", - "int-to-byte", - "int-to-char", - "int-to-short", - "add-int", - "sub-int", - "mul-int", - "div-int", - "rem-int", - "and-int", - "or-int", - "xor-int", - "shl-int", - "shr-int", - "ushr-int", - "add-long", - "sub-long", - "mul-long", - "div-long", - "rem-long", - "and-long", - "or-long", - "xor-long", - "shl-long", - "shr-long", - "ushr-long", - "add-float", - "sub-float", - "mul-float", - "div-float", - "rem-float", - "add-double", - "sub-double", - "mul-double", - "div-double", - "rem-double", - "add-int/2addr", - "sub-int/2addr", - "mul-int/2addr", - "div-int/2addr", - "rem-int/2addr", - "and-int/2addr", - "or-int/2addr", - "xor-int/2addr", - "shl-int/2addr", - "shr-int/2addr", - "ushr-int/2addr", - "add-long/2addr", - "sub-long/2addr", - "mul-long/2addr", - "div-long/2addr", - "rem-long/2addr", - "and-long/2addr", - "or-long/2addr", - "xor-long/2addr", - "shl-long/2addr", - "shr-long/2addr", - "ushr-long/2addr", - "add-float/2addr", - "sub-float/2addr", - "mul-float/2addr", - "div-float/2addr", - "rem-float/2addr", - "add-double/2addr", - "sub-double/2addr", - "mul-double/2addr", - "div-double/2addr", - "rem-double/2addr", - "add-int/lit16", - "rsub-int", - "mul-int/lit16", - "div-int/lit16", - "rem-int/lit16", - "and-int/lit16", - "or-int/lit16", - "xor-int/lit16", - "add-int/lit8", - "rsub-int/lit8", - "mul-int/lit8", - "div-int/lit8", - "rem-int/lit8", - "and-int/lit8", - "or-int/lit8", - "xor-int/lit8", - "shl-int/lit8", - "shr-int/lit8", - "ushr-int/lit8", - "+iget-volatile", - "+iput-volatile", - "+sget-volatile", - "+sput-volatile", - "+iget-object-volatile", - "+iget-wide-volatile", - "+iput-wide-volatile", - "+sget-wide-volatile", - "+sput-wide-volatile", - "^breakpoint", - "^throw-verification-error", - "+execute-inline", - "+execute-inline/range", - "+invoke-object-init/range", - "+return-void-barrier", - "+iget-quick", - "unused-f3", - "unused-f4", - "unused-f5", - "unused-f6", - "unused-f7", - "unused-f8", - "unused-f9", - "invoke-polymorphic", - "invoke-polymorphic/range", - "invoke-custom", - "invoke-custom/range", - "const-method-handle", - "const-method-type", - // END(libdex-opcode-names) -}; - -/* - * Return the name of an opcode. - */ -const char* dexGetOpcodeName(Opcode op) -{ - assert(op >= 0 && op < kNumPackedOpcodes); - return gOpNames[op]; -} diff --git a/libdex/DexOpcodes.h b/libdex/DexOpcodes.h deleted file mode 100644 index f4dcd6b51..000000000 --- a/libdex/DexOpcodes.h +++ /dev/null @@ -1,620 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * Dalvik opcode information. - * - * IMPORTANT NOTE: The contents of this file are mostly generated - * automatically by the opcode-gen tool. Any edits to the generated - * sections will get wiped out the next time the tool is run. - * - * See the file opcode-gen/README.txt for information about updating - * opcodes and instruction formats. - */ - -#ifndef LIBDEX_DEXOPCODES_H_ -#define LIBDEX_DEXOPCODES_H_ - -#include "DexFile.h" - -/* - * kMaxOpcodeValue: the highest possible raw (unpacked) opcode value - * - * kNumPackedOpcodes: the highest possible packed opcode value of a - * valid Dalvik opcode, plus one - * - * TODO: Change this once the rest of the code is prepared to deal with - * extended opcodes. - */ -// BEGIN(libdex-maximum-values); GENERATED AUTOMATICALLY BY opcode-gen -#define kMaxOpcodeValue 0xffff -#define kNumPackedOpcodes 0x100 -// END(libdex-maximum-values); GENERATED AUTOMATICALLY BY opcode-gen - -/* - * Switch table and array data signatures are a code unit consisting - * of "NOP" (0x00) in the low-order byte and a non-zero identifying - * code in the high-order byte. (A true NOP is 0x0000.) - */ -#define kPackedSwitchSignature 0x0100 -#define kSparseSwitchSignature 0x0200 -#define kArrayDataSignature 0x0300 - -/* - * Enumeration of all Dalvik opcodes, where the enumeration value - * associated with each is the corresponding packed opcode number. - * This is different than the opcode value from the Dalvik bytecode - * spec for opcode values >= 0xff; see dexOpcodeFromCodeUnit() below. - * - * A note about the "breakpoint" opcode. This instruction is special, - * in that it should never be seen by anything but the debug - * interpreter. During debugging it takes the place of an arbitrary - * opcode, which means operations like "tell me the opcode width so I - * can find the next instruction" aren't possible. (This is - * correctable, but probably not useful.) - */ -enum Opcode { - // BEGIN(libdex-opcode-enum); GENERATED AUTOMATICALLY BY opcode-gen - OP_NOP = 0x00, - OP_MOVE = 0x01, - OP_MOVE_FROM16 = 0x02, - OP_MOVE_16 = 0x03, - OP_MOVE_WIDE = 0x04, - OP_MOVE_WIDE_FROM16 = 0x05, - OP_MOVE_WIDE_16 = 0x06, - OP_MOVE_OBJECT = 0x07, - OP_MOVE_OBJECT_FROM16 = 0x08, - OP_MOVE_OBJECT_16 = 0x09, - OP_MOVE_RESULT = 0x0a, - OP_MOVE_RESULT_WIDE = 0x0b, - OP_MOVE_RESULT_OBJECT = 0x0c, - OP_MOVE_EXCEPTION = 0x0d, - OP_RETURN_VOID = 0x0e, - OP_RETURN = 0x0f, - OP_RETURN_WIDE = 0x10, - OP_RETURN_OBJECT = 0x11, - OP_CONST_4 = 0x12, - OP_CONST_16 = 0x13, - OP_CONST = 0x14, - OP_CONST_HIGH16 = 0x15, - OP_CONST_WIDE_16 = 0x16, - OP_CONST_WIDE_32 = 0x17, - OP_CONST_WIDE = 0x18, - OP_CONST_WIDE_HIGH16 = 0x19, - OP_CONST_STRING = 0x1a, - OP_CONST_STRING_JUMBO = 0x1b, - OP_CONST_CLASS = 0x1c, - OP_MONITOR_ENTER = 0x1d, - OP_MONITOR_EXIT = 0x1e, - OP_CHECK_CAST = 0x1f, - OP_INSTANCE_OF = 0x20, - OP_ARRAY_LENGTH = 0x21, - OP_NEW_INSTANCE = 0x22, - OP_NEW_ARRAY = 0x23, - OP_FILLED_NEW_ARRAY = 0x24, - OP_FILLED_NEW_ARRAY_RANGE = 0x25, - OP_FILL_ARRAY_DATA = 0x26, - OP_THROW = 0x27, - OP_GOTO = 0x28, - OP_GOTO_16 = 0x29, - OP_GOTO_32 = 0x2a, - OP_PACKED_SWITCH = 0x2b, - OP_SPARSE_SWITCH = 0x2c, - OP_CMPL_FLOAT = 0x2d, - OP_CMPG_FLOAT = 0x2e, - OP_CMPL_DOUBLE = 0x2f, - OP_CMPG_DOUBLE = 0x30, - OP_CMP_LONG = 0x31, - OP_IF_EQ = 0x32, - OP_IF_NE = 0x33, - OP_IF_LT = 0x34, - OP_IF_GE = 0x35, - OP_IF_GT = 0x36, - OP_IF_LE = 0x37, - OP_IF_EQZ = 0x38, - OP_IF_NEZ = 0x39, - OP_IF_LTZ = 0x3a, - OP_IF_GEZ = 0x3b, - OP_IF_GTZ = 0x3c, - OP_IF_LEZ = 0x3d, - OP_UNUSED_3E = 0x3e, - OP_UNUSED_3F = 0x3f, - OP_UNUSED_40 = 0x40, - OP_UNUSED_41 = 0x41, - OP_UNUSED_42 = 0x42, - OP_UNUSED_43 = 0x43, - OP_AGET = 0x44, - OP_AGET_WIDE = 0x45, - OP_AGET_OBJECT = 0x46, - OP_AGET_BOOLEAN = 0x47, - OP_AGET_BYTE = 0x48, - OP_AGET_CHAR = 0x49, - OP_AGET_SHORT = 0x4a, - OP_APUT = 0x4b, - OP_APUT_WIDE = 0x4c, - OP_APUT_OBJECT = 0x4d, - OP_APUT_BOOLEAN = 0x4e, - OP_APUT_BYTE = 0x4f, - OP_APUT_CHAR = 0x50, - OP_APUT_SHORT = 0x51, - OP_IGET = 0x52, - OP_IGET_WIDE = 0x53, - OP_IGET_OBJECT = 0x54, - OP_IGET_BOOLEAN = 0x55, - OP_IGET_BYTE = 0x56, - OP_IGET_CHAR = 0x57, - OP_IGET_SHORT = 0x58, - OP_IPUT = 0x59, - OP_IPUT_WIDE = 0x5a, - OP_IPUT_OBJECT = 0x5b, - OP_IPUT_BOOLEAN = 0x5c, - OP_IPUT_BYTE = 0x5d, - OP_IPUT_CHAR = 0x5e, - OP_IPUT_SHORT = 0x5f, - OP_SGET = 0x60, - OP_SGET_WIDE = 0x61, - OP_SGET_OBJECT = 0x62, - OP_SGET_BOOLEAN = 0x63, - OP_SGET_BYTE = 0x64, - OP_SGET_CHAR = 0x65, - OP_SGET_SHORT = 0x66, - OP_SPUT = 0x67, - OP_SPUT_WIDE = 0x68, - OP_SPUT_OBJECT = 0x69, - OP_SPUT_BOOLEAN = 0x6a, - OP_SPUT_BYTE = 0x6b, - OP_SPUT_CHAR = 0x6c, - OP_SPUT_SHORT = 0x6d, - OP_INVOKE_VIRTUAL = 0x6e, - OP_INVOKE_SUPER = 0x6f, - OP_INVOKE_DIRECT = 0x70, - OP_INVOKE_STATIC = 0x71, - OP_INVOKE_INTERFACE = 0x72, - OP_UNUSED_73 = 0x73, - OP_INVOKE_VIRTUAL_RANGE = 0x74, - OP_INVOKE_SUPER_RANGE = 0x75, - OP_INVOKE_DIRECT_RANGE = 0x76, - OP_INVOKE_STATIC_RANGE = 0x77, - OP_INVOKE_INTERFACE_RANGE = 0x78, - OP_UNUSED_79 = 0x79, - OP_UNUSED_7A = 0x7a, - OP_NEG_INT = 0x7b, - OP_NOT_INT = 0x7c, - OP_NEG_LONG = 0x7d, - OP_NOT_LONG = 0x7e, - OP_NEG_FLOAT = 0x7f, - OP_NEG_DOUBLE = 0x80, - OP_INT_TO_LONG = 0x81, - OP_INT_TO_FLOAT = 0x82, - OP_INT_TO_DOUBLE = 0x83, - OP_LONG_TO_INT = 0x84, - OP_LONG_TO_FLOAT = 0x85, - OP_LONG_TO_DOUBLE = 0x86, - OP_FLOAT_TO_INT = 0x87, - OP_FLOAT_TO_LONG = 0x88, - OP_FLOAT_TO_DOUBLE = 0x89, - OP_DOUBLE_TO_INT = 0x8a, - OP_DOUBLE_TO_LONG = 0x8b, - OP_DOUBLE_TO_FLOAT = 0x8c, - OP_INT_TO_BYTE = 0x8d, - OP_INT_TO_CHAR = 0x8e, - OP_INT_TO_SHORT = 0x8f, - OP_ADD_INT = 0x90, - OP_SUB_INT = 0x91, - OP_MUL_INT = 0x92, - OP_DIV_INT = 0x93, - OP_REM_INT = 0x94, - OP_AND_INT = 0x95, - OP_OR_INT = 0x96, - OP_XOR_INT = 0x97, - OP_SHL_INT = 0x98, - OP_SHR_INT = 0x99, - OP_USHR_INT = 0x9a, - OP_ADD_LONG = 0x9b, - OP_SUB_LONG = 0x9c, - OP_MUL_LONG = 0x9d, - OP_DIV_LONG = 0x9e, - OP_REM_LONG = 0x9f, - OP_AND_LONG = 0xa0, - OP_OR_LONG = 0xa1, - OP_XOR_LONG = 0xa2, - OP_SHL_LONG = 0xa3, - OP_SHR_LONG = 0xa4, - OP_USHR_LONG = 0xa5, - OP_ADD_FLOAT = 0xa6, - OP_SUB_FLOAT = 0xa7, - OP_MUL_FLOAT = 0xa8, - OP_DIV_FLOAT = 0xa9, - OP_REM_FLOAT = 0xaa, - OP_ADD_DOUBLE = 0xab, - OP_SUB_DOUBLE = 0xac, - OP_MUL_DOUBLE = 0xad, - OP_DIV_DOUBLE = 0xae, - OP_REM_DOUBLE = 0xaf, - OP_ADD_INT_2ADDR = 0xb0, - OP_SUB_INT_2ADDR = 0xb1, - OP_MUL_INT_2ADDR = 0xb2, - OP_DIV_INT_2ADDR = 0xb3, - OP_REM_INT_2ADDR = 0xb4, - OP_AND_INT_2ADDR = 0xb5, - OP_OR_INT_2ADDR = 0xb6, - OP_XOR_INT_2ADDR = 0xb7, - OP_SHL_INT_2ADDR = 0xb8, - OP_SHR_INT_2ADDR = 0xb9, - OP_USHR_INT_2ADDR = 0xba, - OP_ADD_LONG_2ADDR = 0xbb, - OP_SUB_LONG_2ADDR = 0xbc, - OP_MUL_LONG_2ADDR = 0xbd, - OP_DIV_LONG_2ADDR = 0xbe, - OP_REM_LONG_2ADDR = 0xbf, - OP_AND_LONG_2ADDR = 0xc0, - OP_OR_LONG_2ADDR = 0xc1, - OP_XOR_LONG_2ADDR = 0xc2, - OP_SHL_LONG_2ADDR = 0xc3, - OP_SHR_LONG_2ADDR = 0xc4, - OP_USHR_LONG_2ADDR = 0xc5, - OP_ADD_FLOAT_2ADDR = 0xc6, - OP_SUB_FLOAT_2ADDR = 0xc7, - OP_MUL_FLOAT_2ADDR = 0xc8, - OP_DIV_FLOAT_2ADDR = 0xc9, - OP_REM_FLOAT_2ADDR = 0xca, - OP_ADD_DOUBLE_2ADDR = 0xcb, - OP_SUB_DOUBLE_2ADDR = 0xcc, - OP_MUL_DOUBLE_2ADDR = 0xcd, - OP_DIV_DOUBLE_2ADDR = 0xce, - OP_REM_DOUBLE_2ADDR = 0xcf, - OP_ADD_INT_LIT16 = 0xd0, - OP_RSUB_INT = 0xd1, - OP_MUL_INT_LIT16 = 0xd2, - OP_DIV_INT_LIT16 = 0xd3, - OP_REM_INT_LIT16 = 0xd4, - OP_AND_INT_LIT16 = 0xd5, - OP_OR_INT_LIT16 = 0xd6, - OP_XOR_INT_LIT16 = 0xd7, - OP_ADD_INT_LIT8 = 0xd8, - OP_RSUB_INT_LIT8 = 0xd9, - OP_MUL_INT_LIT8 = 0xda, - OP_DIV_INT_LIT8 = 0xdb, - OP_REM_INT_LIT8 = 0xdc, - OP_AND_INT_LIT8 = 0xdd, - OP_OR_INT_LIT8 = 0xde, - OP_XOR_INT_LIT8 = 0xdf, - OP_SHL_INT_LIT8 = 0xe0, - OP_SHR_INT_LIT8 = 0xe1, - OP_USHR_INT_LIT8 = 0xe2, - OP_IGET_VOLATILE = 0xe3, - OP_IPUT_VOLATILE = 0xe4, - OP_SGET_VOLATILE = 0xe5, - OP_SPUT_VOLATILE = 0xe6, - OP_IGET_OBJECT_VOLATILE = 0xe7, - OP_IGET_WIDE_VOLATILE = 0xe8, - OP_IPUT_WIDE_VOLATILE = 0xe9, - OP_SGET_WIDE_VOLATILE = 0xea, - OP_SPUT_WIDE_VOLATILE = 0xeb, - OP_BREAKPOINT = 0xec, - OP_THROW_VERIFICATION_ERROR = 0xed, - OP_EXECUTE_INLINE = 0xee, - OP_EXECUTE_INLINE_RANGE = 0xef, - OP_INVOKE_OBJECT_INIT_RANGE = 0xf0, - OP_RETURN_VOID_BARRIER = 0xf1, - OP_IGET_QUICK = 0xf2, - OP_UNUSED_F3 = 0xf3, - OP_UNUSED_F4 = 0xf4, - OP_UNUSED_F5 = 0xf5, - OP_UNUSED_F6 = 0xf6, - OP_UNUSED_F7 = 0xf7, - OP_UNUSED_F8 = 0xf8, - OP_UNUSED_F9 = 0xf9, - OP_INVOKE_POLYMORPHIC = 0xfa, - OP_INVOKE_POLYMORPHIC_RANGE = 0xfb, - OP_INVOKE_CUSTOM = 0xfc, - OP_INVOKE_CUSTOM_RANGE = 0xfd, - OP_CONST_METHOD_HANDLE = 0xfe, - OP_CONST_METHOD_TYPE = 0xff, - // END(libdex-opcode-enum) -}; - -/* - * Macro used to generate a computed goto table for use in implementing - * an interpreter in C. - */ -#define DEFINE_GOTO_TABLE(_name) \ - static const void* (_name)[kNumPackedOpcodes] = { \ - /* BEGIN(libdex-goto-table); GENERATED AUTOMATICALLY BY opcode-gen */ \ - H(OP_NOP), \ - H(OP_MOVE), \ - H(OP_MOVE_FROM16), \ - H(OP_MOVE_16), \ - H(OP_MOVE_WIDE), \ - H(OP_MOVE_WIDE_FROM16), \ - H(OP_MOVE_WIDE_16), \ - H(OP_MOVE_OBJECT), \ - H(OP_MOVE_OBJECT_FROM16), \ - H(OP_MOVE_OBJECT_16), \ - H(OP_MOVE_RESULT), \ - H(OP_MOVE_RESULT_WIDE), \ - H(OP_MOVE_RESULT_OBJECT), \ - H(OP_MOVE_EXCEPTION), \ - H(OP_RETURN_VOID), \ - H(OP_RETURN), \ - H(OP_RETURN_WIDE), \ - H(OP_RETURN_OBJECT), \ - H(OP_CONST_4), \ - H(OP_CONST_16), \ - H(OP_CONST), \ - H(OP_CONST_HIGH16), \ - H(OP_CONST_WIDE_16), \ - H(OP_CONST_WIDE_32), \ - H(OP_CONST_WIDE), \ - H(OP_CONST_WIDE_HIGH16), \ - H(OP_CONST_STRING), \ - H(OP_CONST_STRING_JUMBO), \ - H(OP_CONST_CLASS), \ - H(OP_MONITOR_ENTER), \ - H(OP_MONITOR_EXIT), \ - H(OP_CHECK_CAST), \ - H(OP_INSTANCE_OF), \ - H(OP_ARRAY_LENGTH), \ - H(OP_NEW_INSTANCE), \ - H(OP_NEW_ARRAY), \ - H(OP_FILLED_NEW_ARRAY), \ - H(OP_FILLED_NEW_ARRAY_RANGE), \ - H(OP_FILL_ARRAY_DATA), \ - H(OP_THROW), \ - H(OP_GOTO), \ - H(OP_GOTO_16), \ - H(OP_GOTO_32), \ - H(OP_PACKED_SWITCH), \ - H(OP_SPARSE_SWITCH), \ - H(OP_CMPL_FLOAT), \ - H(OP_CMPG_FLOAT), \ - H(OP_CMPL_DOUBLE), \ - H(OP_CMPG_DOUBLE), \ - H(OP_CMP_LONG), \ - H(OP_IF_EQ), \ - H(OP_IF_NE), \ - H(OP_IF_LT), \ - H(OP_IF_GE), \ - H(OP_IF_GT), \ - H(OP_IF_LE), \ - H(OP_IF_EQZ), \ - H(OP_IF_NEZ), \ - H(OP_IF_LTZ), \ - H(OP_IF_GEZ), \ - H(OP_IF_GTZ), \ - H(OP_IF_LEZ), \ - H(OP_UNUSED_3E), \ - H(OP_UNUSED_3F), \ - H(OP_UNUSED_40), \ - H(OP_UNUSED_41), \ - H(OP_UNUSED_42), \ - H(OP_UNUSED_43), \ - H(OP_AGET), \ - H(OP_AGET_WIDE), \ - H(OP_AGET_OBJECT), \ - H(OP_AGET_BOOLEAN), \ - H(OP_AGET_BYTE), \ - H(OP_AGET_CHAR), \ - H(OP_AGET_SHORT), \ - H(OP_APUT), \ - H(OP_APUT_WIDE), \ - H(OP_APUT_OBJECT), \ - H(OP_APUT_BOOLEAN), \ - H(OP_APUT_BYTE), \ - H(OP_APUT_CHAR), \ - H(OP_APUT_SHORT), \ - H(OP_IGET), \ - H(OP_IGET_WIDE), \ - H(OP_IGET_OBJECT), \ - H(OP_IGET_BOOLEAN), \ - H(OP_IGET_BYTE), \ - H(OP_IGET_CHAR), \ - H(OP_IGET_SHORT), \ - H(OP_IPUT), \ - H(OP_IPUT_WIDE), \ - H(OP_IPUT_OBJECT), \ - H(OP_IPUT_BOOLEAN), \ - H(OP_IPUT_BYTE), \ - H(OP_IPUT_CHAR), \ - H(OP_IPUT_SHORT), \ - H(OP_SGET), \ - H(OP_SGET_WIDE), \ - H(OP_SGET_OBJECT), \ - H(OP_SGET_BOOLEAN), \ - H(OP_SGET_BYTE), \ - H(OP_SGET_CHAR), \ - H(OP_SGET_SHORT), \ - H(OP_SPUT), \ - H(OP_SPUT_WIDE), \ - H(OP_SPUT_OBJECT), \ - H(OP_SPUT_BOOLEAN), \ - H(OP_SPUT_BYTE), \ - H(OP_SPUT_CHAR), \ - H(OP_SPUT_SHORT), \ - H(OP_INVOKE_VIRTUAL), \ - H(OP_INVOKE_SUPER), \ - H(OP_INVOKE_DIRECT), \ - H(OP_INVOKE_STATIC), \ - H(OP_INVOKE_INTERFACE), \ - H(OP_UNUSED_73), \ - H(OP_INVOKE_VIRTUAL_RANGE), \ - H(OP_INVOKE_SUPER_RANGE), \ - H(OP_INVOKE_DIRECT_RANGE), \ - H(OP_INVOKE_STATIC_RANGE), \ - H(OP_INVOKE_INTERFACE_RANGE), \ - H(OP_UNUSED_79), \ - H(OP_UNUSED_7A), \ - H(OP_NEG_INT), \ - H(OP_NOT_INT), \ - H(OP_NEG_LONG), \ - H(OP_NOT_LONG), \ - H(OP_NEG_FLOAT), \ - H(OP_NEG_DOUBLE), \ - H(OP_INT_TO_LONG), \ - H(OP_INT_TO_FLOAT), \ - H(OP_INT_TO_DOUBLE), \ - H(OP_LONG_TO_INT), \ - H(OP_LONG_TO_FLOAT), \ - H(OP_LONG_TO_DOUBLE), \ - H(OP_FLOAT_TO_INT), \ - H(OP_FLOAT_TO_LONG), \ - H(OP_FLOAT_TO_DOUBLE), \ - H(OP_DOUBLE_TO_INT), \ - H(OP_DOUBLE_TO_LONG), \ - H(OP_DOUBLE_TO_FLOAT), \ - H(OP_INT_TO_BYTE), \ - H(OP_INT_TO_CHAR), \ - H(OP_INT_TO_SHORT), \ - H(OP_ADD_INT), \ - H(OP_SUB_INT), \ - H(OP_MUL_INT), \ - H(OP_DIV_INT), \ - H(OP_REM_INT), \ - H(OP_AND_INT), \ - H(OP_OR_INT), \ - H(OP_XOR_INT), \ - H(OP_SHL_INT), \ - H(OP_SHR_INT), \ - H(OP_USHR_INT), \ - H(OP_ADD_LONG), \ - H(OP_SUB_LONG), \ - H(OP_MUL_LONG), \ - H(OP_DIV_LONG), \ - H(OP_REM_LONG), \ - H(OP_AND_LONG), \ - H(OP_OR_LONG), \ - H(OP_XOR_LONG), \ - H(OP_SHL_LONG), \ - H(OP_SHR_LONG), \ - H(OP_USHR_LONG), \ - H(OP_ADD_FLOAT), \ - H(OP_SUB_FLOAT), \ - H(OP_MUL_FLOAT), \ - H(OP_DIV_FLOAT), \ - H(OP_REM_FLOAT), \ - H(OP_ADD_DOUBLE), \ - H(OP_SUB_DOUBLE), \ - H(OP_MUL_DOUBLE), \ - H(OP_DIV_DOUBLE), \ - H(OP_REM_DOUBLE), \ - H(OP_ADD_INT_2ADDR), \ - H(OP_SUB_INT_2ADDR), \ - H(OP_MUL_INT_2ADDR), \ - H(OP_DIV_INT_2ADDR), \ - H(OP_REM_INT_2ADDR), \ - H(OP_AND_INT_2ADDR), \ - H(OP_OR_INT_2ADDR), \ - H(OP_XOR_INT_2ADDR), \ - H(OP_SHL_INT_2ADDR), \ - H(OP_SHR_INT_2ADDR), \ - H(OP_USHR_INT_2ADDR), \ - H(OP_ADD_LONG_2ADDR), \ - H(OP_SUB_LONG_2ADDR), \ - H(OP_MUL_LONG_2ADDR), \ - H(OP_DIV_LONG_2ADDR), \ - H(OP_REM_LONG_2ADDR), \ - H(OP_AND_LONG_2ADDR), \ - H(OP_OR_LONG_2ADDR), \ - H(OP_XOR_LONG_2ADDR), \ - H(OP_SHL_LONG_2ADDR), \ - H(OP_SHR_LONG_2ADDR), \ - H(OP_USHR_LONG_2ADDR), \ - H(OP_ADD_FLOAT_2ADDR), \ - H(OP_SUB_FLOAT_2ADDR), \ - H(OP_MUL_FLOAT_2ADDR), \ - H(OP_DIV_FLOAT_2ADDR), \ - H(OP_REM_FLOAT_2ADDR), \ - H(OP_ADD_DOUBLE_2ADDR), \ - H(OP_SUB_DOUBLE_2ADDR), \ - H(OP_MUL_DOUBLE_2ADDR), \ - H(OP_DIV_DOUBLE_2ADDR), \ - H(OP_REM_DOUBLE_2ADDR), \ - H(OP_ADD_INT_LIT16), \ - H(OP_RSUB_INT), \ - H(OP_MUL_INT_LIT16), \ - H(OP_DIV_INT_LIT16), \ - H(OP_REM_INT_LIT16), \ - H(OP_AND_INT_LIT16), \ - H(OP_OR_INT_LIT16), \ - H(OP_XOR_INT_LIT16), \ - H(OP_ADD_INT_LIT8), \ - H(OP_RSUB_INT_LIT8), \ - H(OP_MUL_INT_LIT8), \ - H(OP_DIV_INT_LIT8), \ - H(OP_REM_INT_LIT8), \ - H(OP_AND_INT_LIT8), \ - H(OP_OR_INT_LIT8), \ - H(OP_XOR_INT_LIT8), \ - H(OP_SHL_INT_LIT8), \ - H(OP_SHR_INT_LIT8), \ - H(OP_USHR_INT_LIT8), \ - H(OP_IGET_VOLATILE), \ - H(OP_IPUT_VOLATILE), \ - H(OP_SGET_VOLATILE), \ - H(OP_SPUT_VOLATILE), \ - H(OP_IGET_OBJECT_VOLATILE), \ - H(OP_IGET_WIDE_VOLATILE), \ - H(OP_IPUT_WIDE_VOLATILE), \ - H(OP_SGET_WIDE_VOLATILE), \ - H(OP_SPUT_WIDE_VOLATILE), \ - H(OP_BREAKPOINT), \ - H(OP_THROW_VERIFICATION_ERROR), \ - H(OP_EXECUTE_INLINE), \ - H(OP_EXECUTE_INLINE_RANGE), \ - H(OP_INVOKE_OBJECT_INIT_RANGE), \ - H(OP_RETURN_VOID_BARRIER), \ - H(OP_IGET_QUICK), \ - H(OP_UNUSED_F3), \ - H(OP_UNUSED_F4), \ - H(OP_UNUSED_F5), \ - H(OP_UNUSED_F6), \ - H(OP_UNUSED_F7), \ - H(OP_UNUSED_F8), \ - H(OP_UNUSED_F9), \ - H(OP_INVOKE_POLYMORPHIC), \ - H(OP_INVOKE_POLYMORPHIC_RANGE), \ - H(OP_INVOKE_CUSTOM), \ - H(OP_INVOKE_CUSTOM_RANGE), \ - H(OP_CONST_METHOD_HANDLE), \ - H(OP_CONST_METHOD_TYPE), \ - /* END(libdex-goto-table) */ \ - }; - -/* - * Return the Opcode for a given raw opcode code unit (which may - * include data payload). The packed index is a zero-based index which - * can be used to point into various opcode-related tables. The Dalvik - * opcode space is inherently sparse, in that the opcode unit is 16 - * bits wide, but for most opcodes, eight of those bits are for data. - */ -DEX_INLINE Opcode dexOpcodeFromCodeUnit(u2 codeUnit) { - /* - * This will want to become table-driven should the opcode layout - * get more complicated. - * - * Note: This has to match the corresponding code in opcode-gen, so - * that data tables get generated in a consistent way. - */ - int lowByte = codeUnit & 0xff; - return (Opcode) lowByte; -} - -/* - * Return the name of an opcode. - */ -const char* dexGetOpcodeName(Opcode op); - -#endif // LIBDEX_DEXOPCODES_H_ diff --git a/libdex/DexOptData.cpp b/libdex/DexOptData.cpp deleted file mode 100644 index 109e851f9..000000000 --- a/libdex/DexOptData.cpp +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * Functions to parse and manipulate the additional data tables added - * to optimized .dex files. - */ - -#include <zlib.h> - -#include "DexOptData.h" - -/* - * Check to see if a given data pointer is a valid double-word-aligned - * pointer into the given memory range (from start inclusive to end - * exclusive). Returns true if valid. - */ -static bool isValidPointer(const void* ptr, const void* start, const void* end) -{ - return (ptr >= start) && (ptr < end) && (((uintptr_t) ptr & 7) == 0); -} - -/* (documented in header file) */ -u4 dexComputeOptChecksum(const DexOptHeader* pOptHeader) -{ - const u1* start = (const u1*) pOptHeader + pOptHeader->depsOffset; - const u1* end = (const u1*) pOptHeader + - pOptHeader->optOffset + pOptHeader->optLength; - - uLong adler = adler32(0L, Z_NULL, 0); - - return (u4) adler32(adler, start, end - start); -} - -/* (documented in header file) */ -bool dexParseOptData(const u1* data, size_t length, DexFile* pDexFile) -{ - const void* pOptStart = data + pDexFile->pOptHeader->optOffset; - const void* pOptEnd = data + length; - const u4* pOpt = (const u4*) pOptStart; - u4 optLength = (const u1*) pOptEnd - (const u1*) pOptStart; - - /* - * Make sure the opt data start is in range and aligned. This may - * seem like a superfluous check, but (a) if the file got - * truncated, it might turn out that pOpt >= pOptEnd; and (b) - * if the opt data header got corrupted, pOpt might not be - * properly aligned. This test will catch both of these cases. - */ - if (!isValidPointer(pOpt, pOptStart, pOptEnd)) { - ALOGE("Bogus opt data start pointer"); - return false; - } - - /* Make sure that the opt data length is a whole number of words. */ - if ((optLength & 3) != 0) { - ALOGE("Unaligned opt data area end"); - return false; - } - - /* - * Make sure that the opt data area is large enough to have at least - * one chunk header. - */ - if (optLength < 8) { - ALOGE("Undersized opt data area (%u)", optLength); - return false; - } - - /* Process chunks until we see the end marker. */ - while (*pOpt != kDexChunkEnd) { - if (!isValidPointer(pOpt + 2, pOptStart, pOptEnd)) { - const u4 offset = ((const u1*) pOpt) - data; - ALOGE("Bogus opt data content pointer at offset %u", offset); - return false; - } - - u4 size = *(pOpt + 1); - const u1* pOptData = (const u1*) (pOpt + 2); - - /* - * The rounded size is 64-bit aligned and includes +8 for the - * type/size header (which was extracted immediately above). - */ - u4 roundedSize = (size + 8 + 7) & ~7; - const u4* pNextOpt = pOpt + (roundedSize / sizeof(u4)); - - if (!isValidPointer(pNextOpt, pOptStart, pOptEnd)) { - const u4 offset = ((const u1*) pOpt) - data; - ALOGE("Opt data area problem for chunk of size %u at offset %u", size, offset); - return false; - } - - switch (*pOpt) { - case kDexChunkClassLookup: - pDexFile->pClassLookup = (const DexClassLookup*) pOptData; - break; - case kDexChunkRegisterMaps: - ALOGV("+++ found register maps, size=%u", size); - pDexFile->pRegisterMapPool = pOptData; - break; - default: - ALOGI("Unknown chunk 0x%08x (%c%c%c%c), size=%d in opt data area", - *pOpt, - (char) ((*pOpt) >> 24), (char) ((*pOpt) >> 16), - (char) ((*pOpt) >> 8), (char) (*pOpt), - size); - break; - } - - pOpt = pNextOpt; - } - - return true; -} diff --git a/libdex/DexOptData.h b/libdex/DexOptData.h deleted file mode 100644 index 69eda0142..000000000 --- a/libdex/DexOptData.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * Functions to parse and manipulate the additional data tables added - * to optimized .dex files. - */ - -#ifndef _LIBDEX_DEXOPTDATA -#define _LIBDEX_DEXOPTDATA - -#include "libdex/DexFile.h" - -/* - * Parse the optimized data tables in the given dex file. - * - * @param data pointer to the start of the entire dex file - * @param length length of the entire dex file, in bytes - * @param pDexFile pointer to the associated dex file structure - */ -bool dexParseOptData(const u1* data, size_t length, DexFile* pDexFile); - -/* - * Compute the checksum of the optimized data tables pointed at by the given - * header. - */ -u4 dexComputeOptChecksum(const DexOptHeader* pOptHeader); - -#endif /* def _LIBDEX_DEXOPTDATA */ diff --git a/libdex/DexProto.cpp b/libdex/DexProto.cpp deleted file mode 100644 index 06c59b37d..000000000 --- a/libdex/DexProto.cpp +++ /dev/null @@ -1,523 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * Functions for dealing with method prototypes - */ - -#include "DexProto.h" - -#include <stdlib.h> -#include <string.h> - -/* - * =========================================================================== - * String Cache - * =========================================================================== - */ - -/* - * Make sure that the given cache can hold a string of the given length, - * including the final '\0' byte. - */ -void dexStringCacheAlloc(DexStringCache* pCache, size_t length) { - if (pCache->allocatedSize != 0) { - if (pCache->allocatedSize >= length) { - return; - } - free((void*) pCache->value); - } - - if (length <= sizeof(pCache->buffer)) { - pCache->value = pCache->buffer; - pCache->allocatedSize = 0; - } else { - pCache->value = (char*) malloc(length); - pCache->allocatedSize = length; - } -} - -/* - * Initialize the given DexStringCache. Use this function before passing - * one into any other function. - */ -void dexStringCacheInit(DexStringCache* pCache) { - pCache->value = pCache->buffer; - pCache->allocatedSize = 0; - pCache->buffer[0] = '\0'; -} - -/* - * Release the allocated contents of the given DexStringCache, if any. - * Use this function after your last use of a DexStringCache. - */ -void dexStringCacheRelease(DexStringCache* pCache) { - if (pCache->allocatedSize != 0) { - free((void*) pCache->value); - pCache->value = pCache->buffer; - pCache->allocatedSize = 0; - } -} - -/* - * If the given DexStringCache doesn't already point at the given value, - * make a copy of it into the cache. This always returns a writable - * pointer to the contents (whether or not a copy had to be made). This - * function is intended to be used after making a call that at least - * sometimes doesn't populate a DexStringCache. - */ -char* dexStringCacheEnsureCopy(DexStringCache* pCache, const char* value) { - if (value != pCache->value) { - size_t length = strlen(value) + 1; - dexStringCacheAlloc(pCache, length); - memcpy(pCache->value, value, length); - } - - return pCache->value; -} - -/* - * Abandon the given DexStringCache, and return a writable copy of the - * given value (reusing the string cache's allocation if possible). - * The return value must be free()d by the caller. Use this instead of - * dexStringCacheRelease() if you want the buffer to survive past the - * scope of the DexStringCache. - */ -char* dexStringCacheAbandon(DexStringCache* pCache, const char* value) { - if ((value == pCache->value) && (pCache->allocatedSize != 0)) { - char* result = pCache->value; - pCache->allocatedSize = 0; - pCache->value = pCache->buffer; - return result; - } else { - return strdup(value); - } -} - - -/* - * =========================================================================== - * Method Prototypes - * =========================================================================== - */ - -/* - * Return the DexProtoId from the given DexProto. The DexProto must - * actually refer to a DexProtoId. - */ -static inline const DexProtoId* getProtoId(const DexProto* pProto) { - return dexGetProtoId(pProto->dexFile, pProto->protoIdx); -} - -/* (documented in header file) */ -const char* dexProtoGetShorty(const DexProto* pProto) { - const DexProtoId* protoId = getProtoId(pProto); - - return dexStringById(pProto->dexFile, protoId->shortyIdx); -} - -/* (documented in header file) */ -const char* dexProtoGetMethodDescriptor(const DexProto* pProto, - DexStringCache* pCache) { - const DexFile* dexFile = pProto->dexFile; - const DexProtoId* protoId = getProtoId(pProto); - const DexTypeList* typeList = dexGetProtoParameters(dexFile, protoId); - size_t length = 3; // parens and terminating '\0' - u4 paramCount = (typeList == NULL) ? 0 : typeList->size; - u4 i; - - for (i = 0; i < paramCount; i++) { - u4 idx = dexTypeListGetIdx(typeList, i); - length += strlen(dexStringByTypeIdx(dexFile, idx)); - } - - length += strlen(dexStringByTypeIdx(dexFile, protoId->returnTypeIdx)); - - dexStringCacheAlloc(pCache, length); - - char *at = (char*) pCache->value; - *(at++) = '('; - - for (i = 0; i < paramCount; i++) { - u4 idx = dexTypeListGetIdx(typeList, i); - const char* desc = dexStringByTypeIdx(dexFile, idx); - strcpy(at, desc); - at += strlen(desc); - } - - *(at++) = ')'; - - strcpy(at, dexStringByTypeIdx(dexFile, protoId->returnTypeIdx)); - return pCache->value; -} - -/* (documented in header file) */ -char* dexProtoCopyMethodDescriptor(const DexProto* pProto) { - DexStringCache cache; - - dexStringCacheInit(&cache); - return dexStringCacheAbandon(&cache, - dexProtoGetMethodDescriptor(pProto, &cache)); -} - -/* (documented in header file) */ -const char* dexProtoGetParameterDescriptors(const DexProto* pProto, - DexStringCache* pCache) { - DexParameterIterator iterator; - size_t length = 1; /* +1 for the terminating '\0' */ - - dexParameterIteratorInit(&iterator, pProto); - - for (;;) { - const char* descriptor = dexParameterIteratorNextDescriptor(&iterator); - if (descriptor == NULL) { - break; - } - - length += strlen(descriptor); - } - - dexParameterIteratorInit(&iterator, pProto); - - dexStringCacheAlloc(pCache, length); - char *at = (char*) pCache->value; - - for (;;) { - const char* descriptor = dexParameterIteratorNextDescriptor(&iterator); - if (descriptor == NULL) { - break; - } - - strcpy(at, descriptor); - at += strlen(descriptor); - } - - return pCache->value; -} - -/* (documented in header file) */ -const char* dexProtoGetReturnType(const DexProto* pProto) { - const DexProtoId* protoId = getProtoId(pProto); - return dexStringByTypeIdx(pProto->dexFile, protoId->returnTypeIdx); -} - -/* (documented in header file) */ -size_t dexProtoGetParameterCount(const DexProto* pProto) { - const DexProtoId* protoId = getProtoId(pProto); - const DexTypeList* typeList = - dexGetProtoParameters(pProto->dexFile, protoId); - return (typeList == NULL) ? 0 : typeList->size; -} - -/* (documented in header file) */ -int dexProtoComputeArgsSize(const DexProto* pProto) { - const char* shorty = dexProtoGetShorty(pProto); - int count = 0; - - /* Skip the return type. */ - shorty++; - - for (;;) { - switch (*(shorty++)) { - case '\0': { - return count; - } - case 'D': - case 'J': { - count += 2; - break; - } - default: { - count++; - break; - } - } - } -} - -/* - * Common implementation for dexProtoCompare() and dexProtoCompareParameters(). - */ -static int protoCompare(const DexProto* pProto1, const DexProto* pProto2, - bool compareReturnType) { - - if (pProto1 == pProto2) { - // Easy out. - return 0; - } else { - const DexFile* dexFile1 = pProto1->dexFile; - const DexProtoId* protoId1 = getProtoId(pProto1); - const DexTypeList* typeList1 = - dexGetProtoParameters(dexFile1, protoId1); - int paramCount1 = (typeList1 == NULL) ? 0 : typeList1->size; - - const DexFile* dexFile2 = pProto2->dexFile; - const DexProtoId* protoId2 = getProtoId(pProto2); - const DexTypeList* typeList2 = - dexGetProtoParameters(dexFile2, protoId2); - int paramCount2 = (typeList2 == NULL) ? 0 : typeList2->size; - - if (protoId1 == protoId2) { - // Another easy out. - return 0; - } - - // Compare return types. - - if (compareReturnType) { - int result = - strcmp(dexStringByTypeIdx(dexFile1, protoId1->returnTypeIdx), - dexStringByTypeIdx(dexFile2, protoId2->returnTypeIdx)); - - if (result != 0) { - return result; - } - } - - // Compare parameters. - - int minParam = (paramCount1 > paramCount2) ? paramCount2 : paramCount1; - int i; - - for (i = 0; i < minParam; i++) { - u4 idx1 = dexTypeListGetIdx(typeList1, i); - u4 idx2 = dexTypeListGetIdx(typeList2, i); - int result = - strcmp(dexStringByTypeIdx(dexFile1, idx1), - dexStringByTypeIdx(dexFile2, idx2)); - - if (result != 0) { - return result; - } - } - - if (paramCount1 < paramCount2) { - return -1; - } else if (paramCount1 > paramCount2) { - return 1; - } else { - return 0; - } - } -} - -/* (documented in header file) */ -int dexProtoCompare(const DexProto* pProto1, const DexProto* pProto2) { - return protoCompare(pProto1, pProto2, true); -} - -/* (documented in header file) */ -int dexProtoCompareParameters(const DexProto* pProto1, const DexProto* pProto2){ - return protoCompare(pProto1, pProto2, false); -} - - -/* - * Helper for dexProtoCompareToDescriptor(), which gets the return type - * descriptor from a method descriptor string. - */ -static const char* methodDescriptorReturnType(const char* descriptor) { - const char* result = strchr(descriptor, ')'); - - if (result == NULL) { - return NULL; - } - - // The return type is the character just past the ')'. - return result + 1; -} - -/* - * Helper for dexProtoCompareToDescriptor(), which indicates the end - * of an embedded argument type descriptor, which is also the - * beginning of the next argument type descriptor. Since this is for - * argument types, it doesn't accept 'V' as a valid type descriptor. - */ -static const char* methodDescriptorNextType(const char* descriptor) { - // Skip any array references. - - while (*descriptor == '[') { - descriptor++; - } - - switch (*descriptor) { - case 'B': case 'C': case 'D': case 'F': - case 'I': case 'J': case 'S': case 'Z': { - return descriptor + 1; - } - case 'L': { - const char* result = strchr(descriptor + 1, ';'); - if (result != NULL) { - // The type ends just past the ';'. - return result + 1; - } - } - } - - return NULL; -} - -/* - * Common implementation for dexProtoCompareToDescriptor() and - * dexProtoCompareToParameterDescriptors(). The descriptor argument - * can be either a full method descriptor (with parens and a return - * type) or an unadorned concatenation of types (e.g. a list of - * argument types). - */ -static int protoCompareToParameterDescriptors(const DexProto* proto, - const char* descriptor, bool expectParens) { - char expectedEndChar = expectParens ? ')' : '\0'; - DexParameterIterator iterator; - dexParameterIteratorInit(&iterator, proto); - - if (expectParens) { - // Skip the '('. - assert (*descriptor == '('); - descriptor++; - } - - for (;;) { - const char* protoDesc = dexParameterIteratorNextDescriptor(&iterator); - - if (*descriptor == expectedEndChar) { - // It's the end of the descriptor string. - if (protoDesc == NULL) { - // It's also the end of the prototype's arguments. - return 0; - } else { - // The prototype still has more arguments. - return 1; - } - } - - if (protoDesc == NULL) { - /* - * The prototype doesn't have arguments left, but the - * descriptor string does. - */ - return -1; - } - - // Both prototype and descriptor have arguments. Compare them. - - const char* nextDesc = methodDescriptorNextType(descriptor); - assert(nextDesc != NULL); - - for (;;) { - char c1 = *(protoDesc++); - char c2 = (descriptor < nextDesc) ? *(descriptor++) : '\0'; - - if (c1 < c2) { - // This includes the case where the proto is shorter. - return -1; - } else if (c1 > c2) { - // This includes the case where the desc is shorter. - return 1; - } else if (c1 == '\0') { - // The two types are equal in length. (c2 necessarily == '\0'.) - break; - } - } - - /* - * If we made it here, the two arguments matched, and - * descriptor == nextDesc. - */ - } -} - -/* (documented in header file) */ -int dexProtoCompareToDescriptor(const DexProto* proto, - const char* descriptor) { - // First compare the return types. - - const char *returnType = methodDescriptorReturnType(descriptor); - assert(returnType != NULL); - - int result = strcmp(dexProtoGetReturnType(proto), returnType); - - if (result != 0) { - return result; - } - - // The return types match, so we have to check arguments. - return protoCompareToParameterDescriptors(proto, descriptor, true); -} - -/* (documented in header file) */ -int dexProtoCompareToParameterDescriptors(const DexProto* proto, - const char* descriptors) { - return protoCompareToParameterDescriptors(proto, descriptors, false); -} - - - - - - -/* - * =========================================================================== - * Parameter Iterators - * =========================================================================== - */ - -/* - * Initialize the given DexParameterIterator to be at the start of the - * parameters of the given prototype. - */ -void dexParameterIteratorInit(DexParameterIterator* pIterator, - const DexProto* pProto) { - pIterator->proto = pProto; - pIterator->cursor = 0; - - pIterator->parameters = - dexGetProtoParameters(pProto->dexFile, getProtoId(pProto)); - pIterator->parameterCount = (pIterator->parameters == NULL) ? 0 - : pIterator->parameters->size; -} - -/* - * Get the type_id index for the next parameter, if any. This returns - * kDexNoIndex if the last parameter has already been consumed. - */ -u4 dexParameterIteratorNextIndex(DexParameterIterator* pIterator) { - int cursor = pIterator->cursor; - int parameterCount = pIterator->parameterCount; - - if (cursor >= parameterCount) { - // The iteration is complete. - return kDexNoIndex; - } else { - u4 idx = dexTypeListGetIdx(pIterator->parameters, cursor); - pIterator->cursor++; - return idx; - } -} - -/* - * Get the type descriptor for the next parameter, if any. This returns - * NULL if the last parameter has already been consumed. - */ -const char* dexParameterIteratorNextDescriptor( - DexParameterIterator* pIterator) { - u4 idx = dexParameterIteratorNextIndex(pIterator); - - if (idx == kDexNoIndex) { - return NULL; - } - - return dexStringByTypeIdx(pIterator->proto->dexFile, idx); -} diff --git a/libdex/DexProto.h b/libdex/DexProto.h deleted file mode 100644 index dccae6c04..000000000 --- a/libdex/DexProto.h +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * Functions for dealing with method prototypes - */ - -#ifndef LIBDEX_DEXPROTO_H_ -#define LIBDEX_DEXPROTO_H_ - -#include "DexFile.h" - -/* - * Single-thread single-string cache. This structure holds a pointer to - * a string which is semi-automatically manipulated by some of the - * method prototype functions. Functions which use in this struct - * generally return a string that is valid until the next - * time the same DexStringCache is used. - */ -struct DexStringCache { - char* value; /* the latest value */ - size_t allocatedSize; /* size of the allocated buffer, if allocated */ - char buffer[120]; /* buffer used to hold small-enough results */ -}; - -/* - * Make sure that the given cache can hold a string of the given length, - * including the final '\0' byte. - */ -void dexStringCacheAlloc(DexStringCache* pCache, size_t length); - -/* - * Initialize the given DexStringCache. Use this function before passing - * one into any other function. - */ -void dexStringCacheInit(DexStringCache* pCache); - -/* - * Release the allocated contents of the given DexStringCache, if any. - * Use this function after your last use of a DexStringCache. - */ -void dexStringCacheRelease(DexStringCache* pCache); - -/* - * If the given DexStringCache doesn't already point at the given value, - * make a copy of it into the cache. This always returns a writable - * pointer to the contents (whether or not a copy had to be made). This - * function is intended to be used after making a call that at least - * sometimes doesn't populate a DexStringCache. - */ -char* dexStringCacheEnsureCopy(DexStringCache* pCache, const char* value); - -/* - * Abandon the given DexStringCache, and return a writable copy of the - * given value (reusing the string cache's allocation if possible). - * The return value must be free()d by the caller. Use this instead of - * dexStringCacheRelease() if you want the buffer to survive past the - * scope of the DexStringCache. - */ -char* dexStringCacheAbandon(DexStringCache* pCache, const char* value); - -/* - * Method prototype structure, which refers to a protoIdx in a - * particular DexFile. - */ -struct DexProto { - const DexFile* dexFile; /* file the idx refers to */ - u4 protoIdx; /* index into proto_ids table of dexFile */ -}; - -/* - * Set the given DexProto to refer to the prototype of the given MethodId. - */ -DEX_INLINE void dexProtoSetFromMethodId(DexProto* pProto, - const DexFile* pDexFile, const DexMethodId* pMethodId) -{ - pProto->dexFile = pDexFile; - pProto->protoIdx = pMethodId->protoIdx; -} - -/* - * Get the short-form method descriptor for the given prototype. The - * prototype must be protoIdx-based. - */ -const char* dexProtoGetShorty(const DexProto* pProto); - -/* - * Get the full method descriptor for the given prototype. - */ -const char* dexProtoGetMethodDescriptor(const DexProto* pProto, - DexStringCache* pCache); - -/* - * Get a copy of the descriptor string associated with the given prototype. - * The returned pointer must be free()ed by the caller. - */ -char* dexProtoCopyMethodDescriptor(const DexProto* pProto); - -/* - * Get the parameter descriptors for the given prototype. This is the - * concatenation of all the descriptors for all the parameters, in - * order, with no other adornment. - */ -const char* dexProtoGetParameterDescriptors(const DexProto* pProto, - DexStringCache* pCache); - -/* - * Return the utf-8 encoded descriptor string from the proto of a MethodId. - */ -DEX_INLINE const char* dexGetDescriptorFromMethodId(const DexFile* pDexFile, - const DexMethodId* pMethodId, DexStringCache* pCache) -{ - DexProto proto; - - dexProtoSetFromMethodId(&proto, pDexFile, pMethodId); - return dexProtoGetMethodDescriptor(&proto, pCache); -} - -/* - * Get a copy of the utf-8 encoded method descriptor string from the - * proto of a MethodId. The returned pointer must be free()ed by the - * caller. - */ -DEX_INLINE char* dexCopyDescriptorFromMethodId(const DexFile* pDexFile, - const DexMethodId* pMethodId) -{ - DexProto proto; - - dexProtoSetFromMethodId(&proto, pDexFile, pMethodId); - return dexProtoCopyMethodDescriptor(&proto); -} - -/* - * Get the type descriptor for the return type of the given prototype. - */ -const char* dexProtoGetReturnType(const DexProto* pProto); - -/* - * Get the parameter count of the given prototype. - */ -size_t dexProtoGetParameterCount(const DexProto* pProto); - -/* - * Compute the number of parameter words (u4 units) required by the - * given prototype. For example, if the method takes (int, long) and - * returns double, this would return 3 (one for the int, two for the - * long, and the return type isn't relevant). - */ -int dexProtoComputeArgsSize(const DexProto* pProto); - -/* - * Compare the two prototypes. The two prototypes are compared - * with the return type as the major order, then the first arguments, - * then second, etc. If two prototypes are identical except that one - * has extra arguments, then the shorter argument is considered the - * earlier one in sort order (similar to strcmp()). - */ -int dexProtoCompare(const DexProto* pProto1, const DexProto* pProto2); - -/* - * Compare the two prototypes, ignoring return type. The two - * prototypes are compared with the first argument as the major order, - * then second, etc. If two prototypes are identical except that one - * has extra arguments, then the shorter argument is considered the - * earlier one in sort order (similar to strcmp()). - */ -int dexProtoCompareParameters(const DexProto* pProto1, - const DexProto* pProto2); - -/* - * Compare a prototype and a string method descriptor. The comparison - * is done as if the descriptor were converted to a prototype and compared - * with dexProtoCompare(). - */ -int dexProtoCompareToDescriptor(const DexProto* proto, const char* descriptor); - -/* - * Compare a prototype and a concatenation of type descriptors. The - * comparison is done as if the descriptors were converted to a - * prototype and compared with dexProtoCompareParameters(). - */ -int dexProtoCompareToParameterDescriptors(const DexProto* proto, - const char* descriptors); - -/* - * Single-thread prototype parameter iterator. This structure holds a - * pointer to a prototype and its parts, along with a cursor. - */ -struct DexParameterIterator { - const DexProto* proto; - const DexTypeList* parameters; - int parameterCount; - int cursor; -}; - -/* - * Initialize the given DexParameterIterator to be at the start of the - * parameters of the given prototype. - */ -void dexParameterIteratorInit(DexParameterIterator* pIterator, - const DexProto* pProto); - -/* - * Get the type_id index for the next parameter, if any. This returns - * kDexNoIndex if the last parameter has already been consumed. - */ -u4 dexParameterIteratorNextIndex(DexParameterIterator* pIterator); - -/* - * Get the type descriptor for the next parameter, if any. This returns - * NULL if the last parameter has already been consumed. - */ -const char* dexParameterIteratorNextDescriptor( - DexParameterIterator* pIterator); - -#endif // LIBDEX_DEXPROTO_H_ diff --git a/libdex/DexSwapVerify.cpp b/libdex/DexSwapVerify.cpp deleted file mode 100644 index 8ffc74371..000000000 --- a/libdex/DexSwapVerify.cpp +++ /dev/null @@ -1,3070 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * Byte-swapping and verification of dex files. - */ - -#include "DexFile.h" -#include "DexClass.h" -#include "DexDataMap.h" -#include "DexProto.h" -#include "DexUtf.h" -#include "Leb128.h" - -#include <zlib.h> - -#include <stdlib.h> -#include <string.h> - -#define SWAP2(_value) (_value) -#define SWAP4(_value) (_value) -#define SWAP8(_value) (_value) - -#define SWAP_FIELD2(_field) (_field) = SWAP2(_field) -#define SWAP_FIELD4(_field) (_field) = SWAP4(_field) -#define SWAP_FIELD8(_field) (_field) = SWAP8(_field) - -/* - * Some information we pass around to help verify values. - */ -struct CheckState { - const DexHeader* pHeader; - const u1* fileStart; - const u1* fileEnd; // points to fileStart + fileLen - u4 fileLen; - 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; - * initialized immediately before class_def cross-verification, and - * freed immediately after it - */ - u4* pDefinedClassBits; - - const void* previousItem; // set during section iteration -}; - -/* - * Return the file offset of the given pointer. - */ -static inline u4 fileOffset(const CheckState* state, const void* ptr) { - return ((const u1*) ptr) - state->fileStart; -} - -/* - * Return a pointer for the given file offset. - */ -static inline void* filePointer(const CheckState* state, u4 offset) { - return (void*) (state->fileStart + offset); -} - -/* - * Verify that a pointer range, start inclusive to end exclusive, only - * covers bytes in the file and doesn't point beyond the end of the - * file. That is, the start must indicate a valid byte or may point at - * the byte just past the end of the file (but no further), and the - * end must be no less than the start and must also not point beyond - * the byte just past the end of the file. - */ -static inline bool checkPtrRange(const CheckState* state, - const void* start, const void* end, const char* label) { - const void* fileStart = state->fileStart; - const void* fileEnd = state->fileEnd; - if ((start < fileStart) || (start > fileEnd) - || (end < start) || (end > fileEnd)) { - ALOGW("Bad offset range for %s: %#x..%#x", label, - fileOffset(state, start), fileOffset(state, end)); - return false; - } - return true; -} - -/* - * Verify that a range of offsets, start inclusive to end exclusive, - * are all valid. That is, the start must indicate a valid byte or may - * point at the byte just past the end of the file (but no further), - * and the end must be no less than the start and must also not point - * beyond the byte just past the end of the file. - * - * Assumes "const CheckState* state". - */ -#define CHECK_OFFSET_RANGE(_start, _end) { \ - const u1* _startPtr = (const u1*) filePointer(state, (_start)); \ - const u1* _endPtr = (const u1*) filePointer(state, (_end)); \ - if (!checkPtrRange(state, _startPtr, _endPtr, \ - #_start ".." #_end)) { \ - return 0; \ - } \ - } - -/* - * Verify that a pointer range, start inclusive to end exclusive, only - * covers bytes in the file and doesn't point beyond the end of the - * file. That is, the start must indicate a valid byte or may point at - * the byte just past the end of the file (but no further), and the - * end must be no less than the start and must also not point beyond - * the byte just past the end of the file. - * - * Assumes "const CheckState* state". - */ -#define CHECK_PTR_RANGE(_start, _end) { \ - if (!checkPtrRange(state, (_start), (_end), #_start ".." #_end)) { \ - return 0; \ - } \ - } - -/* - * Make sure a list of items fits entirely within the file. - * - * Assumes "const CheckState* state" and "typeof(_count) == typeof(_elemSize)" - * If the type sizes or signs are mismatched, this will return 0. - */ -#define CHECK_LIST_SIZE(_ptr, _count, _elemSize) { \ - const u1* _start = (const u1*) (_ptr); \ - const u1* _end = _start + ((_count) * (_elemSize)); \ - u4 _dummy; \ - if (__builtin_mul_overflow((_count), (_elemSize), &_dummy) || \ - !checkPtrRange(state, _start, _end, #_ptr)) { \ - return 0; \ - } \ - } - -/* - * Swap a field that is known to hold an absolute DEX file offset. Note: - * This does not check to see that the swapped offset points within the - * mapped file, since that should be handled (with even more rigor) by - * the cross-verification phase. - * - * Assumes "const CheckState* state". - */ -#define SWAP_OFFSET4(_field) { \ - SWAP_FIELD4((_field)); \ - } - -/* - * Verify that an index falls in a valid range. - */ -#define CHECK_INDEX(_field, _limit) { \ - if ((_field) >= (_limit)) { \ - ALOGW("Bad index: %s(%u) > %s(%u)", \ - #_field, (u4)(_field), #_limit, (u4)(_limit)); \ - return 0; \ - } \ - } - -/* - * Swap an index, and verify that it falls in a valid range. - */ -#define SWAP_INDEX2(_field, _limit) { \ - SWAP_FIELD2((_field)); \ - CHECK_INDEX((_field), (_limit)); \ - } - -/* - * Verify that an index falls in a valid range or is kDexNoIndex. - */ -#define CHECK_INDEX_OR_NOINDEX(_field, _limit) { \ - if ((_field) != kDexNoIndex && (_field) >= (_limit)) { \ - ALOGW("Bad index: %s(%u) > %s(%u)", \ - #_field, (u4)(_field), #_limit, (u4)(_limit)); \ - return 0; \ - } \ - } - -/* - * Swap an index, and verify that it falls in a valid range. - */ -#define SWAP_INDEX4(_field, _limit) { \ - SWAP_FIELD4((_field)); \ - CHECK_INDEX((_field), (_limit)); \ - } - -/* - * Swap an index, and verify that it falls in a valid range or is - * kDexNoIndex. - */ -#define SWAP_INDEX4_OR_NOINDEX(_field, _limit) { \ - SWAP_FIELD4((_field)); \ - CHECK_INDEX_OR_NOINDEX((_field), (_limit)); \ - } - -/* Verify the definer of a given field_idx. */ -static bool verifyFieldDefiner(const CheckState* state, u4 definingClass, - u4 fieldIdx) { - const DexFieldId* field = dexGetFieldId(state->pDexFile, fieldIdx); - return field->classIdx == definingClass; -} - -/* Verify the definer of a given method_idx. */ -static bool verifyMethodDefiner(const CheckState* state, u4 definingClass, - u4 methodIdx) { - const DexMethodId* meth = dexGetMethodId(state->pDexFile, methodIdx); - return meth->classIdx == definingClass; -} - -/* - * Calculate the required size (in elements) of the array pointed at by - * pDefinedClassBits. - */ -static size_t calcDefinedClassBitsSize(const CheckState* state) -{ - // Divide typeIdsSize by 32 (0x20), rounding up. - return (state->pHeader->typeIdsSize + 0x1f) >> 5; -} - -/* - * Set the given bit in pDefinedClassBits, returning its former value. - */ -static bool setDefinedClassBit(const CheckState* state, u4 typeIdx) { - u4 arrayIdx = typeIdx >> 5; - u4 bit = 1 << (typeIdx & 0x1f); - u4* element = &state->pDefinedClassBits[arrayIdx]; - bool result = (*element & bit) != 0; - - *element |= bit; - - return result; -} - -/* - * Swap the header_item. - */ -static bool swapDexHeader(const CheckState* state, DexHeader* pHeader) -{ - CHECK_PTR_RANGE(pHeader, pHeader + 1); - - // magic is ok - SWAP_FIELD4(pHeader->checksum); - // signature is ok - SWAP_FIELD4(pHeader->fileSize); - SWAP_FIELD4(pHeader->headerSize); - SWAP_FIELD4(pHeader->endianTag); - SWAP_FIELD4(pHeader->linkSize); - SWAP_OFFSET4(pHeader->linkOff); - SWAP_OFFSET4(pHeader->mapOff); - SWAP_FIELD4(pHeader->stringIdsSize); - SWAP_OFFSET4(pHeader->stringIdsOff); - SWAP_FIELD4(pHeader->typeIdsSize); - SWAP_OFFSET4(pHeader->typeIdsOff); - SWAP_FIELD4(pHeader->fieldIdsSize); - SWAP_OFFSET4(pHeader->fieldIdsOff); - SWAP_FIELD4(pHeader->methodIdsSize); - SWAP_OFFSET4(pHeader->methodIdsOff); - SWAP_FIELD4(pHeader->protoIdsSize); - SWAP_OFFSET4(pHeader->protoIdsOff); - SWAP_FIELD4(pHeader->classDefsSize); - SWAP_OFFSET4(pHeader->classDefsOff); - SWAP_FIELD4(pHeader->dataSize); - SWAP_OFFSET4(pHeader->dataOff); - - if (pHeader->endianTag != kDexEndianConstant) { - ALOGE("Unexpected endian_tag: %#x", pHeader->endianTag); - return false; - } - - // Assign variables so the diagnostic is prettier. (Hooray for macros.) - u4 linkOff = pHeader->linkOff; - u4 linkEnd = linkOff + pHeader->linkSize; - u4 dataOff = pHeader->dataOff; - u4 dataEnd = dataOff + pHeader->dataSize; - CHECK_OFFSET_RANGE(linkOff, linkEnd); - CHECK_OFFSET_RANGE(dataOff, dataEnd); - - /* - * Note: The offsets and ranges of the other header items end up getting - * checked during the first iteration over the map. - */ - - return true; -} - -/* Check the header section for sanity. */ -static bool checkHeaderSection(const CheckState* state, u4 sectionOffset, - u4 sectionCount, u4* endOffset) { - if (sectionCount != 1) { - ALOGE("Multiple header items"); - return false; - } - - if (sectionOffset != 0) { - ALOGE("Header at %#x; not at start of file", sectionOffset); - return false; - } - - const DexHeader* pHeader = (const DexHeader*) filePointer(state, 0); - *endOffset = pHeader->headerSize; - return true; -} - -/* - * Helper for swapMap(), which turns a map type constant into a small - * one-bit-on integer, suitable for use in an int-sized bit set. - */ -static u4 mapTypeToBitMask(int mapType) { - switch (mapType) { - case kDexTypeHeaderItem: return 1 << 0; - case kDexTypeStringIdItem: return 1 << 1; - case kDexTypeTypeIdItem: return 1 << 2; - case kDexTypeProtoIdItem: return 1 << 3; - case kDexTypeFieldIdItem: return 1 << 4; - case kDexTypeMethodIdItem: return 1 << 5; - case kDexTypeClassDefItem: return 1 << 6; - case kDexTypeMapList: return 1 << 7; - case kDexTypeTypeList: return 1 << 8; - case kDexTypeAnnotationSetRefList: return 1 << 9; - case kDexTypeAnnotationSetItem: return 1 << 10; - case kDexTypeClassDataItem: return 1 << 11; - case kDexTypeCodeItem: return 1 << 12; - case kDexTypeStringDataItem: return 1 << 13; - case kDexTypeDebugInfoItem: return 1 << 14; - 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; - } - } -} - -/* - * Helper for swapMap(), which indicates if an item type should appear - * in the data section. - */ -static bool isDataSectionType(int mapType) { - switch (mapType) { - case kDexTypeHeaderItem: - case kDexTypeStringIdItem: - case kDexTypeTypeIdItem: - case kDexTypeProtoIdItem: - case kDexTypeFieldIdItem: - case kDexTypeMethodIdItem: - case kDexTypeClassDefItem: { - return false; - } - } - - return true; -} - -/* - * Swap the map_list and verify what we can about it. Also, if verification - * passes, allocate the state's DexDataMap. - */ -static bool swapMap(CheckState* state, DexMapList* pMap) -{ - DexMapItem* item = pMap->list; - u4 count; - u4 dataItemCount = 0; // Total count of items in the data section. - u4 dataItemsLeft = state->pHeader->dataSize; // See use below. - u4 usedBits = 0; // Bit set: one bit per section - bool first = true; - u4 lastOffset = 0; - - SWAP_FIELD4(pMap->size); - count = pMap->size; - const u4 sizeOfItem = (u4) sizeof(DexMapItem); - CHECK_LIST_SIZE(item, count, sizeOfItem); - - while (count--) { - SWAP_FIELD2(item->type); - SWAP_FIELD2(item->unused); - SWAP_FIELD4(item->size); - SWAP_OFFSET4(item->offset); - - if (first) { - first = false; - } else if (lastOffset >= item->offset) { - ALOGE("Out-of-order map item: %#x then %#x", - lastOffset, item->offset); - return false; - } - - if (item->offset >= state->pHeader->fileSize) { - ALOGE("Map item after end of file: %x, size %#x", - item->offset, state->pHeader->fileSize); - return false; - } - - if (isDataSectionType(item->type)) { - u4 icount = item->size; - - /* - * This sanity check on the data section items ensures that - * there are no more items than the number of bytes in - * the data section. - */ - if (icount > dataItemsLeft) { - ALOGE("Unrealistically many items in the data section: " - "at least %d", dataItemCount + icount); - return false; - } - - dataItemsLeft -= icount; - dataItemCount += icount; - } - - u4 bit = mapTypeToBitMask(item->type); - - if (bit == 0) { - return false; - } - - if ((usedBits & bit) != 0) { - ALOGE("Duplicate map section of type %#x", item->type); - return false; - } - - if (item->type == kDexTypeCallSiteIdItem) { - state->pCallSiteIds = item; - } else if (item->type == kDexTypeMethodHandleItem) { - state->pMethodHandleItems = item; - } - - usedBits |= bit; - lastOffset = item->offset; - item++; - } - - if ((usedBits & mapTypeToBitMask(kDexTypeHeaderItem)) == 0) { - ALOGE("Map is missing header entry"); - return false; - } - - if ((usedBits & mapTypeToBitMask(kDexTypeMapList)) == 0) { - ALOGE("Map is missing map_list entry"); - return false; - } - - if (((usedBits & mapTypeToBitMask(kDexTypeStringIdItem)) == 0) - && ((state->pHeader->stringIdsOff != 0) - || (state->pHeader->stringIdsSize != 0))) { - ALOGE("Map is missing string_ids entry"); - return false; - } - - if (((usedBits & mapTypeToBitMask(kDexTypeTypeIdItem)) == 0) - && ((state->pHeader->typeIdsOff != 0) - || (state->pHeader->typeIdsSize != 0))) { - ALOGE("Map is missing type_ids entry"); - return false; - } - - if (((usedBits & mapTypeToBitMask(kDexTypeProtoIdItem)) == 0) - && ((state->pHeader->protoIdsOff != 0) - || (state->pHeader->protoIdsSize != 0))) { - ALOGE("Map is missing proto_ids entry"); - return false; - } - - if (((usedBits & mapTypeToBitMask(kDexTypeFieldIdItem)) == 0) - && ((state->pHeader->fieldIdsOff != 0) - || (state->pHeader->fieldIdsSize != 0))) { - ALOGE("Map is missing field_ids entry"); - return false; - } - - if (((usedBits & mapTypeToBitMask(kDexTypeMethodIdItem)) == 0) - && ((state->pHeader->methodIdsOff != 0) - || (state->pHeader->methodIdsSize != 0))) { - ALOGE("Map is missing method_ids entry"); - return false; - } - - if (((usedBits & mapTypeToBitMask(kDexTypeClassDefItem)) == 0) - && ((state->pHeader->classDefsOff != 0) - || (state->pHeader->classDefsSize != 0))) { - ALOGE("Map is missing class_defs entry"); - return false; - } - - state->pDataMap = dexDataMapAlloc(dataItemCount); - if (state->pDataMap == NULL) { - ALOGE("Unable to allocate data map (size %#x)", dataItemCount); - return false; - } - - return true; -} - -/* Check the map section for sanity. */ -static bool checkMapSection(const CheckState* state, u4 sectionOffset, - u4 sectionCount, u4* endOffset) { - if (sectionCount != 1) { - ALOGE("Multiple map list items"); - return false; - } - - if (sectionOffset != state->pHeader->mapOff) { - ALOGE("Map not at header-defined offset: %#x, expected %#x", - sectionOffset, state->pHeader->mapOff); - return false; - } - - const DexMapList* pMap = (const DexMapList*) filePointer(state, sectionOffset); - - *endOffset = - sectionOffset + sizeof(u4) + (pMap->size * sizeof(DexMapItem)); - return true; -} - -/* Perform byte-swapping and intra-item verification on string_id_item. */ -static void* swapStringIdItem(const CheckState* state, void* ptr) { - DexStringId* item = (DexStringId*) ptr; - - CHECK_PTR_RANGE(item, item + 1); - SWAP_OFFSET4(item->stringDataOff); - - return item + 1; -} - -/* Perform cross-item verification of string_id_item. */ -static void* crossVerifyStringIdItem(const CheckState* state, void* ptr) { - const DexStringId* item = (const DexStringId*) ptr; - - if (!dexDataMapVerify(state->pDataMap, - item->stringDataOff, kDexTypeStringDataItem)) { - return NULL; - } - - const DexStringId* item0 = (const DexStringId*) state->previousItem; - if (item0 != NULL) { - // Check ordering. - const char* s0 = dexGetStringData(state->pDexFile, item0); - const char* s1 = dexGetStringData(state->pDexFile, item); - if (dexUtf8Cmp(s0, s1) >= 0) { - ALOGE("Out-of-order string_ids: '%s' then '%s'", s0, s1); - return NULL; - } - } - - return (void*) (item + 1); -} - -/* Perform byte-swapping and intra-item verification on type_id_item. */ -static void* swapTypeIdItem(const CheckState* state, void* ptr) { - DexTypeId* item = (DexTypeId*) ptr; - - CHECK_PTR_RANGE(item, item + 1); - SWAP_INDEX4(item->descriptorIdx, state->pHeader->stringIdsSize); - - return item + 1; -} - -/* Perform cross-item verification of type_id_item. */ -static void* crossVerifyTypeIdItem(const CheckState* state, void* ptr) { - const DexTypeId* item = (const DexTypeId*) ptr; - const char* descriptor = - dexStringById(state->pDexFile, item->descriptorIdx); - - if (!dexIsValidTypeDescriptor(descriptor)) { - ALOGE("Invalid type descriptor: '%s'", descriptor); - return NULL; - } - - const DexTypeId* item0 = (const DexTypeId*) state->previousItem; - if (item0 != NULL) { - // Check ordering. This relies on string_ids being in order. - if (item0->descriptorIdx >= item->descriptorIdx) { - ALOGE("Out-of-order type_ids: %#x then %#x", - item0->descriptorIdx, item->descriptorIdx); - return NULL; - } - } - - return (void*) (item + 1); -} - -/* Perform byte-swapping and intra-item verification on proto_id_item. */ -static void* swapProtoIdItem(const CheckState* state, void* ptr) { - DexProtoId* item = (DexProtoId*) ptr; - - CHECK_PTR_RANGE(item, item + 1); - SWAP_INDEX4(item->shortyIdx, state->pHeader->stringIdsSize); - SWAP_INDEX4(item->returnTypeIdx, state->pHeader->typeIdsSize); - SWAP_OFFSET4(item->parametersOff); - - return item + 1; -} - -/* Helper for crossVerifyProtoIdItem(), which checks a shorty character - * to see if it is compatible with a type descriptor. Returns true if - * so, false if not. */ -static bool shortyDescMatch(char shorty, const char* descriptor, bool - isReturnType) { - switch (shorty) { - case 'V': { - if (!isReturnType) { - ALOGE("Invalid use of void"); - return false; - } - FALLTHROUGH_INTENDED; - } - case 'B': - case 'C': - case 'D': - case 'F': - case 'I': - case 'J': - case 'S': - case 'Z': { - if ((descriptor[0] != shorty) || (descriptor[1] != '\0')) { - ALOGE("Shorty vs. primitive type mismatch: '%c', '%s'", - shorty, descriptor); - return false; - } - break; - } - case 'L': { - if ((descriptor[0] != 'L') && (descriptor[0] != '[')) { - ALOGE("Shorty vs. type mismatch: '%c', '%s'", - shorty, descriptor); - return false; - } - break; - } - default: { - ALOGE("Bogus shorty: '%c'", shorty); - return false; - } - } - - return true; -} - -/* Perform cross-item verification of proto_id_item. */ -static void* crossVerifyProtoIdItem(const CheckState* state, void* ptr) { - const DexProtoId* item = (const DexProtoId*) ptr; - const char* shorty = - dexStringById(state->pDexFile, item->shortyIdx); - - if (!dexDataMapVerify0Ok(state->pDataMap, - item->parametersOff, kDexTypeTypeList)) { - return NULL; - } - - if (!shortyDescMatch(*shorty, - dexStringByTypeIdx(state->pDexFile, item->returnTypeIdx), - true)) { - return NULL; - } - - u4 protoIdx = item - state->pDexFile->pProtoIds; - DexProto proto = { state->pDexFile, protoIdx }; - DexParameterIterator iterator; - - dexParameterIteratorInit(&iterator, &proto); - shorty++; // Skip the return type. - - for (;;) { - const char *desc = dexParameterIteratorNextDescriptor(&iterator); - - if (desc == NULL) { - break; - } - - if (*shorty == '\0') { - ALOGE("Shorty is too short"); - return NULL; - } - - if (!shortyDescMatch(*shorty, desc, false)) { - return NULL; - } - - shorty++; - } - - if (*shorty != '\0') { - ALOGE("Shorty is too long"); - return NULL; - } - - const DexProtoId* item0 = (const DexProtoId*) state->previousItem; - if (item0 != NULL) { - // Check ordering. This relies on type_ids being in order. - if (item0->returnTypeIdx > item->returnTypeIdx) { - ALOGE("Out-of-order proto_id return types"); - return NULL; - } else if (item0->returnTypeIdx == item->returnTypeIdx) { - bool badOrder = false; - DexProto proto0 = { state->pDexFile, protoIdx - 1 }; - DexParameterIterator iterator0; - - dexParameterIteratorInit(&iterator, &proto); - dexParameterIteratorInit(&iterator0, &proto0); - - for (;;) { - u4 idx0 = dexParameterIteratorNextIndex(&iterator0); - u4 idx1 = dexParameterIteratorNextIndex(&iterator); - - if (idx1 == kDexNoIndex) { - badOrder = true; - break; - } - - if (idx0 == kDexNoIndex) { - break; - } - - if (idx0 < idx1) { - break; - } else if (idx0 > idx1) { - badOrder = true; - break; - } - } - - if (badOrder) { - ALOGE("Out-of-order proto_id arguments"); - return NULL; - } - } - } - - return (void*) (item + 1); -} - -/* Perform byte-swapping and intra-item verification on field_id_item. */ -static void* swapFieldIdItem(const CheckState* state, void* ptr) { - DexFieldId* item = (DexFieldId*) ptr; - - CHECK_PTR_RANGE(item, item + 1); - SWAP_INDEX2(item->classIdx, state->pHeader->typeIdsSize); - SWAP_INDEX2(item->typeIdx, state->pHeader->typeIdsSize); - SWAP_INDEX4(item->nameIdx, state->pHeader->stringIdsSize); - - return item + 1; -} - -/* Perform cross-item verification of field_id_item. */ -static void* crossVerifyFieldIdItem(const CheckState* state, void* ptr) { - const DexFieldId* item = (const DexFieldId*) ptr; - const char* s; - - s = dexStringByTypeIdx(state->pDexFile, item->classIdx); - if (!dexIsClassDescriptor(s)) { - ALOGE("Invalid descriptor for class_idx: '%s'", s); - return NULL; - } - - s = dexStringByTypeIdx(state->pDexFile, item->typeIdx); - if (!dexIsFieldDescriptor(s)) { - ALOGE("Invalid descriptor for type_idx: '%s'", s); - return NULL; - } - - s = dexStringById(state->pDexFile, item->nameIdx); - if (!dexIsValidMemberName(s)) { - ALOGE("Invalid name: '%s'", s); - return NULL; - } - - const DexFieldId* item0 = (const DexFieldId*) state->previousItem; - if (item0 != NULL) { - // Check ordering. This relies on the other sections being in order. - bool done = false; - bool bogus = false; - - if (item0->classIdx > item->classIdx) { - bogus = true; - done = true; - } else if (item0->classIdx < item->classIdx) { - done = true; - } - - if (!done) { - if (item0->nameIdx > item->nameIdx) { - bogus = true; - done = true; - } else if (item0->nameIdx < item->nameIdx) { - done = true; - } - } - - if (!done) { - if (item0->typeIdx >= item->typeIdx) { - bogus = true; - } - } - - if (bogus) { - ALOGE("Out-of-order field_ids"); - return NULL; - } - } - - return (void*) (item + 1); -} - -/* Perform byte-swapping and intra-item verification on method_id_item. */ -static void* swapMethodIdItem(const CheckState* state, void* ptr) { - DexMethodId* item = (DexMethodId*) ptr; - - CHECK_PTR_RANGE(item, item + 1); - SWAP_INDEX2(item->classIdx, state->pHeader->typeIdsSize); - SWAP_INDEX2(item->protoIdx, state->pHeader->protoIdsSize); - SWAP_INDEX4(item->nameIdx, state->pHeader->stringIdsSize); - - return item + 1; -} - -/* Perform cross-item verification of method_id_item. */ -static void* crossVerifyMethodIdItem(const CheckState* state, void* ptr) { - const DexMethodId* item = (const DexMethodId*) ptr; - const char* s; - - s = dexStringByTypeIdx(state->pDexFile, item->classIdx); - if (!dexIsReferenceDescriptor(s)) { - ALOGE("Invalid descriptor for class_idx: '%s'", s); - return NULL; - } - - s = dexStringById(state->pDexFile, item->nameIdx); - if (!dexIsValidMemberName(s)) { - ALOGE("Invalid name: '%s'", s); - return NULL; - } - - const DexMethodId* item0 = (const DexMethodId*) state->previousItem; - if (item0 != NULL) { - // Check ordering. This relies on the other sections being in order. - bool done = false; - bool bogus = false; - - if (item0->classIdx > item->classIdx) { - bogus = true; - done = true; - } else if (item0->classIdx < item->classIdx) { - done = true; - } - - if (!done) { - if (item0->nameIdx > item->nameIdx) { - bogus = true; - done = true; - } else if (item0->nameIdx < item->nameIdx) { - done = true; - } - } - - if (!done) { - if (item0->protoIdx >= item->protoIdx) { - bogus = true; - } - } - - if (bogus) { - ALOGE("Out-of-order method_ids"); - return NULL; - } - } - - return (void*) (item + 1); -} - -/* Perform byte-swapping and intra-item verification on class_def_item. */ -static void* swapClassDefItem(const CheckState* state, void* ptr) { - DexClassDef* item = (DexClassDef*) ptr; - - CHECK_PTR_RANGE(item, item + 1); - SWAP_INDEX4(item->classIdx, state->pHeader->typeIdsSize); - SWAP_FIELD4(item->accessFlags); - SWAP_INDEX4_OR_NOINDEX(item->superclassIdx, state->pHeader->typeIdsSize); - SWAP_OFFSET4(item->interfacesOff); - SWAP_INDEX4_OR_NOINDEX(item->sourceFileIdx, state->pHeader->stringIdsSize); - SWAP_OFFSET4(item->annotationsOff); - SWAP_OFFSET4(item->classDataOff); - - if ((item->accessFlags & ~ACC_CLASS_MASK) != 0) { - // The VM specification says that unknown flags should be ignored. - ALOGV("Bogus class access flags %x", item->accessFlags); - item->accessFlags &= ACC_CLASS_MASK; - } - - return item + 1; -} - -/* defined below */ -static u4 findFirstClassDataDefiner(const CheckState* state, - DexClassData* classData); -static u4 findFirstAnnotationsDirectoryDefiner(const CheckState* state, - const DexAnnotationsDirectoryItem* dir); - -/* Helper for crossVerifyClassDefItem(), which checks a class_data_item to - * make sure all its references are to a given class. */ -static bool verifyClassDataIsForDef(const CheckState* state, u4 offset, - u4 definerIdx) { - if (offset == 0) { - return true; - } - - const u1* data = (const u1*) filePointer(state, offset); - DexClassData* classData = dexReadAndVerifyClassData(&data, NULL); - - if (classData == NULL) { - // Shouldn't happen, but bail here just in case. - return false; - } - - /* - * The class_data_item verification ensures that - * it consistently refers to the same definer, so all we need to - * do is check the first one. - */ - u4 dataDefiner = findFirstClassDataDefiner(state, classData); - bool result = (dataDefiner == definerIdx) || (dataDefiner == kDexNoIndex); - - free(classData); - return result; -} - -/* Helper for crossVerifyClassDefItem(), which checks an - * annotations_directory_item to make sure all its references are to a - * given class. */ -static bool verifyAnnotationsDirectoryIsForDef(const CheckState* state, - u4 offset, u4 definerIdx) { - if (offset == 0) { - return true; - } - - const DexAnnotationsDirectoryItem* dir = - (const DexAnnotationsDirectoryItem*) filePointer(state, offset); - u4 annoDefiner = findFirstAnnotationsDirectoryDefiner(state, dir); - - return (annoDefiner == definerIdx) || (annoDefiner == kDexNoIndex); -} - -/* Perform cross-item verification of class_def_item. */ -static void* crossVerifyClassDefItem(const CheckState* state, void* ptr) { - const DexClassDef* item = (const DexClassDef*) ptr; - u4 classIdx = item->classIdx; - const char* descriptor = dexStringByTypeIdx(state->pDexFile, classIdx); - - if (!dexIsClassDescriptor(descriptor)) { - ALOGE("Invalid class: '%s'", descriptor); - return NULL; - } - - if (setDefinedClassBit(state, classIdx)) { - ALOGE("Duplicate class definition: '%s'", descriptor); - return NULL; - } - - bool okay = - dexDataMapVerify0Ok(state->pDataMap, - item->interfacesOff, kDexTypeTypeList) - && dexDataMapVerify0Ok(state->pDataMap, - item->annotationsOff, kDexTypeAnnotationsDirectoryItem) - && dexDataMapVerify0Ok(state->pDataMap, - item->classDataOff, kDexTypeClassDataItem) - && dexDataMapVerify0Ok(state->pDataMap, - item->staticValuesOff, kDexTypeEncodedArrayItem); - - if (!okay) { - return NULL; - } - - if (item->superclassIdx != kDexNoIndex) { - descriptor = dexStringByTypeIdx(state->pDexFile, item->superclassIdx); - if (!dexIsClassDescriptor(descriptor)) { - ALOGE("Invalid superclass: '%s'", descriptor); - return NULL; - } - } - - const DexTypeList* interfaces = - dexGetInterfacesList(state->pDexFile, item); - if (interfaces != NULL) { - u4 size = interfaces->size; - u4 i; - - /* - * Ensure that all interfaces refer to classes (not arrays or - * primitives). - */ - for (i = 0; i < size; i++) { - descriptor = dexStringByTypeIdx(state->pDexFile, - dexTypeListGetIdx(interfaces, i)); - if (!dexIsClassDescriptor(descriptor)) { - ALOGE("Invalid interface: '%s'", descriptor); - return NULL; - } - } - - /* - * Ensure that there are no duplicates. This is an O(N^2) test, - * but in practice the number of interfaces implemented by any - * given class is low. I will buy a milkshake for the - * first person to show me a realistic case for which this test - * would be unacceptably slow. - */ - for (i = 1; i < size; i++) { - u4 idx1 = dexTypeListGetIdx(interfaces, i); - u4 j; - for (j = 0; j < i; j++) { - u4 idx2 = dexTypeListGetIdx(interfaces, j); - if (idx1 == idx2) { - ALOGE("Duplicate interface: '%s'", - dexStringByTypeIdx(state->pDexFile, idx1)); - return NULL; - } - } - } - } - - if (!verifyClassDataIsForDef(state, item->classDataOff, item->classIdx)) { - ALOGE("Invalid class_data_item"); - return NULL; - } - - if (!verifyAnnotationsDirectoryIsForDef(state, item->annotationsOff, - item->classIdx)) { - ALOGE("Invalid annotations_directory_item"); - return NULL; - } - - 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 > (u2) MethodHandleType::INVOKE_INTERFACE) { - ALOGE("Unknown method handle type: %u", item->methodHandleType); - return NULL; - } - switch ((MethodHandleType) item->methodHandleType) { - case MethodHandleType::STATIC_PUT: - case MethodHandleType::STATIC_GET: - case MethodHandleType::INSTANCE_PUT: - case MethodHandleType::INSTANCE_GET: - if (item->fieldOrMethodIdx >= state->pHeader->fieldIdsSize) { - ALOGE("Method handle has invalid field id: %u\n", item->fieldOrMethodIdx); - return NULL; - } - break; - case MethodHandleType::INVOKE_STATIC: - case MethodHandleType::INVOKE_INSTANCE: - case MethodHandleType::INVOKE_CONSTRUCTOR: - case MethodHandleType::INVOKE_DIRECT: - case MethodHandleType::INVOKE_INTERFACE: - if (item->fieldOrMethodIdx >= state->pHeader->methodIdsSize) { - ALOGE("Method handle has invalid method id: %u\n", item->fieldOrMethodIdx); - return NULL; - } - break; - } - return (void*) (item + 1); -} - -/* Helper for swapAnnotationsDirectoryItem(), which performs - * byte-swapping and intra-item verification on an - * annotation_directory_item's field elements. */ -static u1* swapFieldAnnotations(const CheckState* state, u4 count, u1* addr) { - DexFieldAnnotationsItem* item = (DexFieldAnnotationsItem*) addr; - bool first = true; - u4 lastIdx = 0; - - const u4 sizeOfItem = (u4) sizeof(DexFieldAnnotationsItem); - CHECK_LIST_SIZE(item, count, sizeOfItem); - - while (count--) { - SWAP_INDEX4(item->fieldIdx, state->pHeader->fieldIdsSize); - SWAP_OFFSET4(item->annotationsOff); - - if (first) { - first = false; - } else if (lastIdx >= item->fieldIdx) { - ALOGE("Out-of-order field_idx: %#x then %#x", lastIdx, - item->fieldIdx); - return NULL; - } - - lastIdx = item->fieldIdx; - item++; - } - - return (u1*) item; -} - -/* Helper for swapAnnotationsDirectoryItem(), which performs - * byte-swapping and intra-item verification on an - * annotation_directory_item's method elements. */ -static u1* swapMethodAnnotations(const CheckState* state, u4 count, u1* addr) { - DexMethodAnnotationsItem* item = (DexMethodAnnotationsItem*) addr; - bool first = true; - u4 lastIdx = 0; - - const u4 sizeOfItem = (u4) sizeof(DexMethodAnnotationsItem); - CHECK_LIST_SIZE(item, count, sizeOfItem); - - while (count--) { - SWAP_INDEX4(item->methodIdx, state->pHeader->methodIdsSize); - SWAP_OFFSET4(item->annotationsOff); - - if (first) { - first = false; - } else if (lastIdx >= item->methodIdx) { - ALOGE("Out-of-order method_idx: %#x then %#x", lastIdx, - item->methodIdx); - return NULL; - } - - lastIdx = item->methodIdx; - item++; - } - - return (u1*) item; -} - -/* Helper for swapAnnotationsDirectoryItem(), which performs - * byte-swapping and intra-item verification on an - * annotation_directory_item's parameter elements. */ -static u1* swapParameterAnnotations(const CheckState* state, u4 count, - u1* addr) { - DexParameterAnnotationsItem* item = (DexParameterAnnotationsItem*) addr; - bool first = true; - u4 lastIdx = 0; - - const u4 sizeOfItem = (u4) sizeof(DexParameterAnnotationsItem); - CHECK_LIST_SIZE(item, count, sizeOfItem); - - while (count--) { - SWAP_INDEX4(item->methodIdx, state->pHeader->methodIdsSize); - SWAP_OFFSET4(item->annotationsOff); - - if (first) { - first = false; - } else if (lastIdx >= item->methodIdx) { - ALOGE("Out-of-order method_idx: %#x then %#x", lastIdx, - item->methodIdx); - return NULL; - } - - lastIdx = item->methodIdx; - item++; - } - - return (u1*) item; -} - -/* Perform byte-swapping and intra-item verification on - * annotations_directory_item. */ -static void* swapAnnotationsDirectoryItem(const CheckState* state, void* ptr) { - DexAnnotationsDirectoryItem* item = (DexAnnotationsDirectoryItem*) ptr; - - CHECK_PTR_RANGE(item, item + 1); - SWAP_OFFSET4(item->classAnnotationsOff); - SWAP_FIELD4(item->fieldsSize); - SWAP_FIELD4(item->methodsSize); - SWAP_FIELD4(item->parametersSize); - - u1* addr = (u1*) (item + 1); - - if (item->fieldsSize != 0) { - addr = swapFieldAnnotations(state, item->fieldsSize, addr); - if (addr == NULL) { - return NULL; - } - } - - if (item->methodsSize != 0) { - addr = swapMethodAnnotations(state, item->methodsSize, addr); - if (addr == NULL) { - return NULL; - } - } - - if (item->parametersSize != 0) { - addr = swapParameterAnnotations(state, item->parametersSize, addr); - if (addr == NULL) { - return NULL; - } - } - - 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, - const u1* addr, u4 definingClass) { - const DexFieldAnnotationsItem* item = (DexFieldAnnotationsItem*) addr; - - while (count--) { - if (!verifyFieldDefiner(state, definingClass, item->fieldIdx)) { - return NULL; - } - if (!dexDataMapVerify(state->pDataMap, item->annotationsOff, - kDexTypeAnnotationSetItem)) { - return NULL; - } - item++; - } - - return (const u1*) item; -} - -/* Helper for crossVerifyAnnotationsDirectoryItem(), which checks the - * method elements. */ -static const u1* crossVerifyMethodAnnotations(const CheckState* state, - u4 count, const u1* addr, u4 definingClass) { - const DexMethodAnnotationsItem* item = (DexMethodAnnotationsItem*) addr; - - while (count--) { - if (!verifyMethodDefiner(state, definingClass, item->methodIdx)) { - return NULL; - } - if (!dexDataMapVerify(state->pDataMap, item->annotationsOff, - kDexTypeAnnotationSetItem)) { - return NULL; - } - item++; - } - - return (const u1*) item; -} - -/* Helper for crossVerifyAnnotationsDirectoryItem(), which checks the - * parameter elements. */ -static const u1* crossVerifyParameterAnnotations(const CheckState* state, - u4 count, const u1* addr, u4 definingClass) { - const DexParameterAnnotationsItem* item = - (DexParameterAnnotationsItem*) addr; - - while (count--) { - if (!verifyMethodDefiner(state, definingClass, item->methodIdx)) { - return NULL; - } - if (!dexDataMapVerify(state->pDataMap, item->annotationsOff, - kDexTypeAnnotationSetRefList)) { - return NULL; - } - item++; - } - - return (const u1*) item; -} - -/* Helper for crossVerifyClassDefItem() and - * crossVerifyAnnotationsDirectoryItem(), which finds the type_idx of - * the definer of the first item in the data. */ -static u4 findFirstAnnotationsDirectoryDefiner(const CheckState* state, - const DexAnnotationsDirectoryItem* dir) { - if (dir->fieldsSize != 0) { - const DexFieldAnnotationsItem* fields = - dexGetFieldAnnotations(state->pDexFile, dir); - const DexFieldId* field = - dexGetFieldId(state->pDexFile, fields[0].fieldIdx); - return field->classIdx; - } - - if (dir->methodsSize != 0) { - const DexMethodAnnotationsItem* methods = - dexGetMethodAnnotations(state->pDexFile, dir); - const DexMethodId* method = - dexGetMethodId(state->pDexFile, methods[0].methodIdx); - return method->classIdx; - } - - if (dir->parametersSize != 0) { - const DexParameterAnnotationsItem* parameters = - dexGetParameterAnnotations(state->pDexFile, dir); - const DexMethodId* method = - dexGetMethodId(state->pDexFile, parameters[0].methodIdx); - return method->classIdx; - } - - return kDexNoIndex; -} - -/* Perform cross-item verification of annotations_directory_item. */ -static void* crossVerifyAnnotationsDirectoryItem(const CheckState* state, - void* ptr) { - const DexAnnotationsDirectoryItem* item = (const DexAnnotationsDirectoryItem*) ptr; - u4 definingClass = findFirstAnnotationsDirectoryDefiner(state, item); - - if (!dexDataMapVerify0Ok(state->pDataMap, - item->classAnnotationsOff, kDexTypeAnnotationSetItem)) { - return NULL; - } - - const u1* addr = (const u1*) (item + 1); - - if (item->fieldsSize != 0) { - addr = crossVerifyFieldAnnotations(state, item->fieldsSize, addr, - definingClass); - if (addr == NULL) { - return NULL; - } - } - - if (item->methodsSize != 0) { - addr = crossVerifyMethodAnnotations(state, item->methodsSize, addr, - definingClass); - if (addr == NULL) { - return NULL; - } - } - - if (item->parametersSize != 0) { - addr = crossVerifyParameterAnnotations(state, item->parametersSize, - addr, definingClass); - if (addr == NULL) { - return NULL; - } - } - - return (void*) addr; -} - -/* Perform byte-swapping and intra-item verification on type_list. */ -static void* swapTypeList(const CheckState* state, void* ptr) -{ - DexTypeList* pTypeList = (DexTypeList*) ptr; - DexTypeItem* pType; - u4 count; - - CHECK_PTR_RANGE(pTypeList, pTypeList + 1); - SWAP_FIELD4(pTypeList->size); - count = pTypeList->size; - pType = pTypeList->list; - - const u4 sizeOfItem = (u4) sizeof(DexTypeItem); - CHECK_LIST_SIZE(pType, count, sizeOfItem); - - while (count--) { - SWAP_INDEX2(pType->typeIdx, state->pHeader->typeIdsSize); - pType++; - } - - return pType; -} - -/* Perform byte-swapping and intra-item verification on - * annotation_set_ref_list. */ -static void* swapAnnotationSetRefList(const CheckState* state, void* ptr) { - DexAnnotationSetRefList* list = (DexAnnotationSetRefList*) ptr; - DexAnnotationSetRefItem* item; - u4 count; - - CHECK_PTR_RANGE(list, list + 1); - SWAP_FIELD4(list->size); - count = list->size; - item = list->list; - - const u4 sizeOfItem = (u4) sizeof(DexAnnotationSetRefItem); - CHECK_LIST_SIZE(item, count, sizeOfItem); - - while (count--) { - SWAP_OFFSET4(item->annotationsOff); - item++; - } - - return item; -} - -/* Perform cross-item verification of annotation_set_ref_list. */ -static void* crossVerifyAnnotationSetRefList(const CheckState* state, - void* ptr) { - const DexAnnotationSetRefList* list = (const DexAnnotationSetRefList*) ptr; - const DexAnnotationSetRefItem* item = list->list; - int count = list->size; - - while (count--) { - if (!dexDataMapVerify0Ok(state->pDataMap, - item->annotationsOff, kDexTypeAnnotationSetItem)) { - return NULL; - } - item++; - } - - return (void*) item; -} - -/* Perform byte-swapping and intra-item verification on - * annotation_set_item. */ -static void* swapAnnotationSetItem(const CheckState* state, void* ptr) { - DexAnnotationSetItem* set = (DexAnnotationSetItem*) ptr; - u4* item; - u4 count; - - CHECK_PTR_RANGE(set, set + 1); - SWAP_FIELD4(set->size); - count = set->size; - item = set->entries; - - const u4 sizeOfItem = (u4) sizeof(u4); - CHECK_LIST_SIZE(item, count, sizeOfItem); - - while (count--) { - SWAP_OFFSET4(*item); - item++; - } - - return item; -} - -/* Helper for crossVerifyAnnotationSetItem(), which extracts the type_idx - * out of an annotation_item. */ -static u4 annotationItemTypeIdx(const DexAnnotationItem* item) { - const u1* data = item->annotation; - return readUnsignedLeb128(&data); -} - -/* Perform cross-item verification of annotation_set_item. */ -static void* crossVerifyAnnotationSetItem(const CheckState* state, void* ptr) { - const DexAnnotationSetItem* set = (const DexAnnotationSetItem*) ptr; - int count = set->size; - u4 lastIdx = 0; - bool first = true; - int i; - - for (i = 0; i < count; i++) { - if (!dexDataMapVerify0Ok(state->pDataMap, - dexGetAnnotationOff(set, i), kDexTypeAnnotationItem)) { - return NULL; - } - - const DexAnnotationItem* annotation = - dexGetAnnotationItem(state->pDexFile, set, i); - u4 idx = annotationItemTypeIdx(annotation); - - if (first) { - first = false; - } else if (lastIdx >= idx) { - ALOGE("Out-of-order entry types: %#x then %#x", - lastIdx, idx); - return NULL; - } - - lastIdx = idx; - } - - return (void*) (set->entries + count); -} - -/* Helper for verifyClassDataItem(), which checks a list of fields. */ -static bool verifyFields(const CheckState* state, u4 size, - DexField* fields, bool expectStatic) { - u4 i; - - for (i = 0; i < size; i++) { - DexField* field = &fields[i]; - u4 accessFlags = field->accessFlags; - bool isStatic = (accessFlags & ACC_STATIC) != 0; - - CHECK_INDEX(field->fieldIdx, state->pHeader->fieldIdsSize); - - if (isStatic != expectStatic) { - ALOGE("Field in wrong list @ %d", i); - return false; - } - - if ((accessFlags & ~ACC_FIELD_MASK) != 0) { - // The VM specification says that unknown flags should be ignored. - ALOGV("Bogus field access flags %x @ %d", accessFlags, i); - field->accessFlags &= ACC_FIELD_MASK; - } - } - - return true; -} - -/* Helper for verifyClassDataItem(), which checks a list of methods. */ -static bool verifyMethods(const CheckState* state, u4 size, - DexMethod* methods, bool expectDirect) { - u4 i; - - for (i = 0; i < size; i++) { - DexMethod* method = &methods[i]; - - CHECK_INDEX(method->methodIdx, state->pHeader->methodIdsSize); - - u4 accessFlags = method->accessFlags; - bool isDirect = - (accessFlags & (ACC_STATIC | ACC_PRIVATE | ACC_CONSTRUCTOR)) != 0; - bool expectCode = (accessFlags & (ACC_NATIVE | ACC_ABSTRACT)) == 0; - bool isSynchronized = (accessFlags & ACC_SYNCHRONIZED) != 0; - bool allowSynchronized = (accessFlags & ACC_NATIVE) != 0; - - if (isDirect != expectDirect) { - ALOGE("Method in wrong list @ %d", i); - return false; - } - - if (isSynchronized && !allowSynchronized) { - ALOGE("Bogus method access flags (synchronization) %x @ %d", accessFlags, i); - return false; - } - - if ((accessFlags & ~ACC_METHOD_MASK) != 0) { - // The VM specification says that unknown flags should be ignored. - ALOGV("Bogus method access flags %x @ %d", accessFlags, i); - method->accessFlags &= ACC_METHOD_MASK; - } - - if (expectCode) { - if (method->codeOff == 0) { - ALOGE("Unexpected zero code_off for access_flags %x", - accessFlags); - return false; - } - } else if (method->codeOff != 0) { - ALOGE("Unexpected non-zero code_off %#x for access_flags %x", - method->codeOff, accessFlags); - return false; - } - } - - return true; -} - -/* Helper for verifyClassDataItem(), which does most of the work. */ -static bool verifyClassDataItem0(const CheckState* state, - DexClassData* classData) { - bool okay; - - okay = verifyFields(state, classData->header.staticFieldsSize, - classData->staticFields, true); - - if (!okay) { - ALOGE("Trouble with static fields"); - return false; - } - - verifyFields(state, classData->header.instanceFieldsSize, - classData->instanceFields, false); - - if (!okay) { - ALOGE("Trouble with instance fields"); - return false; - } - - okay = verifyMethods(state, classData->header.directMethodsSize, - classData->directMethods, true); - - if (!okay) { - ALOGE("Trouble with direct methods"); - return false; - } - - okay = verifyMethods(state, classData->header.virtualMethodsSize, - classData->virtualMethods, false); - - if (!okay) { - ALOGE("Trouble with virtual methods"); - return false; - } - - return true; -} - -/* Perform intra-item verification on class_data_item. */ -static void* intraVerifyClassDataItem(const CheckState* state, void* ptr) { - const u1* data = (const u1*) ptr; - DexClassData* classData = dexReadAndVerifyClassData(&data, state->fileEnd); - - if (classData == NULL) { - ALOGE("Unable to parse class_data_item"); - return NULL; - } - - bool okay = verifyClassDataItem0(state, classData); - - free(classData); - - if (!okay) { - return NULL; - } - - return (void*) data; -} - -/* Helper for crossVerifyClassDefItem() and - * crossVerifyClassDataItem(), which finds the type_idx of the definer - * of the first item in the data. */ -static u4 findFirstClassDataDefiner(const CheckState* state, - DexClassData* classData) { - if (classData->header.staticFieldsSize != 0) { - u4 fieldIdx = classData->staticFields[0].fieldIdx; - const DexFieldId* field = dexGetFieldId(state->pDexFile, fieldIdx); - return field->classIdx; - } - - if (classData->header.instanceFieldsSize != 0) { - u4 fieldIdx = classData->instanceFields[0].fieldIdx; - const DexFieldId* field = dexGetFieldId(state->pDexFile, fieldIdx); - return field->classIdx; - } - - if (classData->header.directMethodsSize != 0) { - u4 methodIdx = classData->directMethods[0].methodIdx; - const DexMethodId* meth = dexGetMethodId(state->pDexFile, methodIdx); - return meth->classIdx; - } - - if (classData->header.virtualMethodsSize != 0) { - u4 methodIdx = classData->virtualMethods[0].methodIdx; - const DexMethodId* meth = dexGetMethodId(state->pDexFile, methodIdx); - return meth->classIdx; - } - - return kDexNoIndex; -} - -/* Perform cross-item verification of class_data_item. */ -static void* crossVerifyClassDataItem(const CheckState* state, void* ptr) { - const u1* data = (const u1*) ptr; - DexClassData* classData = dexReadAndVerifyClassData(&data, state->fileEnd); - u4 definingClass = findFirstClassDataDefiner(state, classData); - bool okay = true; - u4 i; - - for (i = classData->header.staticFieldsSize; okay && (i > 0); /*i*/) { - i--; - const DexField* field = &classData->staticFields[i]; - okay = verifyFieldDefiner(state, definingClass, field->fieldIdx); - } - - for (i = classData->header.instanceFieldsSize; okay && (i > 0); /*i*/) { - i--; - const DexField* field = &classData->instanceFields[i]; - okay = verifyFieldDefiner(state, definingClass, field->fieldIdx); - } - - for (i = classData->header.directMethodsSize; okay && (i > 0); /*i*/) { - i--; - const DexMethod* meth = &classData->directMethods[i]; - okay = dexDataMapVerify0Ok(state->pDataMap, meth->codeOff, - kDexTypeCodeItem) - && verifyMethodDefiner(state, definingClass, meth->methodIdx); - } - - for (i = classData->header.virtualMethodsSize; okay && (i > 0); /*i*/) { - i--; - const DexMethod* meth = &classData->virtualMethods[i]; - okay = dexDataMapVerify0Ok(state->pDataMap, meth->codeOff, - kDexTypeCodeItem) - && verifyMethodDefiner(state, definingClass, meth->methodIdx); - } - - free(classData); - - if (!okay) { - return NULL; - } - - return (void*) data; -} - -/* Helper for swapCodeItem(), which fills an array with all the valid - * handlerOff values for catch handlers and also verifies the handler - * contents. */ -static u4 setHandlerOffsAndVerify(const CheckState* state, - DexCode* code, u4 firstOffset, u4 handlersSize, u4* handlerOffs) { - const u1* fileEnd = state->fileEnd; - const u1* handlersBase = dexGetCatchHandlerData(code); - u4 offset = firstOffset; - bool okay = true; - u4 i; - - for (i = 0; i < handlersSize; i++) { - const u1* ptr = handlersBase + offset; - int size = readAndVerifySignedLeb128(&ptr, fileEnd, &okay); - bool catchAll; - - if (!okay) { - ALOGE("Bogus size"); - return 0; - } - - if ((size < -65536) || (size > 65536)) { - ALOGE("Invalid size: %d", size); - return 0; - } - - if (size <= 0) { - catchAll = true; - size = -size; - } else { - catchAll = false; - } - - handlerOffs[i] = offset; - - while (size-- > 0) { - u4 typeIdx = - readAndVerifyUnsignedLeb128(&ptr, fileEnd, &okay); - - if (!okay) { - ALOGE("Bogus type_idx"); - return 0; - } - - CHECK_INDEX(typeIdx, state->pHeader->typeIdsSize); - - u4 addr = readAndVerifyUnsignedLeb128(&ptr, fileEnd, &okay); - - if (!okay) { - ALOGE("Bogus addr"); - return 0; - } - - if (addr >= code->insnsSize) { - ALOGE("Invalid addr: %#x", addr); - return 0; - } - } - - if (catchAll) { - u4 addr = readAndVerifyUnsignedLeb128(&ptr, fileEnd, &okay); - - if (!okay) { - ALOGE("Bogus catch_all_addr"); - return 0; - } - - if (addr >= code->insnsSize) { - ALOGE("Invalid catch_all_addr: %#x", addr); - return 0; - } - } - - offset = ptr - handlersBase; - } - - return offset; -} - -/* Helper for swapCodeItem(), which does all the try-catch related - * swapping and verification. */ -static void* swapTriesAndCatches(const CheckState* state, DexCode* code) { - const u1* encodedHandlers = dexGetCatchHandlerData(code); - const u1* encodedPtr = encodedHandlers; - bool okay = true; - u4 handlersSize = - readAndVerifyUnsignedLeb128(&encodedPtr, state->fileEnd, &okay); - - if (!okay) { - ALOGE("Bogus handlers_size"); - return NULL; - } - - if ((handlersSize == 0) || (handlersSize >= 65536)) { - ALOGE("Invalid handlers_size: %d", handlersSize); - return NULL; - } - - u4 handlerOffs[handlersSize]; // list of valid handlerOff values - u4 endOffset = setHandlerOffsAndVerify(state, code, - encodedPtr - encodedHandlers, - handlersSize, handlerOffs); - - if (endOffset == 0) { - return NULL; - } - - DexTry* tries = (DexTry*) dexGetTries(code); - u4 count = code->triesSize; - u4 lastEnd = 0; - - const u4 sizeOfItem = (u4) sizeof(DexTry); - CHECK_LIST_SIZE(tries, count, sizeOfItem); - - while (count--) { - u4 i; - - SWAP_FIELD4(tries->startAddr); - SWAP_FIELD2(tries->insnCount); - SWAP_FIELD2(tries->handlerOff); - - if (tries->startAddr < lastEnd) { - ALOGE("Out-of-order try"); - return NULL; - } - - if (tries->startAddr >= code->insnsSize) { - ALOGE("Invalid start_addr: %#x", tries->startAddr); - return NULL; - } - - for (i = 0; i < handlersSize; i++) { - if (tries->handlerOff == handlerOffs[i]) { - break; - } - } - - if (i == handlersSize) { - ALOGE("Bogus handler offset: %#x", tries->handlerOff); - return NULL; - } - - lastEnd = tries->startAddr + tries->insnCount; - - if (lastEnd > code->insnsSize) { - ALOGE("Invalid insn_count: %#x (end addr %#x)", - tries->insnCount, lastEnd); - return NULL; - } - - tries++; - } - - return (u1*) encodedHandlers + endOffset; -} - -/* Perform byte-swapping and intra-item verification on code_item. */ -static void* swapCodeItem(const CheckState* state, void* ptr) { - DexCode* item = (DexCode*) ptr; - u2* insns; - u4 count; - - CHECK_PTR_RANGE(item, item + 1); - SWAP_FIELD2(item->registersSize); - SWAP_FIELD2(item->insSize); - SWAP_FIELD2(item->outsSize); - SWAP_FIELD2(item->triesSize); - SWAP_OFFSET4(item->debugInfoOff); - SWAP_FIELD4(item->insnsSize); - - if (item->insSize > item->registersSize) { - ALOGE("insSize (%u) > registersSize (%u)", item->insSize, - item->registersSize); - return NULL; - } - - if ((item->outsSize > 5) && (item->outsSize > item->registersSize)) { - /* - * It's okay for outsSize to be up to five, even if registersSize - * is smaller, since the short forms of method invocation allow - * repetition of a register multiple times within a single parameter - * list. Longer parameter lists, though, need to be represented - * in-order in the register file. - */ - ALOGE("outsSize (%u) > registersSize (%u)", item->outsSize, - item->registersSize); - return NULL; - } - - count = item->insnsSize; - insns = item->insns; - - const u4 sizeOfItem = (u4) sizeof(u2); - CHECK_LIST_SIZE(insns, count, sizeOfItem); - - while (count--) { - *insns = SWAP2(*insns); - insns++; - } - - if (item->triesSize == 0) { - ptr = insns; - } else { - if ((((uintptr_t) insns) & 3) != 0) { - // Four-byte alignment for the tries. Verify the spacer is a 0. - if (*insns != 0) { - ALOGE("Non-zero padding: %#x", (u4) *insns); - return NULL; - } - } - - ptr = swapTriesAndCatches(state, item); - } - - return ptr; -} - -/* Perform intra-item verification on string_data_item. */ -static void* intraVerifyStringDataItem(const CheckState* state, void* ptr) { - const u1* fileEnd = state->fileEnd; - const u1* data = (const u1*) ptr; - bool okay = true; - u4 utf16Size = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay); - u4 i; - - if (!okay) { - ALOGE("Bogus utf16_size"); - return NULL; - } - - for (i = 0; i < utf16Size; i++) { - if (data >= fileEnd) { - ALOGE("String data would go beyond end-of-file"); - return NULL; - } - - u1 byte1 = *(data++); - - // Switch on the high four bits. - switch (byte1 >> 4) { - case 0x00: { - // Special case of bit pattern 0xxx. - if (byte1 == 0) { - ALOGE("String shorter than indicated utf16_size %#x", - utf16Size); - return NULL; - } - break; - } - case 0x01: - case 0x02: - case 0x03: - case 0x04: - case 0x05: - case 0x06: - case 0x07: { - // Bit pattern 0xxx. No need for any extra bytes or checks. - break; - } - case 0x08: - case 0x09: - case 0x0a: - case 0x0b: - case 0x0f: { - /* - * Bit pattern 10xx or 1111, which are illegal start bytes. - * Note: 1111 is valid for normal UTF-8, but not the - * modified UTF-8 used here. - */ - ALOGE("Illegal start byte %#x", byte1); - return NULL; - } - case 0x0e: { - // Bit pattern 1110, so there are two additional bytes. - u1 byte2 = *(data++); - if ((byte2 & 0xc0) != 0x80) { - ALOGE("Illegal continuation byte %#x", byte2); - return NULL; - } - u1 byte3 = *(data++); - if ((byte3 & 0xc0) != 0x80) { - ALOGE("Illegal continuation byte %#x", byte3); - return NULL; - } - u2 value = ((byte1 & 0x0f) << 12) | ((byte2 & 0x3f) << 6) - | (byte3 & 0x3f); - if (value < 0x800) { - ALOGE("Illegal representation for value %x", value); - return NULL; - } - break; - } - case 0x0c: - case 0x0d: { - // Bit pattern 110x, so there is one additional byte. - u1 byte2 = *(data++); - if ((byte2 & 0xc0) != 0x80) { - ALOGE("Illegal continuation byte %#x", byte2); - return NULL; - } - u2 value = ((byte1 & 0x1f) << 6) | (byte2 & 0x3f); - if ((value != 0) && (value < 0x80)) { - ALOGE("Illegal representation for value %x", value); - return NULL; - } - break; - } - } - } - - if (*(data++) != '\0') { - ALOGE("String longer than indicated utf16_size %#x", utf16Size); - return NULL; - } - - return (void*) data; -} - -/* Perform intra-item verification on debug_info_item. */ -static void* intraVerifyDebugInfoItem(const CheckState* state, void* ptr) { - const u1* fileEnd = state->fileEnd; - const u1* data = (const u1*) ptr; - bool okay = true; - u4 i; - - readAndVerifyUnsignedLeb128(&data, fileEnd, &okay); - - if (!okay) { - ALOGE("Bogus line_start"); - return NULL; - } - - u4 parametersSize = - readAndVerifyUnsignedLeb128(&data, fileEnd, &okay); - - if (!okay) { - ALOGE("Bogus parameters_size"); - return NULL; - } - - if (parametersSize > 65536) { - ALOGE("Invalid parameters_size: %#x", parametersSize); - return NULL; - } - - for (i = 0; i < parametersSize; i++) { - u4 parameterName = - readAndVerifyUnsignedLeb128(&data, fileEnd, &okay); - - if (!okay) { - ALOGE("Bogus parameter_name"); - return NULL; - } - - if (parameterName != 0) { - parameterName--; - CHECK_INDEX(parameterName, state->pHeader->stringIdsSize); - } - } - - bool done = false; - while (!done) { - u1 opcode = *(data++); - - switch (opcode) { - case DBG_END_SEQUENCE: { - done = true; - break; - } - case DBG_ADVANCE_PC: { - readAndVerifyUnsignedLeb128(&data, fileEnd, &okay); - break; - } - case DBG_ADVANCE_LINE: { - readAndVerifySignedLeb128(&data, fileEnd, &okay); - break; - } - case DBG_START_LOCAL: { - u4 idx; - u4 regNum = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay); - if (!okay) break; - if (regNum >= 65536) { - okay = false; - break; - } - idx = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay); - if (!okay) break; - if (idx != 0) { - idx--; - CHECK_INDEX(idx, state->pHeader->stringIdsSize); - } - idx = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay); - if (!okay) break; - if (idx != 0) { - idx--; - CHECK_INDEX(idx, state->pHeader->stringIdsSize); - } - break; - } - case DBG_END_LOCAL: - case DBG_RESTART_LOCAL: { - u4 regNum = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay); - if (!okay) break; - if (regNum >= 65536) { - okay = false; - break; - } - break; - } - case DBG_START_LOCAL_EXTENDED: { - u4 idx; - u4 regNum = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay); - if (!okay) break; - if (regNum >= 65536) { - okay = false; - break; - } - idx = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay); - if (!okay) break; - if (idx != 0) { - idx--; - CHECK_INDEX(idx, state->pHeader->stringIdsSize); - } - idx = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay); - if (!okay) break; - if (idx != 0) { - idx--; - CHECK_INDEX(idx, state->pHeader->stringIdsSize); - } - idx = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay); - if (!okay) break; - if (idx != 0) { - idx--; - CHECK_INDEX(idx, state->pHeader->stringIdsSize); - } - break; - } - case DBG_SET_FILE: { - u4 idx = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay); - if (!okay) break; - if (idx != 0) { - idx--; - CHECK_INDEX(idx, state->pHeader->stringIdsSize); - } - break; - } - default: { - // No arguments to parse for anything else. - } - } - - if (!okay) { - ALOGE("Bogus syntax for opcode %02x", opcode); - return NULL; - } - } - - return (void*) data; -} - -/* defined below */ -static const u1* verifyEncodedValue(const CheckState* state, const u1* data, - bool crossVerify); -static const u1* verifyEncodedAnnotation(const CheckState* state, - const u1* data, bool crossVerify); - -/* Helper for verifyEncodedValue(), which reads a 1- to 4- byte unsigned - * little endian value. */ -static u4 readUnsignedLittleEndian(const CheckState* state, const u1** pData, - u4 size) { - const u1* data = *pData; - u4 result = 0; - u4 i; - - CHECK_PTR_RANGE(data, data + size); - - for (i = 0; i < size; i++) { - result |= ((u4) *(data++)) << (i * 8); - } - - *pData = data; - return result; -} - -/* Helper for *VerifyAnnotationItem() and *VerifyEncodedArrayItem(), which - * verifies an encoded_array. */ -static const u1* verifyEncodedArray(const CheckState* state, - const u1* data, bool crossVerify) { - bool okay = true; - u4 size = readAndVerifyUnsignedLeb128(&data, state->fileEnd, &okay); - - if (!okay) { - ALOGE("Bogus encoded_array size"); - return NULL; - } - - while (size--) { - data = verifyEncodedValue(state, data, crossVerify); - if (data == NULL) { - ALOGE("Bogus encoded_array value"); - return NULL; - } - } - - 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, - const u1* data, bool crossVerify) { - CHECK_PTR_RANGE(data, data + 1); - - u1 headerByte = *(data++); - u4 valueType = headerByte & kDexAnnotationValueTypeMask; - u4 valueArg = headerByte >> kDexAnnotationValueArgShift; - - switch (valueType) { - case kDexAnnotationByte: { - if (valueArg != 0) { - ALOGE("Bogus byte size %#x", valueArg); - return NULL; - } - data++; - break; - } - case kDexAnnotationShort: - case kDexAnnotationChar: { - if (valueArg > 1) { - ALOGE("Bogus char/short size %#x", valueArg); - return NULL; - } - data += valueArg + 1; - break; - } - case kDexAnnotationInt: - case kDexAnnotationFloat: { - if (valueArg > 3) { - ALOGE("Bogus int/float size %#x", valueArg); - return NULL; - } - data += valueArg + 1; - break; - } - case kDexAnnotationLong: - case kDexAnnotationDouble: { - 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); - return NULL; - } - u4 idx = readUnsignedLittleEndian(state, &data, valueArg + 1); - CHECK_INDEX(idx, state->pHeader->stringIdsSize); - break; - } - case kDexAnnotationType: { - if (valueArg > 3) { - ALOGE("Bogus type size %#x", valueArg); - return NULL; - } - u4 idx = readUnsignedLittleEndian(state, &data, valueArg + 1); - CHECK_INDEX(idx, state->pHeader->typeIdsSize); - break; - } - case kDexAnnotationField: - case kDexAnnotationEnum: { - if (valueArg > 3) { - ALOGE("Bogus field/enum size %#x", valueArg); - return NULL; - } - u4 idx = readUnsignedLittleEndian(state, &data, valueArg + 1); - CHECK_INDEX(idx, state->pHeader->fieldIdsSize); - break; - } - case kDexAnnotationMethod: { - if (valueArg > 3) { - ALOGE("Bogus method size %#x", valueArg); - return NULL; - } - u4 idx = readUnsignedLittleEndian(state, &data, valueArg + 1); - CHECK_INDEX(idx, state->pHeader->methodIdsSize); - break; - } - case kDexAnnotationArray: { - if (valueArg != 0) { - ALOGE("Bogus array value_arg %#x", valueArg); - return NULL; - } - data = verifyEncodedArray(state, data, crossVerify); - break; - } - case kDexAnnotationAnnotation: { - if (valueArg != 0) { - ALOGE("Bogus annotation value_arg %#x", valueArg); - return NULL; - } - data = verifyEncodedAnnotation(state, data, crossVerify); - break; - } - case kDexAnnotationNull: { - if (valueArg != 0) { - ALOGE("Bogus null value_arg %#x", valueArg); - return NULL; - } - // Nothing else to do for this type. - break; - } - case kDexAnnotationBoolean: { - if (valueArg > 1) { - ALOGE("Bogus boolean value_arg %#x", valueArg); - return NULL; - } - // Nothing else to do for this type. - break; - } - default: { - ALOGE("Bogus value_type %#x", valueType); - return NULL; - } - } - - return data; -} - -/* Helper for *VerifyAnnotationItem() and *VerifyEncodedArrayItem(), which - * verifies an encoded_annotation. */ -static const u1* verifyEncodedAnnotation(const CheckState* state, - const u1* data, bool crossVerify) { - const u1* fileEnd = state->fileEnd; - bool okay = true; - u4 idx = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay); - - if (!okay) { - ALOGE("Bogus encoded_annotation type_idx"); - return NULL; - } - - CHECK_INDEX(idx, state->pHeader->typeIdsSize); - - if (crossVerify) { - const char* descriptor = dexStringByTypeIdx(state->pDexFile, idx); - if (!dexIsClassDescriptor(descriptor)) { - ALOGE("Bogus annotation type: '%s'", descriptor); - return NULL; - } - } - - u4 size = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay); - u4 lastIdx = 0; - bool first = true; - - if (!okay) { - ALOGE("Bogus encoded_annotation size"); - return NULL; - } - - while (size--) { - idx = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay); - - if (!okay) { - ALOGE("Bogus encoded_annotation name_idx"); - return NULL; - } - - CHECK_INDEX(idx, state->pHeader->stringIdsSize); - - if (crossVerify) { - const char* name = dexStringById(state->pDexFile, idx); - if (!dexIsValidMemberName(name)) { - ALOGE("Bogus annotation member name: '%s'", name); - return NULL; - } - } - - if (first) { - first = false; - } else if (lastIdx >= idx) { - ALOGE("Out-of-order encoded_annotation name_idx: %#x then %#x", - lastIdx, idx); - return NULL; - } - - data = verifyEncodedValue(state, data, crossVerify); - lastIdx = idx; - - if (data == NULL) { - return NULL; - } - } - - return data; -} - -/* Perform intra-item verification on encoded_array_item. */ -static void* intraVerifyEncodedArrayItem(const CheckState* state, void* ptr) { - return (void*) verifyEncodedArray(state, (const u1*) ptr, false); -} - -/* Perform intra-item verification on annotation_item. */ -static void* intraVerifyAnnotationItem(const CheckState* state, void* ptr) { - const u1* data = (const u1*) ptr; - - CHECK_PTR_RANGE(data, data + 1); - - switch (*(data++)) { - case kDexVisibilityBuild: - case kDexVisibilityRuntime: - case kDexVisibilitySystem: { - break; - } - default: { - ALOGE("Bogus annotation visibility: %#x", *data); - return NULL; - } - } - - return (void*) verifyEncodedAnnotation(state, data, false); -} - -/* - * Function to visit an individual top-level item type. - */ -typedef void* ItemVisitorFunction(const CheckState* state, void* ptr); - -/* - * Iterate over all the items in a section, optionally updating the - * data map (done if mapType is passed as non-negative). The section - * must consist of concatenated items of the same type. - */ -static bool iterateSectionWithOptionalUpdate(CheckState* state, - u4 offset, u4 count, ItemVisitorFunction* func, u4 alignment, - u4* nextOffset, int mapType) { - u4 alignmentMask = alignment - 1; - u4 i; - - state->previousItem = NULL; - - for (i = 0; i < count; i++) { - u4 newOffset = (offset + alignmentMask) & ~alignmentMask; - u1* ptr = (u1*) filePointer(state, newOffset); - - if (offset < newOffset) { - ptr = (u1*) filePointer(state, offset); - if (offset < newOffset) { - CHECK_OFFSET_RANGE(offset, newOffset); - while (offset < newOffset) { - if (*ptr != '\0') { - ALOGE("Non-zero padding 0x%02x @ %x", *ptr, offset); - return false; - } - ptr++; - offset++; - } - } - } - - u1* newPtr = (u1*) func(state, ptr); - newOffset = fileOffset(state, newPtr); - - if (newPtr == NULL) { - ALOGE("Trouble with item %d @ offset %#x", i, offset); - return false; - } - - if (newOffset > state->fileLen) { - ALOGE("Item %d @ offset %#x ends out of bounds", i, offset); - return false; - } - - if (mapType >= 0) { - dexDataMapAdd(state->pDataMap, offset, mapType); - } - - state->previousItem = ptr; - offset = newOffset; - } - - if (nextOffset != NULL) { - *nextOffset = offset; - } - - return true; -} - -/* - * Iterate over all the items in a section. The section must consist of - * concatenated items of the same type. This variant will not update the data - * map. - */ -static bool iterateSection(CheckState* state, u4 offset, u4 count, - ItemVisitorFunction* func, u4 alignment, u4* nextOffset) { - return iterateSectionWithOptionalUpdate(state, offset, count, func, - alignment, nextOffset, -1); -} - -/* - * Like iterateSection(), but also check that the offset and count match - * a given pair of expected values. - */ -static bool checkBoundsAndIterateSection(CheckState* state, - u4 offset, u4 count, u4 expectedOffset, u4 expectedCount, - ItemVisitorFunction* func, u4 alignment, u4* nextOffset) { - if (offset != expectedOffset) { - ALOGE("Bogus offset for section: got %#x; expected %#x", - offset, expectedOffset); - return false; - } - - if (count != expectedCount) { - ALOGE("Bogus size for section: got %#x; expected %#x", - count, expectedCount); - return false; - } - - return iterateSection(state, offset, count, func, alignment, nextOffset); -} - -/* - * Like iterateSection(), but also update the data section map and - * check that all the items fall within the data section. - */ -static bool iterateDataSection(CheckState* state, u4 offset, u4 count, - ItemVisitorFunction* func, u4 alignment, u4* nextOffset, int mapType) { - u4 dataStart = state->pHeader->dataOff; - u4 dataEnd = dataStart + state->pHeader->dataSize; - - assert(nextOffset != NULL); - - if ((offset < dataStart) || (offset >= dataEnd)) { - ALOGE("Bogus offset for data subsection: %#x", offset); - return false; - } - - if (!iterateSectionWithOptionalUpdate(state, offset, count, func, - alignment, nextOffset, mapType)) { - return false; - } - - if (*nextOffset > dataEnd) { - ALOGE("Out-of-bounds end of data subsection: %#x", *nextOffset); - return false; - } - - return true; -} - -/* - * Byte-swap all items in the given map except the header and the map - * itself, both of which should have already gotten swapped. This also - * does all possible intra-item verification, that is, verification - * that doesn't need to assume the sanctity of the contents of *other* - * items. The intra-item limitation is because at the time an item is - * asked to verify itself, it can't assume that the items it refers to - * have been byte-swapped and verified. - */ -static bool swapEverythingButHeaderAndMap(CheckState* state, - DexMapList* pMap) { - const DexMapItem* item = pMap->list; - u4 lastOffset = 0; - u4 count = pMap->size; - bool okay = true; - - while (okay && count--) { - u4 sectionOffset = item->offset; - u4 sectionCount = item->size; - u2 type = item->type; - - if (lastOffset < sectionOffset) { - CHECK_OFFSET_RANGE(lastOffset, sectionOffset); - const u1* ptr = (const u1*) filePointer(state, lastOffset); - while (lastOffset < sectionOffset) { - if (*ptr != '\0') { - ALOGE("Non-zero padding 0x%02x before section start @ %x", - *ptr, lastOffset); - okay = false; - break; - } - ptr++; - lastOffset++; - } - } else if (lastOffset > sectionOffset) { - ALOGE("Section overlap or out-of-order map: %x, %x", - lastOffset, sectionOffset); - okay = false; - } - - if (!okay) { - break; - } - - switch (type) { - case kDexTypeHeaderItem: { - /* - * The header got swapped very early on, but do some - * additional sanity checking here. - */ - okay = checkHeaderSection(state, sectionOffset, sectionCount, - &lastOffset); - break; - } - case kDexTypeStringIdItem: { - okay = checkBoundsAndIterateSection(state, sectionOffset, - sectionCount, state->pHeader->stringIdsOff, - state->pHeader->stringIdsSize, swapStringIdItem, - sizeof(u4), &lastOffset); - break; - } - case kDexTypeTypeIdItem: { - okay = checkBoundsAndIterateSection(state, sectionOffset, - sectionCount, state->pHeader->typeIdsOff, - state->pHeader->typeIdsSize, swapTypeIdItem, - sizeof(u4), &lastOffset); - break; - } - case kDexTypeProtoIdItem: { - okay = checkBoundsAndIterateSection(state, sectionOffset, - sectionCount, state->pHeader->protoIdsOff, - state->pHeader->protoIdsSize, swapProtoIdItem, - sizeof(u4), &lastOffset); - break; - } - case kDexTypeFieldIdItem: { - okay = checkBoundsAndIterateSection(state, sectionOffset, - sectionCount, state->pHeader->fieldIdsOff, - state->pHeader->fieldIdsSize, swapFieldIdItem, - sizeof(u4), &lastOffset); - break; - } - case kDexTypeMethodIdItem: { - okay = checkBoundsAndIterateSection(state, sectionOffset, - sectionCount, state->pHeader->methodIdsOff, - state->pHeader->methodIdsSize, swapMethodIdItem, - sizeof(u4), &lastOffset); - break; - } - case kDexTypeClassDefItem: { - okay = checkBoundsAndIterateSection(state, sectionOffset, - sectionCount, state->pHeader->classDefsOff, - state->pHeader->classDefsSize, swapClassDefItem, - 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 - * additional sanity checking here. - */ - okay = checkMapSection(state, sectionOffset, sectionCount, - &lastOffset); - break; - } - case kDexTypeTypeList: { - okay = iterateDataSection(state, sectionOffset, sectionCount, - swapTypeList, sizeof(u4), &lastOffset, type); - break; - } - case kDexTypeAnnotationSetRefList: { - okay = iterateDataSection(state, sectionOffset, sectionCount, - swapAnnotationSetRefList, sizeof(u4), &lastOffset, - type); - break; - } - case kDexTypeAnnotationSetItem: { - okay = iterateDataSection(state, sectionOffset, sectionCount, - swapAnnotationSetItem, sizeof(u4), &lastOffset, type); - break; - } - case kDexTypeClassDataItem: { - okay = iterateDataSection(state, sectionOffset, sectionCount, - intraVerifyClassDataItem, sizeof(u1), &lastOffset, - type); - break; - } - case kDexTypeCodeItem: { - okay = iterateDataSection(state, sectionOffset, sectionCount, - swapCodeItem, sizeof(u4), &lastOffset, type); - break; - } - case kDexTypeStringDataItem: { - okay = iterateDataSection(state, sectionOffset, sectionCount, - intraVerifyStringDataItem, sizeof(u1), &lastOffset, - type); - break; - } - case kDexTypeDebugInfoItem: { - okay = iterateDataSection(state, sectionOffset, sectionCount, - intraVerifyDebugInfoItem, sizeof(u1), &lastOffset, - type); - break; - } - case kDexTypeAnnotationItem: { - okay = iterateDataSection(state, sectionOffset, sectionCount, - intraVerifyAnnotationItem, sizeof(u1), &lastOffset, - type); - break; - } - case kDexTypeEncodedArrayItem: { - okay = iterateDataSection(state, sectionOffset, sectionCount, - intraVerifyEncodedArrayItem, sizeof(u1), &lastOffset, - type); - break; - } - case kDexTypeAnnotationsDirectoryItem: { - okay = iterateDataSection(state, sectionOffset, sectionCount, - swapAnnotationsDirectoryItem, sizeof(u4), &lastOffset, - type); - break; - } - default: { - ALOGE("Unknown map item type %04x", type); - return false; - } - } - - if (!okay) { - ALOGE("Swap of section type %04x failed", type); - } - - item++; - } - - return okay; -} - -/* - * Perform cross-item verification on everything that needs it. This - * pass is only called after all items are byte-swapped and - * intra-verified (checked for internal consistency). - */ -static bool crossVerifyEverything(CheckState* state, DexMapList* pMap) -{ - const DexMapItem* item = pMap->list; - u4 count = pMap->size; - bool okay = true; - - while (okay && count--) { - u4 sectionOffset = item->offset; - u4 sectionCount = item->size; - - switch (item->type) { - case kDexTypeHeaderItem: - case kDexTypeMapList: - case kDexTypeTypeList: - case kDexTypeCodeItem: - case kDexTypeStringDataItem: - case kDexTypeDebugInfoItem: - case kDexTypeAnnotationItem: - case kDexTypeEncodedArrayItem: { - // There is no need for cross-item verification for these. - break; - } - case kDexTypeStringIdItem: { - okay = iterateSection(state, sectionOffset, sectionCount, - crossVerifyStringIdItem, sizeof(u4), NULL); - break; - } - case kDexTypeTypeIdItem: { - okay = iterateSection(state, sectionOffset, sectionCount, - crossVerifyTypeIdItem, sizeof(u4), NULL); - break; - } - case kDexTypeProtoIdItem: { - okay = iterateSection(state, sectionOffset, sectionCount, - crossVerifyProtoIdItem, sizeof(u4), NULL); - break; - } - case kDexTypeFieldIdItem: { - okay = iterateSection(state, sectionOffset, sectionCount, - crossVerifyFieldIdItem, sizeof(u4), NULL); - break; - } - case kDexTypeMethodIdItem: { - okay = iterateSection(state, sectionOffset, sectionCount, - crossVerifyMethodIdItem, sizeof(u4), NULL); - break; - } - case kDexTypeClassDefItem: { - // Allocate (on the stack) the "observed class_def" bits. - size_t arraySize = calcDefinedClassBitsSize(state); - u4 definedClassBits[arraySize]; - memset(definedClassBits, 0, arraySize * sizeof(u4)); - state->pDefinedClassBits = definedClassBits; - - okay = iterateSection(state, sectionOffset, sectionCount, - crossVerifyClassDefItem, sizeof(u4), NULL); - - 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); - break; - } - case kDexTypeAnnotationSetItem: { - okay = iterateSection(state, sectionOffset, sectionCount, - crossVerifyAnnotationSetItem, sizeof(u4), NULL); - break; - } - case kDexTypeClassDataItem: { - okay = iterateSection(state, sectionOffset, sectionCount, - crossVerifyClassDataItem, sizeof(u1), NULL); - break; - } - case kDexTypeAnnotationsDirectoryItem: { - okay = iterateSection(state, sectionOffset, sectionCount, - crossVerifyAnnotationsDirectoryItem, sizeof(u4), NULL); - break; - } - default: { - ALOGE("Unknown map item type %04x", item->type); - return false; - } - } - - if (!okay) { - ALOGE("Cross-item verify of section type %04x failed", - item->type); - } - - item++; - } - - return okay; -} - -/* (documented in header file) */ -bool dexHasValidMagic(const DexHeader* pHeader) -{ - const u1* magic = pHeader->magic; - const u1* version = &magic[4]; - - if (memcmp(magic, DEX_MAGIC, 4) != 0) { - ALOGE("ERROR: unrecognized magic number (%02x %02x %02x %02x)", - magic[0], magic[1], magic[2], magic[3]); - return false; - } - - 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_38, 4) != 0) && - (memcmp(version, DEX_MAGIC_VERS_39, 4) != 0)) { - /* - * Magic was correct, but this is an unsupported older or - * newer format variant. - */ - ALOGE("ERROR: unsupported dex version (%02x %02x %02x %02x)", - version[0], version[1], version[2], version[3]); - return false; - } - - return true; -} - -/* - * Fix the byte ordering of all fields in the DEX file, and do - * structural verification. This is only required for code that opens - * "raw" DEX files, such as the DEX optimizer. - * - * Returns 0 on success, nonzero on failure. - */ -int dexSwapAndVerify(u1* addr, size_t len) -{ - DexHeader* pHeader; - CheckState state; - bool okay = true; - - memset(&state, 0, sizeof(state)); - ALOGV("+++ swapping and verifying"); - - /* - * Note: The caller must have verified that "len" is at least as - * large as a dex file header. - */ - pHeader = (DexHeader*) addr; - - if (!dexHasValidMagic(pHeader)) { - okay = false; - } - - if (okay) { - u4 expectedLen = SWAP4(pHeader->fileSize); - if (len != expectedLen) { - ALOGE("ERROR: Bad length: expected %u, got %zu", expectedLen, len); - okay = false; - } - } - - if (okay) { - /* - * Compute the adler32 checksum and compare it to what's stored in - * the file. This isn't free, but chances are good that we just - * unpacked this from a jar file and have all of the pages sitting - * in memory, so it's pretty quick. - * - * This might be a big-endian system, so we need to do this before - * we byte-swap the header. - */ - uLong adler = adler32(0L, Z_NULL, 0); - const int nonSum = sizeof(pHeader->magic) + sizeof(pHeader->checksum); - u4 storedFileSize = SWAP4(pHeader->fileSize); - u4 expectedChecksum = SWAP4(pHeader->checksum); - - adler = adler32(adler, ((const u1*) pHeader) + nonSum, - storedFileSize - nonSum); - - if (adler != expectedChecksum) { - ALOGE("ERROR: bad checksum (%08lx, expected %08x)", - adler, expectedChecksum); - okay = false; - } - } - - if (okay) { - state.fileStart = addr; - state.fileEnd = addr + len; - state.fileLen = len; - state.pDexFile = NULL; - state.pDataMap = NULL; - state.pDefinedClassBits = NULL; - state.previousItem = NULL; - - /* - * Swap the header and check the contents. - */ - okay = swapDexHeader(&state, pHeader); - } - - if (okay) { - state.pHeader = pHeader; - - if (pHeader->headerSize < sizeof(DexHeader)) { - ALOGE("ERROR: Small header size %d, struct %d", - pHeader->headerSize, (int) sizeof(DexHeader)); - okay = false; - } else if (pHeader->headerSize > sizeof(DexHeader)) { - ALOGW("WARNING: Large header size %d, struct %d", - pHeader->headerSize, (int) sizeof(DexHeader)); - // keep going? - } - } - - if (okay) { - /* - * Look for the map. Swap it and then use it to find and swap - * everything else. - */ - if (pHeader->mapOff != 0) { - DexFile dexFile; - DexMapList* pDexMap = (DexMapList*) (addr + pHeader->mapOff); - - okay = okay && swapMap(&state, pDexMap); - okay = okay && swapEverythingButHeaderAndMap(&state, pDexMap); - - dexFileSetupBasicPointers(&dexFile, addr); - state.pDexFile = &dexFile; - - okay = okay && crossVerifyEverything(&state, pDexMap); - } else { - ALOGE("ERROR: No map found; impossible to byte-swap and verify"); - okay = false; - } - } - - if (!okay) { - ALOGE("ERROR: Byte swap + verify failed"); - } - - if (state.pDataMap != NULL) { - dexDataMapFree(state.pDataMap); - } - - return !okay; // 0 == success -} - -/* - * Detect the file type of the given memory buffer via magic number. - * Call dexSwapAndVerify() on an unoptimized DEX file, do nothing - * but return successfully on an optimized DEX file, and report an - * error for all other cases. - * - * Returns 0 on success, nonzero on failure. - */ -int dexSwapAndVerifyIfNecessary(u1* addr, size_t len) -{ - if (memcmp(addr, DEX_OPT_MAGIC, 4) == 0) { - // It is an optimized dex file. - return 0; - } - - if (memcmp(addr, DEX_MAGIC, 4) == 0) { - // It is an unoptimized dex file. - return dexSwapAndVerify(addr, len); - } - - ALOGE("ERROR: Bad magic number (0x%02x %02x %02x %02x)", - addr[0], addr[1], addr[2], addr[3]); - - return 1; -} diff --git a/libdex/DexUtf.cpp b/libdex/DexUtf.cpp deleted file mode 100644 index df49d1831..000000000 --- a/libdex/DexUtf.cpp +++ /dev/null @@ -1,304 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * Validate and manipulate MUTF-8 encoded string data. - */ - -#include "DexUtf.h" - -/* Compare two '\0'-terminated modified UTF-8 strings, using Unicode - * code point values for comparison. This treats different encodings - * for the same code point as equivalent, except that only a real '\0' - * byte is considered the string terminator. The return value is as - * for strcmp(). */ -int dexUtf8Cmp(const char* s1, const char* s2) { - for (;;) { - if (*s1 == '\0') { - if (*s2 == '\0') { - return 0; - } - return -1; - } else if (*s2 == '\0') { - return 1; - } - - int utf1 = dexGetUtf16FromUtf8(&s1); - int utf2 = dexGetUtf16FromUtf8(&s2); - int diff = utf1 - utf2; - - if (diff != 0) { - return diff; - } - } -} - -/* for dexIsValidMemberNameUtf8(), a bit vector indicating valid low ascii */ -u4 DEX_MEMBER_VALID_LOW_ASCII[4] = { - 0x00000000, // 00..1f low control characters; nothing valid - 0x03ff2010, // 20..3f digits and symbols; valid: '0'..'9', '$', '-' - 0x87fffffe, // 40..5f uppercase etc.; valid: 'A'..'Z', '_' - 0x07fffffe // 60..7f lowercase etc.; valid: 'a'..'z' -}; - -/* Helper for dexIsValidMemberNameUtf8(); do not call directly. */ -bool dexIsValidMemberNameUtf8_0(const char** pUtf8Ptr) { - /* - * It's a multibyte encoded character. Decode it and analyze. We - * accept anything that isn't (a) an improperly encoded low value, - * (b) an improper surrogate pair, (c) an encoded '\0', (d) a high - * control character, or (e) a high space, layout, or special - * character (U+00a0, U+2000..U+200f, U+2028..U+202f, - * U+fff0..U+ffff). This is all specified in the dex format - * document. - */ - - u2 utf16 = dexGetUtf16FromUtf8(pUtf8Ptr); - - // Perform follow-up tests based on the high 8 bits. - switch (utf16 >> 8) { - case 0x00: { - // It's only valid if it's above the ISO-8859-1 high space (0xa0). - return (utf16 > 0x00a0); - } - case 0xd8: - case 0xd9: - case 0xda: - case 0xdb: { - /* - * It's a leading surrogate. Check to see that a trailing - * surrogate follows. - */ - utf16 = dexGetUtf16FromUtf8(pUtf8Ptr); - return (utf16 >= 0xdc00) && (utf16 <= 0xdfff); - } - case 0xdc: - case 0xdd: - case 0xde: - case 0xdf: { - // It's a trailing surrogate, which is not valid at this point. - return false; - } - case 0x20: - case 0xff: { - // It's in the range that has spaces, controls, and specials. - switch (utf16 & 0xfff8) { - case 0x2000: - case 0x2008: - case 0x2028: - case 0xfff0: - case 0xfff8: { - return false; - } - } - break; - } - } - - return true; -} - -/* Return whether the given string is a valid field or method name. */ -bool dexIsValidMemberName(const char* s) { - bool angleName = false; - - switch (*s) { - case '\0': { - // The empty string is not a valid name. - return false; - } - case '<': { - /* - * '<' is allowed only at the start of a name, and if present, - * means that the name must end with '>'. - */ - angleName = true; - s++; - break; - } - } - - for (;;) { - switch (*s) { - case '\0': { - return !angleName; - } - case '>': { - return angleName && s[1] == '\0'; - } - } - if (!dexIsValidMemberNameUtf8(&s)) { - return false; - } - } -} - -/* Helper for validating type descriptors and class names, which is parametric - * with respect to type vs. class and dot vs. slash. */ -static bool isValidTypeDescriptorOrClassName(const char* s, bool isClassName, - bool dotSeparator) { - int arrayCount = 0; - - while (*s == '[') { - arrayCount++; - s++; - } - - if (arrayCount > 255) { - // Arrays may have no more than 255 dimensions. - return false; - } - - if (arrayCount != 0) { - /* - * If we're looking at an array of some sort, then it doesn't - * matter if what is being asked for is a class name; the - * format looks the same as a type descriptor in that case, so - * treat it as such. - */ - isClassName = false; - } - - if (!isClassName) { - /* - * We are looking for a descriptor. Either validate it as a - * single-character primitive type, or continue on to check the - * embedded class name (bracketed by "L" and ";"). - */ - switch (*(s++)) { - case 'B': - case 'C': - case 'D': - case 'F': - case 'I': - case 'J': - case 'S': - case 'Z': { - // These are all single-character descriptors for primitive types. - return (*s == '\0'); - } - case 'V': { - // Non-array void is valid, but you can't have an array of void. - return (arrayCount == 0) && (*s == '\0'); - } - case 'L': { - // Class name: Break out and continue below. - break; - } - default: { - // Oddball descriptor character. - return false; - } - } - } - - /* - * We just consumed the 'L' that introduces a class name as part - * of a type descriptor, or we are looking for an unadorned class - * name. - */ - - bool sepOrFirst = true; // first character or just encountered a separator. - for (;;) { - u1 c = (u1) *s; - switch (c) { - case '\0': { - /* - * Premature end for a type descriptor, but valid for - * a class name as long as we haven't encountered an - * empty component (including the degenerate case of - * the empty string ""). - */ - return isClassName && !sepOrFirst; - } - case ';': { - /* - * Invalid character for a class name, but the - * legitimate end of a type descriptor. In the latter - * case, make sure that this is the end of the string - * and that it doesn't end with an empty component - * (including the degenerate case of "L;"). - */ - return !isClassName && !sepOrFirst && (s[1] == '\0'); - } - case '/': - case '.': { - if (dotSeparator != (c == '.')) { - // The wrong separator character. - return false; - } - if (sepOrFirst) { - // Separator at start or two separators in a row. - return false; - } - sepOrFirst = true; - s++; - break; - } - default: { - if (!dexIsValidMemberNameUtf8(&s)) { - return false; - } - sepOrFirst = false; - break; - } - } - } -} - -/* Return whether the given string is a valid type descriptor. */ -bool dexIsValidTypeDescriptor(const char* s) { - return isValidTypeDescriptorOrClassName(s, false, false); -} - -/* (documented in header) */ -bool dexIsValidClassName(const char* s, bool dotSeparator) { - return isValidTypeDescriptorOrClassName(s, true, dotSeparator); -} - -/* Return whether the given string is a valid reference descriptor. This - * is true if dexIsValidTypeDescriptor() returns true and the descriptor - * is for a class or array and not a primitive type. */ -bool dexIsReferenceDescriptor(const char* s) { - if (!dexIsValidTypeDescriptor(s)) { - return false; - } - - return (s[0] == 'L') || (s[0] == '['); -} - -/* Return whether the given string is a valid class descriptor. This - * is true if dexIsValidTypeDescriptor() returns true and the descriptor - * is for a class and not an array or primitive type. */ -bool dexIsClassDescriptor(const char* s) { - if (!dexIsValidTypeDescriptor(s)) { - return false; - } - - return s[0] == 'L'; -} - -/* Return whether the given string is a valid field type descriptor. This - * is true if dexIsValidTypeDescriptor() returns true and the descriptor - * is for anything but "void". */ -bool dexIsFieldDescriptor(const char* s) { - if (!dexIsValidTypeDescriptor(s)) { - return false; - } - - return s[0] != 'V'; -} - diff --git a/libdex/DexUtf.h b/libdex/DexUtf.h deleted file mode 100644 index cb3d919ae..000000000 --- a/libdex/DexUtf.h +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * Validate and manipulate MUTF-8 (modified UTF-8) encoded string data. - */ - -#ifndef LIBDEX_DEXUTF_H_ -#define LIBDEX_DEXUTF_H_ - -#include "DexFile.h" - -/* - * Retrieve the next UTF-16 character from a UTF-8 string. - * - * Advances "*pUtf8Ptr" to the start of the next character. - * - * WARNING: If a string is corrupted by dropping a '\0' in the middle - * of a 3-byte sequence, you can end up overrunning the buffer with - * reads (and possibly with the writes if the length was computed and - * cached before the damage). For performance reasons, this function - * assumes that the string being parsed is known to be valid (e.g., by - * already being verified). Most strings we process here are coming - * out of dex files or other internal translations, so the only real - * risk comes from the JNI NewStringUTF call. - */ -DEX_INLINE u2 dexGetUtf16FromUtf8(const char** pUtf8Ptr) -{ - unsigned int one, two, three; - - one = *(*pUtf8Ptr)++; - if ((one & 0x80) != 0) { - /* two- or three-byte encoding */ - two = *(*pUtf8Ptr)++; - if ((one & 0x20) != 0) { - /* three-byte encoding */ - three = *(*pUtf8Ptr)++; - return ((one & 0x0f) << 12) | - ((two & 0x3f) << 6) | - (three & 0x3f); - } else { - /* two-byte encoding */ - return ((one & 0x1f) << 6) | - (two & 0x3f); - } - } else { - /* one-byte encoding */ - return one; - } -} - -/* Compare two '\0'-terminated modified UTF-8 strings, using Unicode - * code point values for comparison. This treats different encodings - * for the same code point as equivalent, except that only a real '\0' - * byte is considered the string terminator. The return value is as - * for strcmp(). */ -int dexUtf8Cmp(const char* s1, const char* s2); - -/* for dexIsValidMemberNameUtf8(), a bit vector indicating valid low ascii */ -extern u4 DEX_MEMBER_VALID_LOW_ASCII[4]; - -/* Helper for dexIsValidMemberUtf8(); do not call directly. */ -bool dexIsValidMemberNameUtf8_0(const char** pUtf8Ptr); - -/* Return whether the pointed-at modified-UTF-8 encoded character is - * valid as part of a member name, updating the pointer to point past - * the consumed character. This will consume two encoded UTF-16 code - * points if the character is encoded as a surrogate pair. Also, if - * this function returns false, then the given pointer may only have - * been partially advanced. */ -DEX_INLINE bool dexIsValidMemberNameUtf8(const char** pUtf8Ptr) { - u1 c = (u1) **pUtf8Ptr; - if (c <= 0x7f) { - // It's low-ascii, so check the table. - u4 wordIdx = c >> 5; - u4 bitIdx = c & 0x1f; - (*pUtf8Ptr)++; - return (DEX_MEMBER_VALID_LOW_ASCII[wordIdx] & (1 << bitIdx)) != 0; - } - - /* - * It's a multibyte encoded character. Call a non-inline function - * for the heavy lifting. - */ - return dexIsValidMemberNameUtf8_0(pUtf8Ptr); -} - -/* Return whether the given string is a valid field or method name. */ -bool dexIsValidMemberName(const char* s); - -/* Return whether the given string is a valid type descriptor. */ -bool dexIsValidTypeDescriptor(const char* s); - -/* Return whether the given string is a valid internal-form class - * name, with components separated either by dots or slashes as - * specified. A class name is like a type descriptor, except that it - * can't name a primitive type (including void). In terms of syntax, - * the form is either (a) the name of the class without adornment - * (that is, not bracketed by "L" and ";"); or (b) identical to the - * type descriptor syntax for array types. */ -bool dexIsValidClassName(const char* s, bool dotSeparator); - -/* Return whether the given string is a valid reference descriptor. This - * is true if dexIsValidTypeDescriptor() returns true and the descriptor - * is for a class or array and not a primitive type. */ -bool dexIsReferenceDescriptor(const char* s); - -/* Return whether the given string is a valid class descriptor. This - * is true if dexIsValidTypeDescriptor() returns true and the descriptor - * is for a class and not an array or primitive type. */ -bool dexIsClassDescriptor(const char* s); - -/* Return whether the given string is a valid field type descriptor. This - * is true if dexIsValidTypeDescriptor() returns true and the descriptor - * is for anything but "void". */ -bool dexIsFieldDescriptor(const char* s); - -#endif // LIBDEX_DEXUTF_H_ diff --git a/libdex/InstrUtils.cpp b/libdex/InstrUtils.cpp deleted file mode 100644 index 56f5dd80b..000000000 --- a/libdex/InstrUtils.cpp +++ /dev/null @@ -1,702 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * Dalvik instruction utility functions. - * - * IMPORTANT NOTE: Much of the contents of this file are generated - * automatically by the opcode-gen tool. Any edits to the generated - * sections will get wiped out the next time the tool is run. - */ - -#include "InstrUtils.h" -#include <stdlib.h> - -/* - * Table that maps each opcode to the full width of instructions that - * use that opcode, in (16-bit) code units. Unimplemented opcodes as - * well as the "breakpoint" opcode have a width of zero. - */ -static InstructionWidth gInstructionWidthTable[kNumPackedOpcodes] = { - // BEGIN(libdex-widths); GENERATED AUTOMATICALLY BY opcode-gen - 1, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 2, 3, 2, 2, 3, 5, 2, 2, 3, 2, 1, 1, 2, - 2, 1, 2, 2, 3, 3, 3, 1, 1, 2, 3, 3, 3, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, - 0, 0, 0, 0, 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, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, - 3, 3, 3, 0, 3, 3, 3, 3, 3, 0, 0, 1, 1, 1, 1, 1, - 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, 2, 2, 2, 2, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 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, 0, 0, 0, 0, 0, 0, 0, 4, 4, 3, 3, 2, 2, - // END(libdex-widths) -}; - -/* - * Table that maps each opcode to the flags associated with that - * opcode. - */ -static u1 gOpcodeFlagsTable[kNumPackedOpcodes] = { - // BEGIN(libdex-flags); GENERATED AUTOMATICALLY BY opcode-gen - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanReturn, - kInstrCanReturn, - kInstrCanReturn, - kInstrCanReturn, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue, - kInstrCanThrow, - kInstrCanBranch, - kInstrCanBranch, - kInstrCanBranch, - kInstrCanContinue|kInstrCanSwitch, - kInstrCanContinue|kInstrCanSwitch, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue|kInstrCanBranch, - kInstrCanContinue|kInstrCanBranch, - kInstrCanContinue|kInstrCanBranch, - kInstrCanContinue|kInstrCanBranch, - kInstrCanContinue|kInstrCanBranch, - kInstrCanContinue|kInstrCanBranch, - kInstrCanContinue|kInstrCanBranch, - kInstrCanContinue|kInstrCanBranch, - kInstrCanContinue|kInstrCanBranch, - kInstrCanContinue|kInstrCanBranch, - kInstrCanContinue|kInstrCanBranch, - kInstrCanContinue|kInstrCanBranch, - 0, - 0, - 0, - 0, - 0, - 0, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow|kInstrInvoke, - kInstrCanContinue|kInstrCanThrow|kInstrInvoke, - kInstrCanContinue|kInstrCanThrow|kInstrInvoke, - kInstrCanContinue|kInstrCanThrow|kInstrInvoke, - kInstrCanContinue|kInstrCanThrow|kInstrInvoke, - 0, - kInstrCanContinue|kInstrCanThrow|kInstrInvoke, - kInstrCanContinue|kInstrCanThrow|kInstrInvoke, - kInstrCanContinue|kInstrCanThrow|kInstrInvoke, - kInstrCanContinue|kInstrCanThrow|kInstrInvoke, - kInstrCanContinue|kInstrCanThrow|kInstrInvoke, - 0, - 0, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - 0, - kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow|kInstrInvoke, - kInstrCanReturn, - kInstrCanContinue|kInstrCanThrow, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - kInstrCanContinue|kInstrCanThrow|kInstrInvoke, - kInstrCanContinue|kInstrCanThrow|kInstrInvoke, - kInstrCanContinue|kInstrCanThrow|kInstrInvoke, - kInstrCanContinue|kInstrCanThrow|kInstrInvoke, - kInstrCanContinue|kInstrCanThrow, - kInstrCanContinue|kInstrCanThrow, - // END(libdex-flags) -}; - -/* - * Table that maps each opcode to the instruction format associated - * that opcode. - */ -static u1 gInstructionFormatTable[kNumPackedOpcodes] = { - // BEGIN(libdex-formats); GENERATED AUTOMATICALLY BY opcode-gen - kFmt10x, kFmt12x, kFmt22x, kFmt32x, kFmt12x, kFmt22x, kFmt32x, - kFmt12x, kFmt22x, kFmt32x, kFmt11x, kFmt11x, kFmt11x, kFmt11x, - kFmt10x, kFmt11x, kFmt11x, kFmt11x, kFmt11n, kFmt21s, kFmt31i, - kFmt21h, kFmt21s, kFmt31i, kFmt51l, kFmt21h, kFmt21c, kFmt31c, - kFmt21c, kFmt11x, kFmt11x, kFmt21c, kFmt22c, kFmt12x, kFmt21c, - kFmt22c, kFmt35c, kFmt3rc, kFmt31t, kFmt11x, kFmt10t, kFmt20t, - kFmt30t, kFmt31t, kFmt31t, kFmt23x, kFmt23x, kFmt23x, kFmt23x, - kFmt23x, kFmt22t, kFmt22t, kFmt22t, kFmt22t, kFmt22t, kFmt22t, - kFmt21t, kFmt21t, kFmt21t, kFmt21t, kFmt21t, kFmt21t, kFmt00x, - kFmt00x, kFmt00x, kFmt00x, kFmt00x, kFmt00x, kFmt23x, kFmt23x, - kFmt23x, kFmt23x, kFmt23x, kFmt23x, kFmt23x, kFmt23x, kFmt23x, - kFmt23x, kFmt23x, kFmt23x, kFmt23x, kFmt23x, kFmt22c, kFmt22c, - kFmt22c, kFmt22c, kFmt22c, kFmt22c, kFmt22c, kFmt22c, kFmt22c, - kFmt22c, kFmt22c, kFmt22c, kFmt22c, kFmt22c, kFmt21c, kFmt21c, - kFmt21c, kFmt21c, kFmt21c, kFmt21c, kFmt21c, kFmt21c, kFmt21c, - kFmt21c, kFmt21c, kFmt21c, kFmt21c, kFmt21c, kFmt35c, kFmt35c, - kFmt35c, kFmt35c, kFmt35c, kFmt00x, kFmt3rc, kFmt3rc, kFmt3rc, - kFmt3rc, kFmt3rc, kFmt00x, kFmt00x, kFmt12x, kFmt12x, kFmt12x, - kFmt12x, kFmt12x, kFmt12x, kFmt12x, kFmt12x, kFmt12x, kFmt12x, - kFmt12x, kFmt12x, kFmt12x, kFmt12x, kFmt12x, kFmt12x, kFmt12x, - kFmt12x, kFmt12x, kFmt12x, kFmt12x, kFmt23x, kFmt23x, kFmt23x, - kFmt23x, kFmt23x, kFmt23x, kFmt23x, kFmt23x, kFmt23x, kFmt23x, - kFmt23x, kFmt23x, kFmt23x, kFmt23x, kFmt23x, kFmt23x, kFmt23x, - kFmt23x, kFmt23x, kFmt23x, kFmt23x, kFmt23x, kFmt23x, kFmt23x, - kFmt23x, kFmt23x, kFmt23x, kFmt23x, kFmt23x, kFmt23x, kFmt23x, - kFmt23x, kFmt12x, kFmt12x, kFmt12x, kFmt12x, kFmt12x, kFmt12x, - kFmt12x, kFmt12x, kFmt12x, kFmt12x, kFmt12x, kFmt12x, kFmt12x, - kFmt12x, kFmt12x, kFmt12x, kFmt12x, kFmt12x, kFmt12x, kFmt12x, - kFmt12x, kFmt12x, kFmt12x, kFmt12x, kFmt12x, kFmt12x, kFmt12x, - kFmt12x, kFmt12x, kFmt12x, kFmt12x, kFmt12x, kFmt22s, kFmt22s, - kFmt22s, kFmt22s, kFmt22s, kFmt22s, kFmt22s, kFmt22s, kFmt22b, - kFmt22b, kFmt22b, kFmt22b, kFmt22b, kFmt22b, kFmt22b, kFmt22b, - kFmt22b, kFmt22b, kFmt22b, kFmt22c, kFmt22c, kFmt21c, kFmt21c, - kFmt22c, kFmt22c, kFmt22c, kFmt21c, kFmt21c, kFmt00x, kFmt20bc, - kFmt35mi, kFmt3rmi, kFmt35c, kFmt10x, kFmt22cs, kFmt00x, kFmt00x, - kFmt00x, kFmt00x, kFmt00x, kFmt00x, kFmt00x, kFmt45cc, kFmt4rcc, - kFmt35c, kFmt3rc, kFmt21c, kFmt21c, - // END(libdex-formats) -}; - -/* - * Table that maps each opcode to the index type implied by that - * opcode. - */ -static u1 gInstructionIndexTypeTable[kNumPackedOpcodes] = { - // BEGIN(libdex-index-types); GENERATED AUTOMATICALLY BY opcode-gen - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexStringRef, - kIndexStringRef, kIndexTypeRef, kIndexNone, - kIndexNone, kIndexTypeRef, kIndexTypeRef, - kIndexNone, kIndexTypeRef, kIndexTypeRef, - kIndexTypeRef, kIndexTypeRef, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexUnknown, - kIndexUnknown, kIndexUnknown, kIndexUnknown, - kIndexUnknown, kIndexUnknown, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexFieldRef, kIndexFieldRef, - kIndexFieldRef, kIndexFieldRef, kIndexFieldRef, - kIndexFieldRef, kIndexFieldRef, kIndexFieldRef, - kIndexFieldRef, kIndexFieldRef, kIndexFieldRef, - kIndexFieldRef, kIndexFieldRef, kIndexFieldRef, - kIndexFieldRef, kIndexFieldRef, kIndexFieldRef, - kIndexFieldRef, kIndexFieldRef, kIndexFieldRef, - kIndexFieldRef, kIndexFieldRef, kIndexFieldRef, - kIndexFieldRef, kIndexFieldRef, kIndexFieldRef, - kIndexFieldRef, kIndexFieldRef, kIndexMethodRef, - kIndexMethodRef, kIndexMethodRef, kIndexMethodRef, - kIndexMethodRef, kIndexUnknown, kIndexMethodRef, - kIndexMethodRef, kIndexMethodRef, kIndexMethodRef, - kIndexMethodRef, kIndexUnknown, kIndexUnknown, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexFieldRef, - kIndexFieldRef, kIndexFieldRef, kIndexFieldRef, - kIndexFieldRef, kIndexFieldRef, kIndexFieldRef, - kIndexFieldRef, kIndexFieldRef, kIndexUnknown, - kIndexVaries, kIndexInlineMethod, kIndexInlineMethod, - kIndexMethodRef, kIndexNone, kIndexFieldOffset, - kIndexUnknown, kIndexUnknown, kIndexUnknown, - kIndexUnknown, kIndexUnknown, kIndexUnknown, - kIndexUnknown, kIndexMethodAndProtoRef, kIndexMethodAndProtoRef, - kIndexCallSiteRef, kIndexCallSiteRef, kIndexMethodHandleRef, - kIndexProtoRef, - // END(libdex-index-types) -}; - -/* - * Global InstructionInfoTables struct. - */ -InstructionInfoTables gDexOpcodeInfo = { - gInstructionFormatTable, - gInstructionIndexTypeTable, - gOpcodeFlagsTable, - gInstructionWidthTable -}; - -/* - * Handy macros for helping decode instructions. - */ -#define FETCH(_offset) (insns[(_offset)]) -#define FETCH_u4(_offset) (fetch_u4_impl((_offset), insns)) -#define INST_A(_inst) (((u2)(_inst) >> 8) & 0x0f) -#define INST_B(_inst) ((u2)(_inst) >> 12) -#define INST_AA(_inst) ((_inst) >> 8) - -/* Helper for FETCH_u4, above. */ -static inline u4 fetch_u4_impl(u4 offset, const u2* insns) { - return insns[offset] | ((u4) insns[offset+1] << 16); -} - -/* - * Decode the instruction pointed to by "insns". - * - * Fills out the pieces of "pDec" that are affected by the current - * instruction. Does not touch anything else. - */ -void dexDecodeInstruction(const u2* insns, DecodedInstruction* pDec) -{ - u2 inst = *insns; - Opcode opcode = dexOpcodeFromCodeUnit(inst); - InstructionFormat format = dexGetFormatFromOpcode(opcode); - - pDec->opcode = opcode; - pDec->indexType = dexGetIndexTypeFromOpcode(opcode); - - switch (format) { - case kFmt10x: // op - /* nothing to do; copy the AA bits out for the verifier */ - pDec->vA = INST_AA(inst); - break; - case kFmt12x: // op vA, vB - pDec->vA = INST_A(inst); - pDec->vB = INST_B(inst); - break; - case kFmt11n: // op vA, #+B - pDec->vA = INST_A(inst); - pDec->vB = (s4) (INST_B(inst) << 28) >> 28; // sign extend 4-bit value - break; - case kFmt11x: // op vAA - pDec->vA = INST_AA(inst); - break; - case kFmt10t: // op +AA - pDec->vA = (s1) INST_AA(inst); // sign-extend 8-bit value - break; - case kFmt20t: // op +AAAA - pDec->vA = (s2) FETCH(1); // sign-extend 16-bit value - break; - case kFmt20bc: // [opt] op AA, thing@BBBB - case kFmt21c: // op vAA, thing@BBBB - case kFmt22x: // op vAA, vBBBB - pDec->vA = INST_AA(inst); - pDec->vB = FETCH(1); - break; - case kFmt21s: // op vAA, #+BBBB - case kFmt21t: // op vAA, +BBBB - pDec->vA = INST_AA(inst); - pDec->vB = (s2) FETCH(1); // sign-extend 16-bit value - break; - case kFmt21h: // op vAA, #+BBBB0000[00000000] - pDec->vA = INST_AA(inst); - /* - * The value should be treated as right-zero-extended, but we don't - * actually do that here. Among other things, we don't know if it's - * the top bits of a 32- or 64-bit value. - */ - pDec->vB = FETCH(1); - break; - case kFmt23x: // op vAA, vBB, vCC - pDec->vA = INST_AA(inst); - pDec->vB = FETCH(1) & 0xff; - pDec->vC = FETCH(1) >> 8; - break; - case kFmt22b: // op vAA, vBB, #+CC - pDec->vA = INST_AA(inst); - pDec->vB = FETCH(1) & 0xff; - pDec->vC = (s1) (FETCH(1) >> 8); // sign-extend 8-bit value - break; - case kFmt22s: // op vA, vB, #+CCCC - case kFmt22t: // op vA, vB, +CCCC - pDec->vA = INST_A(inst); - pDec->vB = INST_B(inst); - pDec->vC = (s2) FETCH(1); // sign-extend 16-bit value - break; - case kFmt22c: // op vA, vB, thing@CCCC - case kFmt22cs: // [opt] op vA, vB, field offset CCCC - pDec->vA = INST_A(inst); - pDec->vB = INST_B(inst); - pDec->vC = FETCH(1); - break; - case kFmt30t: // op +AAAAAAAA - pDec->vA = FETCH_u4(1); // signed 32-bit value - break; - case kFmt31t: // op vAA, +BBBBBBBB - case kFmt31c: // op vAA, string@BBBBBBBB - pDec->vA = INST_AA(inst); - pDec->vB = FETCH_u4(1); // 32-bit value - break; - case kFmt32x: // op vAAAA, vBBBB - pDec->vA = FETCH(1); - pDec->vB = FETCH(2); - break; - case kFmt31i: // op vAA, #+BBBBBBBB - pDec->vA = INST_AA(inst); - pDec->vB = FETCH_u4(1); // signed 32-bit value - break; - case kFmt35c: // op {vC, vD, vE, vF, vG}, thing@BBBB - case kFmt35ms: // [opt] invoke-virtual+super - case kFmt35mi: // [opt] inline invoke - { - /* - * Note that the fields mentioned in the spec don't appear in - * their "usual" positions here compared to most formats. This - * was done so that the field names for the argument count and - * reference index match between this format and the corresponding - * range formats (3rc and friends). - * - * Bottom line: The argument count is always in vA, and the - * method constant (or equivalent) is always in vB. - */ - u2 regList; - int count; - - pDec->vA = INST_B(inst); // This is labeled A in the spec. - pDec->vB = FETCH(1); - regList = FETCH(2); - - count = pDec->vA; - - /* - * Copy the argument registers into the arg[] array, and - * also copy the first argument (if any) into vC. (The - * DecodedInstruction structure doesn't have separate - * fields for {vD, vE, vF, vG}, so there's no need to make - * copies of those.) Note that cases 5..2 fall through. - */ - switch (count) { - case 5: { - if (format == kFmt35mi) { - /* A fifth arg is verboten for inline invokes. */ - ALOGW("Invalid arg count in 35mi (5)"); - goto bail; - } - /* - * Per note at the top of this format decoder, the - * fifth argument comes from the A field in the - * instruction, but it's labeled G in the spec. - */ - pDec->arg[4] = INST_A(inst); - FALLTHROUGH_INTENDED; - } - case 4: pDec->arg[3] = (regList >> 12) & 0x0f; FALLTHROUGH_INTENDED; - case 3: pDec->arg[2] = (regList >> 8) & 0x0f; FALLTHROUGH_INTENDED; - case 2: pDec->arg[1] = (regList >> 4) & 0x0f; FALLTHROUGH_INTENDED; - case 1: pDec->vC = pDec->arg[0] = regList & 0x0f; break; - case 0: break; // Valid, but no need to do anything. - default: - ALOGW("Invalid arg count in 35c/35ms/35mi (%d)", count); - goto bail; - } - } - break; - case kFmt3rc: // op {vCCCC .. v(CCCC+AA-1)}, meth@BBBB - case kFmt3rms: // [opt] invoke-virtual+super/range - case kFmt3rmi: // [opt] execute-inline/range - pDec->vA = INST_AA(inst); - pDec->vB = FETCH(1); - pDec->vC = FETCH(2); - break; - case kFmt51l: // op vAA, #+BBBBBBBBBBBBBBBB - pDec->vA = INST_AA(inst); - pDec->vB_wide = FETCH_u4(1) | ((u8) FETCH_u4(3) << 32); - break; - case kFmt45cc: - { - // AG op BBBB FEDC HHHH - pDec->vA = INST_B(inst); // This is labelled A in the spec. - pDec->vB = FETCH(1); // vB meth@BBBB - u2 fedc = FETCH(2); - pDec->vC = fedc & 0xf; - pDec->arg[0] = (fedc >> 4) & 0xf; // vD - pDec->arg[1] = (fedc >> 8) & 0xf; // vE - pDec->arg[2] = (fedc >> 12); // vF - pDec->arg[3] = INST_A(inst); // vG - pDec->arg[4] = FETCH(3); // vH proto@HHHH - } - break; - case kFmt4rcc: - { - // AA op BBBB CCCC HHHH - pDec->vA = INST_AA(inst); - pDec->vB = FETCH(1); - pDec->vC = FETCH(2); - pDec->arg[4] = FETCH(3); // vH proto@HHHH - } - break; - default: - ALOGW("Can't decode unexpected format %d (op=%d)", format, opcode); - assert(false); - break; - } - -bail: - ; -} - -/* - * Return the width of the specified instruction, or 0 if not defined. Also - * works for special OP_NOP entries, including switch statement data tables - * and array data. - */ -size_t dexGetWidthFromInstruction(const u2* insns) -{ - size_t width; - - if (*insns == kPackedSwitchSignature) { - width = 4 + insns[1] * 2; - } else if (*insns == kSparseSwitchSignature) { - width = 2 + insns[1] * 4; - } else if (*insns == kArrayDataSignature) { - u2 elemWidth = insns[1]; - u4 len = insns[2] | (((u4)insns[3]) << 16); - // The plus 1 is to round up for odd size and width. - width = 4 + (elemWidth * len + 1) / 2; - } else { - width = dexGetWidthFromOpcode(dexOpcodeFromCodeUnit(insns[0])); - } - - return width; -} diff --git a/libdex/InstrUtils.h b/libdex/InstrUtils.h deleted file mode 100644 index c5bf77cb0..000000000 --- a/libdex/InstrUtils.h +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * Dalvik instruction utility functions. - */ -#ifndef LIBDEX_INSTRUTILS_H_ -#define LIBDEX_INSTRUTILS_H_ - -#include "DexFile.h" -#include "DexOpcodes.h" - -/* - * Possible instruction formats associated with Dalvik opcodes. - * - * See the file opcode-gen/README.txt for information about updating - * opcodes and instruction formats. - */ -enum InstructionFormat { - kFmt00x = 0, // unknown format (also used for "breakpoint" opcode) - kFmt10x, // op - kFmt12x, // op vA, vB - kFmt11n, // op vA, #+B - kFmt11x, // op vAA - kFmt10t, // op +AA - kFmt20bc, // [opt] op AA, thing@BBBB - kFmt20t, // op +AAAA - kFmt22x, // op vAA, vBBBB - kFmt21t, // op vAA, +BBBB - kFmt21s, // op vAA, #+BBBB - kFmt21h, // op vAA, #+BBBB00000[00000000] - kFmt21c, // op vAA, thing@BBBB - kFmt23x, // op vAA, vBB, vCC - kFmt22b, // op vAA, vBB, #+CC - kFmt22t, // op vA, vB, +CCCC - kFmt22s, // op vA, vB, #+CCCC - kFmt22c, // op vA, vB, thing@CCCC - kFmt22cs, // [opt] op vA, vB, field offset CCCC - kFmt30t, // op +AAAAAAAA - kFmt32x, // op vAAAA, vBBBB - kFmt31i, // op vAA, #+BBBBBBBB - kFmt31t, // op vAA, +BBBBBBBB - kFmt31c, // op vAA, string@BBBBBBBB - kFmt35c, // op {vC,vD,vE,vF,vG}, thing@BBBB - kFmt35ms, // [opt] invoke-virtual+super - kFmt3rc, // op {vCCCC .. v(CCCC+AA-1)}, thing@BBBB - kFmt3rms, // [opt] invoke-virtual+super/range - kFmt51l, // op vAA, #+BBBBBBBBBBBBBBBB - kFmt35mi, // [opt] inline invoke - kFmt3rmi, // [opt] inline invoke/range - kFmt45cc, // op {vC, vD, vE, vF, vG}, meth@BBBB, proto@HHHH - kFmt4rcc, // op {VCCCC .. v(CCCC+AA-1)}, meth@BBBB, proto@HHHH -}; - -/* - * Types of indexed reference that are associated with opcodes whose - * formats include such an indexed reference (e.g., 21c and 35c). - */ -enum InstructionIndexType { - kIndexUnknown = 0, - kIndexNone, // has no index - kIndexVaries, // "It depends." Used for throw-verification-error - kIndexTypeRef, // type reference index - kIndexStringRef, // string reference index - kIndexMethodRef, // method reference index - kIndexFieldRef, // field reference index - 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 - kIndexCallSiteRef, // call site index - kIndexMethodHandleRef, // constant method handle reference index - kIndexProtoRef, // constant prototype reference index -}; - -/* - * Instruction width implied by an opcode's format; a value in the - * range 0 to 5. Note that there are special "pseudo-instructions" - * which are used to encode switch and data tables, and these don't - * have a fixed width. See dexGetWidthFromInstruction(), below. - */ -typedef u1 InstructionWidth; - -/* - * Opcode control flow flags, used by the verifier and JIT. - */ -typedef u1 OpcodeFlags; -enum OpcodeFlagsBits { - kInstrCanBranch = 1, // conditional or unconditional branch - kInstrCanContinue = 1 << 1, // flow can continue to next statement - kInstrCanSwitch = 1 << 2, // switch statement - kInstrCanThrow = 1 << 3, // could cause an exception to be thrown - kInstrCanReturn = 1 << 4, // returns, no additional statements - kInstrInvoke = 1 << 5, // a flavor of invoke -}; - -/* - * Struct that includes a pointer to each of the opcode information - * tables. - * - * Note: We use "u1*" here instead of the names of the enumerated - * types to guarantee that elements don't use much space. We hold out - * hope for a standard way to indicate the size of an enumerated type - * that works for both C and C++, but in the mean time, this will - * suffice. - */ -struct InstructionInfoTables { - u1* formats; /* InstructionFormat elements */ - u1* indexTypes; /* InstructionIndexType elements */ - OpcodeFlags* flags; - InstructionWidth* widths; -}; - -/* - * Global InstructionInfoTables struct. - */ -extern InstructionInfoTables gDexOpcodeInfo; - -/* - * Holds the contents of a decoded instruction. - */ -struct DecodedInstruction { - u4 vA; - u4 vB; - u8 vB_wide; /* for kFmt51l */ - u4 vC; - u4 arg[5]; /* vC/D/E/F/G in invoke or filled-new-array */ - Opcode opcode; - InstructionIndexType indexType; -}; - -/* - * Return the instruction width of the specified opcode, or 0 if not defined. - */ -DEX_INLINE size_t dexGetWidthFromOpcode(Opcode opcode) -{ - assert((u4) opcode < kNumPackedOpcodes); - return gDexOpcodeInfo.widths[opcode]; -} - -/* - * Return the width of the specified instruction, or 0 if not defined. Also - * works for special OP_NOP entries, including switch statement data tables - * and array data. - */ -size_t dexGetWidthFromInstruction(const u2* insns); - -/* - * Returns the flags for the specified opcode. - */ -DEX_INLINE OpcodeFlags dexGetFlagsFromOpcode(Opcode opcode) -{ - assert((u4) opcode < kNumPackedOpcodes); - return gDexOpcodeInfo.flags[opcode]; -} - -/* - * Returns true if the given flags represent a goto (unconditional branch). - */ -DEX_INLINE bool dexIsGoto(OpcodeFlags flags) -{ - return (flags & (kInstrCanBranch | kInstrCanContinue)) == kInstrCanBranch; -} - -/* - * Return the instruction format for the specified opcode. - */ -DEX_INLINE InstructionFormat dexGetFormatFromOpcode(Opcode opcode) -{ - assert((u4) opcode < kNumPackedOpcodes); - return (InstructionFormat) gDexOpcodeInfo.formats[opcode]; -} - -/* - * Return the instruction index type for the specified opcode. - */ -DEX_INLINE InstructionIndexType dexGetIndexTypeFromOpcode(Opcode opcode) -{ - assert((u4) opcode < kNumPackedOpcodes); - return (InstructionIndexType) gDexOpcodeInfo.indexTypes[opcode]; -} - -/* - * Decode the instruction pointed to by "insns". - */ -void dexDecodeInstruction(const u2* insns, DecodedInstruction* pDec); - -#endif // LIBDEX_INSTRUTILS_H_ diff --git a/libdex/Leb128.cpp b/libdex/Leb128.cpp deleted file mode 100644 index ed09e19aa..000000000 --- a/libdex/Leb128.cpp +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * Functions for interpreting LEB128 (little endian base 128) values - */ - -#include "Leb128.h" - -/* - * Reads an unsigned LEB128 value, updating the given pointer to point - * just past the end of the read value and also indicating whether the - * value was syntactically valid. The only syntactically *invalid* - * values are ones that are five bytes long where the final byte has - * any but the low-order four bits set. Additionally, if the limit is - * passed as non-NULL and bytes would need to be read past the limit, - * then the read is considered invalid. - */ -int readAndVerifyUnsignedLeb128(const u1** pStream, const u1* limit, - bool* okay) { - const u1* ptr = *pStream; - int result = readUnsignedLeb128(pStream); - - if (((limit != NULL) && (*pStream > limit)) - || (((*pStream - ptr) == 5) && (ptr[4] > 0x0f))) { - *okay = false; - } - - return result; -} - -/* - * Reads a signed LEB128 value, updating the given pointer to point - * just past the end of the read value and also indicating whether the - * value was syntactically valid. The only syntactically *invalid* - * values are ones that are five bytes long where the final byte has - * any but the low-order four bits set. Additionally, if the limit is - * passed as non-NULL and bytes would need to be read past the limit, - * then the read is considered invalid. - */ -int readAndVerifySignedLeb128(const u1** pStream, const u1* limit, - bool* okay) { - const u1* ptr = *pStream; - int result = readSignedLeb128(pStream); - - if (((limit != NULL) && (*pStream > limit)) - || (((*pStream - ptr) == 5) && (ptr[4] > 0x0f))) { - *okay = false; - } - - return result; -} diff --git a/libdex/Leb128.h b/libdex/Leb128.h deleted file mode 100644 index 21f4edaa1..000000000 --- a/libdex/Leb128.h +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * Functions for interpreting LEB128 (little endian base 128) values - */ - -#ifndef LIBDEX_LEB128_H_ -#define LIBDEX_LEB128_H_ - -#include "DexFile.h" - -/* - * Reads an unsigned LEB128 value, updating the given pointer to point - * just past the end of the read value. This function tolerates - * non-zero high-order bits in the fifth encoded byte. - */ -DEX_INLINE int readUnsignedLeb128(const u1** pStream) { - const u1* ptr = *pStream; - int result = *(ptr++); - - if (result > 0x7f) { - int cur = *(ptr++); - result = (result & 0x7f) | ((cur & 0x7f) << 7); - if (cur > 0x7f) { - cur = *(ptr++); - result |= (cur & 0x7f) << 14; - if (cur > 0x7f) { - cur = *(ptr++); - result |= (cur & 0x7f) << 21; - if (cur > 0x7f) { - /* - * Note: We don't check to see if cur is out of - * range here, meaning we tolerate garbage in the - * high four-order bits. - */ - cur = *(ptr++); - result |= cur << 28; - } - } - } - } - - *pStream = ptr; - return result; -} - -/* - * Reads a signed LEB128 value, updating the given pointer to point - * just past the end of the read value. This function tolerates - * non-zero high-order bits in the fifth encoded byte. - */ -DEX_INLINE int readSignedLeb128(const u1** pStream) { - const u1* ptr = *pStream; - int result = *(ptr++); - - if (result <= 0x7f) { - result = (result << 25) >> 25; - } else { - int cur = *(ptr++); - result = (result & 0x7f) | ((cur & 0x7f) << 7); - if (cur <= 0x7f) { - result = (result << 18) >> 18; - } else { - cur = *(ptr++); - result |= (cur & 0x7f) << 14; - if (cur <= 0x7f) { - result = (result << 11) >> 11; - } else { - cur = *(ptr++); - result |= (cur & 0x7f) << 21; - if (cur <= 0x7f) { - result = (result << 4) >> 4; - } else { - /* - * Note: We don't check to see if cur is out of - * range here, meaning we tolerate garbage in the - * high four-order bits. - */ - cur = *(ptr++); - result |= cur << 28; - } - } - } - } - - *pStream = ptr; - return result; -} - -/* - * Reads an unsigned LEB128 value, updating the given pointer to point - * just past the end of the read value and also indicating whether the - * value was syntactically valid. The only syntactically *invalid* - * values are ones that are five bytes long where the final byte has - * any but the low-order four bits set. Additionally, if the limit is - * passed as non-NULL and bytes would need to be read past the limit, - * then the read is considered invalid. - */ -int readAndVerifyUnsignedLeb128(const u1** pStream, const u1* limit, - bool* okay); - -/* - * Reads a signed LEB128 value, updating the given pointer to point - * just past the end of the read value and also indicating whether the - * value was syntactically valid. The only syntactically *invalid* - * values are ones that are five bytes long where the final byte has - * any but the low-order four bits set. Additionally, if the limit is - * passed as non-NULL and bytes would need to be read past the limit, - * then the read is considered invalid. - */ -int readAndVerifySignedLeb128(const u1** pStream, const u1* limit, bool* okay); - - -/* - * Writes a 32-bit value in unsigned ULEB128 format. - * - * Returns the updated pointer. - */ -DEX_INLINE u1* writeUnsignedLeb128(u1* ptr, u4 data) -{ - while (true) { - u1 out = data & 0x7f; - if (out != data) { - *ptr++ = out | 0x80; - data >>= 7; - } else { - *ptr++ = out; - break; - } - } - - return ptr; -} - -/* - * Returns the number of bytes needed to encode "val" in ULEB128 form. - */ -DEX_INLINE int unsignedLeb128Size(u4 data) -{ - int count = 0; - - do { - data >>= 7; - count++; - } while (data != 0); - - return count; -} - -#endif diff --git a/libdex/OptInvocation.cpp b/libdex/OptInvocation.cpp deleted file mode 100644 index 35d6262e5..000000000 --- a/libdex/OptInvocation.cpp +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * Utility functions for dealing with optimized dex files. - */ - -#include <stdint.h> -#include <stdlib.h> -#include <unistd.h> -#include <fcntl.h> -#include <string.h> -#include <sys/stat.h> -#include <sys/file.h> -#include <errno.h> - -#include "OptInvocation.h" -#include "DexFile.h" - -static const char* kCacheDirectoryName = "dalvik-cache"; - -#if defined(__aarch64__) -static const char* kInstructionSet = "arm64"; -#elif defined(__arm__) -static const char* kInstructionSet = "arm"; -#elif defined(__i386__) -static const char* kInstructionSet = "x86"; -#elif defined(__mips__) -static const char* kInstructionSet = "mips"; -#elif defined(__x86_64__) -static const char* kInstructionSet = "x86_64"; -#else -#error Unsupported instruction set. -#endif - -static int dexOptMkdir(const char* path, int mode) -{ -#ifdef _WIN32 - return mkdir(path); -#else - return mkdir(path, mode); -#endif -} - -/* - * Given the filename of a .jar or .dex file, construct the DEX file cache - * name. - * - * For a Jar, "subFileName" is the name of the entry (usually "classes.dex"). - * For a DEX, it may be NULL. - * - * Returns a newly-allocated string, or NULL on failure. - */ -char* dexOptGenerateCacheFileName(const char* fileName, const char* subFileName) -{ - char nameBuf[512]; - char absoluteFile[sizeof(nameBuf)]; - const size_t kBufLen = sizeof(nameBuf) - 1; - const char* dataRoot; - char* cp; - - /* - * Get the absolute path of the Jar or DEX file. - */ - absoluteFile[0] = '\0'; - if (fileName[0] != '/') { - /* - * Generate the absolute path. This doesn't do everything it - * should, e.g. if filename is "./out/whatever" it doesn't crunch - * the leading "./" out, but it'll do. - */ - if (getcwd(absoluteFile, kBufLen) == NULL) { - ALOGE("Can't get CWD while opening jar file"); - return NULL; - } - strncat(absoluteFile, "/", kBufLen - strlen(absoluteFile)); - } - strncat(absoluteFile, fileName, kBufLen - strlen(absoluteFile)); - - /* - * Append the name of the Jar file entry, if any. This is not currently - * required, but will be if we start putting more than one DEX file - * in a Jar. - */ - if (subFileName != NULL) { - strncat(absoluteFile, "/", kBufLen - strlen(absoluteFile)); - strncat(absoluteFile, subFileName, kBufLen - strlen(absoluteFile)); - } - - /* Turn the path into a flat filename by replacing - * any slashes after the first one with '@' characters. - */ - cp = absoluteFile + 1; - while (*cp != '\0') { - if (*cp == '/') { - *cp = '@'; - } - cp++; - } - - /* Build the name of the cache directory. - */ - dataRoot = getenv("ANDROID_DATA"); - if (dataRoot == NULL) - dataRoot = "/data"; - snprintf(nameBuf, kBufLen, "%s/%s", dataRoot, kCacheDirectoryName); - if (strcmp(dataRoot, "/data") != 0) { - int result = dexOptMkdir(nameBuf, 0700); - if (result != 0 && errno != EEXIST) { - ALOGE("Failed to create dalvik-cache directory %s: %s", nameBuf, strerror(errno)); - return NULL; - } - } - snprintf(nameBuf, kBufLen, "%s/%s/%s", dataRoot, kCacheDirectoryName, kInstructionSet); - if (strcmp(dataRoot, "/data") != 0) { - int result = dexOptMkdir(nameBuf, 0700); - if (result != 0 && errno != EEXIST) { - ALOGE("Failed to create dalvik-cache directory %s: %s", nameBuf, strerror(errno)); - return NULL; - } - } - - /* Tack on the file name for the actual cache file path. - */ - strncat(nameBuf, absoluteFile, kBufLen - strlen(nameBuf)); - - ALOGV("Cache file for '%s' '%s' is '%s'", fileName, subFileName, nameBuf); - return strdup(nameBuf); -} - -/* - * Create a skeletal "opt" header in a new file. Most of the fields are - * initialized to garbage, but we fill in "dexOffset" so others can - * see how large the header is. - * - * "fd" must be positioned at the start of the file. On return, it will - * be positioned just past the header, and the place where the DEX data - * should go. - * - * Returns 0 on success, errno on failure. - */ -int dexOptCreateEmptyHeader(int fd) -{ - DexOptHeader optHdr; - ssize_t actual; - - assert(lseek(fd, 0, SEEK_CUR) == 0); - - /* - * The data is only expected to be readable on the current system, so - * we just write the structure. We do need the file offset to be 64-bit - * aligned to fulfill a DEX requirement. - */ - assert((sizeof(optHdr) & 0x07) == 0); - memset(&optHdr, 0xff, sizeof(optHdr)); - optHdr.dexOffset = sizeof(optHdr); - actual = write(fd, &optHdr, sizeof(optHdr)); - if (actual != sizeof(optHdr)) { - ALOGE("opt header write failed: %s", strerror(errno)); - return errno; - } - - return 0; -} diff --git a/libdex/OptInvocation.h b/libdex/OptInvocation.h deleted file mode 100644 index 3f32b94bf..000000000 --- a/libdex/OptInvocation.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * Utility functions related to "dexopt". - */ -#ifndef LIBDEX_OPTINVOCATION_H_ -#define LIBDEX_OPTINVOCATION_H_ - -/* - * Utility routines, used by the VM. - */ -char* dexOptGenerateCacheFileName(const char* fileName, - const char* subFileName); -int dexOptCreateEmptyHeader(int fd); - -#endif // LIBDEX_OPTINVOCATION_H_ diff --git a/libdex/SysUtil.cpp b/libdex/SysUtil.cpp deleted file mode 100644 index 3a1cba3b5..000000000 --- a/libdex/SysUtil.cpp +++ /dev/null @@ -1,370 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * System utilities. - */ -#include "DexFile.h" -#include "SysUtil.h" - -#include <stdlib.h> -#include <stdio.h> -#include <unistd.h> -#include <string.h> -#if !defined(__MINGW32__) -# include <sys/mman.h> -#endif -#include <limits.h> -#include <errno.h> - -/* - * TEMP_FAILURE_RETRY is defined by some, but not all, versions of - * <unistd.h>. (Alas, it is not as standard as we'd hoped!) So, if it's - * not already defined, then define it here. - */ -#ifndef TEMP_FAILURE_RETRY -/* Used to retry syscalls that can return EINTR. */ -#define TEMP_FAILURE_RETRY(exp) ({ \ - typeof (exp) _rc; \ - do { \ - _rc = (exp); \ - } while (_rc == -1 && errno == EINTR); \ - _rc; }) -#endif - -/* - * Create an anonymous shared memory segment large enough to hold "length" - * bytes. The actual segment may be larger because mmap() operates on - * page boundaries (usually 4K). - */ -static void* sysCreateAnonShmem(size_t length) -{ -#if !defined(__MINGW32__) - void* ptr; - - ptr = mmap(NULL, length, PROT_READ | PROT_WRITE, - MAP_SHARED | MAP_ANON, -1, 0); - if (ptr == MAP_FAILED) { - ALOGW("mmap(%d, RW, SHARED|ANON) failed: %s", (int) length, - strerror(errno)); - return NULL; - } - - return ptr; -#else - ALOGE("sysCreateAnonShmem not implemented."); - return NULL; -#endif -} - -/* - * Create a private anonymous storage area. - */ -int sysCreatePrivateMap(size_t length, MemMapping* pMap) -{ - void* memPtr; - - memPtr = sysCreateAnonShmem(length); - if (memPtr == NULL) - return -1; - - pMap->addr = pMap->baseAddr = memPtr; - pMap->length = pMap->baseLength = length; - return 0; -} - -/* - * Determine the current offset and remaining length of the open file. - */ -static int getFileStartAndLength(int fd, off_t *start_, size_t *length_) -{ - off_t start, end; - size_t length; - - assert(start_ != NULL); - assert(length_ != NULL); - - start = lseek(fd, 0L, SEEK_CUR); - end = lseek(fd, 0L, SEEK_END); - (void) lseek(fd, start, SEEK_SET); - - if (start == (off_t) -1 || end == (off_t) -1) { - ALOGE("could not determine length of file"); - return -1; - } - - length = end - start; - if (length == 0) { - ALOGE("file is empty"); - return -1; - } - - *start_ = start; - *length_ = length; - - return 0; -} - -#if defined(__MINGW32__) -int sysFakeMapFile(int fd, MemMapping* pMap) -{ - /* No MMAP, just fake it by copying the bits. - For Win32 we could use MapViewOfFile if really necessary - (see libs/utils/FileMap.cpp). - */ - off_t start; - size_t length; - void* memPtr; - - assert(pMap != NULL); - - if (getFileStartAndLength(fd, &start, &length) < 0) - return -1; - - memPtr = malloc(length); - if (read(fd, memPtr, length) < 0) { - ALOGW("read(fd=%d, start=%d, length=%d) failed: %s", (int) length, - fd, (int) start, strerror(errno)); - free(memPtr); - return -1; - } - - pMap->baseAddr = pMap->addr = memPtr; - pMap->baseLength = pMap->length = length; - - return 0; -} -#endif - -/* - * Map a file (from fd's current offset) into a private, read-write memory - * segment that will be marked read-only (a/k/a "writable read-only"). The - * file offset must be a multiple of the system page size. - * - * In some cases the mapping will be fully writable (e.g. for files on - * FAT filesystems). - * - * On success, returns 0 and fills out "pMap". On failure, returns a nonzero - * value and does not disturb "pMap". - */ -int sysMapFileInShmemWritableReadOnly(int fd, MemMapping* pMap) -{ -#if !defined(__MINGW32__) - off_t start; - size_t length; - void* memPtr; - - assert(pMap != NULL); - - if (getFileStartAndLength(fd, &start, &length) < 0) - return -1; - - memPtr = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_FILE | MAP_PRIVATE, - fd, start); - if (memPtr == MAP_FAILED) { - ALOGW("mmap(%d, R/W, FILE|PRIVATE, %d, %d) failed: %s", (int) length, - fd, (int) start, strerror(errno)); - return -1; - } - if (mprotect(memPtr, length, PROT_READ) < 0) { - /* this fails with EACCESS on FAT filesystems, e.g. /sdcard */ - int err = errno; - ALOGV("mprotect(%p, %zd, PROT_READ) failed: %s", - memPtr, length, strerror(err)); - ALOGD("mprotect(RO) failed (%d), file will remain read-write", err); - } - - pMap->baseAddr = pMap->addr = memPtr; - pMap->baseLength = pMap->length = length; - - return 0; -#else - return sysFakeMapFile(fd, pMap); -#endif -} - -/* - * Map part of a file into a shared, read-only memory segment. The "start" - * offset is absolute, not relative. - * - * On success, returns 0 and fills out "pMap". On failure, returns a nonzero - * value and does not disturb "pMap". - */ -int sysMapFileSegmentInShmem(int fd, off_t start, size_t length, - MemMapping* pMap) -{ -#if !defined(__MINGW32__) - size_t actualLength; - off_t actualStart; - int adjust; - void* memPtr; - - assert(pMap != NULL); - - /* adjust to be page-aligned */ - adjust = start % SYSTEM_PAGE_SIZE; - actualStart = start - adjust; - actualLength = length + adjust; - - memPtr = mmap(NULL, actualLength, PROT_READ, MAP_FILE | MAP_SHARED, - fd, actualStart); - if (memPtr == MAP_FAILED) { - ALOGW("mmap(%d, R, FILE|SHARED, %d, %d) failed: %s", - (int) actualLength, fd, (int) actualStart, strerror(errno)); - return -1; - } - - pMap->baseAddr = memPtr; - pMap->baseLength = actualLength; - pMap->addr = (char*)memPtr + adjust; - pMap->length = length; - - LOGVV("mmap seg (st=%d ln=%d): bp=%p bl=%d ad=%p ln=%d", - (int) start, (int) length, - pMap->baseAddr, (int) pMap->baseLength, - pMap->addr, (int) pMap->length); - - return 0; -#else - ALOGE("sysMapFileSegmentInShmem not implemented."); - return -1; -#endif -} - -/* - * Change the access rights on one or more pages to read-only or read-write. - * - * Returns 0 on success. - */ -int sysChangeMapAccess(void* addr, size_t length, int wantReadWrite, - MemMapping* pMap) -{ -#if !defined(__MINGW32__) - /* - * Verify that "addr" is part of this mapping file. - */ - if (addr < pMap->baseAddr || - (u1*)addr >= (u1*)pMap->baseAddr + pMap->baseLength) - { - ALOGE("Attempted to change %p; map is %p - %p", - addr, pMap->baseAddr, (u1*)pMap->baseAddr + pMap->baseLength); - return -1; - } - - /* - * Align "addr" to a page boundary and adjust "length" appropriately. - * (The address must be page-aligned, the length doesn't need to be, - * but we do need to ensure we cover the same range.) - */ - u1* alignAddr = (u1*) ((uintptr_t) addr & ~(SYSTEM_PAGE_SIZE-1)); - size_t alignLength = length + ((u1*) addr - alignAddr); - - //ALOGI("%p/%zd --> %p/%zd", addr, length, alignAddr, alignLength); - int prot = wantReadWrite ? (PROT_READ|PROT_WRITE) : (PROT_READ); - if (mprotect(alignAddr, alignLength, prot) != 0) { - ALOGV("mprotect (%p,%zd,%d) failed: %s", - alignAddr, alignLength, prot, strerror(errno)); - return (errno != 0) ? errno : -1; - } -#endif - - /* for "fake" mapping, no need to do anything */ - return 0; -} - -/* - * Release a memory mapping. - */ -void sysReleaseShmem(MemMapping* pMap) -{ -#if !defined(__MINGW32__) - if (pMap->baseAddr == NULL && pMap->baseLength == 0) - return; - - if (munmap(pMap->baseAddr, pMap->baseLength) < 0) { - ALOGW("munmap(%p, %zd) failed: %s", - pMap->baseAddr, pMap->baseLength, strerror(errno)); - } else { - ALOGV("munmap(%p, %zd) succeeded", pMap->baseAddr, pMap->baseLength); - pMap->baseAddr = NULL; - pMap->baseLength = 0; - } -#else - /* Free the bits allocated by sysMapFileInShmem. */ - if (pMap->baseAddr != NULL) { - free(pMap->baseAddr); - pMap->baseAddr = NULL; - } - pMap->baseLength = 0; -#endif -} - -/* - * Make a copy of a MemMapping. - */ -void sysCopyMap(MemMapping* dst, const MemMapping* src) -{ - memcpy(dst, src, sizeof(MemMapping)); -} - -/* - * Write until all bytes have been written. - * - * Returns 0 on success, or an errno value on failure. - */ -int sysWriteFully(int fd, const void* buf, size_t count, const char* logMsg) -{ - while (count != 0) { - ssize_t actual = TEMP_FAILURE_RETRY(write(fd, buf, count)); - if (actual < 0) { - int err = errno; - ALOGE("%s: write failed: %s", logMsg, strerror(err)); - return err; - } else if (actual != (ssize_t) count) { - ALOGD("%s: partial write (will retry): (%d of %zd)", - logMsg, (int) actual, count); - buf = (const void*) (((const u1*) buf) + actual); - } - count -= actual; - } - - return 0; -} - -/* See documentation comment in header file. */ -int sysCopyFileToFile(int outFd, int inFd, size_t count) -{ - const size_t kBufSize = 32768; - unsigned char buf[kBufSize]; - - while (count != 0) { - size_t getSize = (count > kBufSize) ? kBufSize : count; - - ssize_t actual = TEMP_FAILURE_RETRY(read(inFd, buf, getSize)); - if (actual != (ssize_t) getSize) { - ALOGW("sysCopyFileToFile: copy read failed (%d vs %zd)", - (int) actual, getSize); - return -1; - } - - if (sysWriteFully(outFd, buf, getSize, "sysCopyFileToFile") != 0) - return -1; - - count -= getSize; - } - - return 0; -} diff --git a/libdex/SysUtil.h b/libdex/SysUtil.h deleted file mode 100644 index c02ec6eda..000000000 --- a/libdex/SysUtil.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * System utilities. - */ -#ifndef LIBDEX_SYSUTIL_H_ -#define LIBDEX_SYSUTIL_H_ - -#include <sys/types.h> - -/* - * System page size. Normally you're expected to get this from - * sysconf(_SC_PAGESIZE) or some system-specific define (usually PAGESIZE - * or PAGE_SIZE). If we use a simple #define the compiler can generate - * appropriate masks directly, so we define it here and verify it as the - * VM is starting up. - * - * Must be a power of 2. - */ -#ifdef PAGE_SHIFT -#define SYSTEM_PAGE_SIZE (1<<PAGE_SHIFT) -#else -#define SYSTEM_PAGE_SIZE 4096 -#endif - -/* - * Use this to keep track of mapped segments. - */ -struct MemMapping { - void* addr; /* start of data */ - size_t length; /* length of data */ - - void* baseAddr; /* page-aligned base address */ - size_t baseLength; /* length of mapping */ -}; - -/* - * Copy a map. - */ -void sysCopyMap(MemMapping* dst, const MemMapping* src); - -/* - * Map a file (from fd's current offset) into a shared, read-only memory - * segment that can be made writable. (In some cases, such as when - * mapping a file on a FAT filesystem, the result may be fully writable.) - * - * On success, "pMap" is filled in, and zero is returned. - */ -int sysMapFileInShmemWritableReadOnly(int fd, MemMapping* pMap); - -/* - * Map part of a file into a shared, read-only memory segment. - * - * On success, "pMap" is filled in, and zero is returned. - */ -int sysMapFileSegmentInShmem(int fd, off_t start, size_t length, - MemMapping* pMap); - -/* - * Create a private anonymous mapping, useful for large allocations. - * - * On success, "pMap" is filled in, and zero is returned. - */ -int sysCreatePrivateMap(size_t length, MemMapping* pMap); - -/* - * Change the access rights on one or more pages. If "wantReadWrite" is - * zero, the pages will be made read-only; otherwise they will be read-write. - * - * Returns 0 on success. - */ -int sysChangeMapAccess(void* addr, size_t length, int wantReadWrite, - MemMapping* pmap); - -/* - * Release the pages associated with a shared memory segment. - * - * This does not free "pMap"; it just releases the memory. - */ -void sysReleaseShmem(MemMapping* pMap); - -/* - * Write until all bytes have been written. - * - * Returns 0 on success, or an errno value on failure. - */ -int sysWriteFully(int fd, const void* buf, size_t count, const char* logMsg); - -/* - * Copy the given number of bytes from one fd to another. Returns - * 0 on success, -1 on failure. - */ -int sysCopyFileToFile(int outFd, int inFd, size_t count); - -#endif // LIBDEX_SYSUTIL_H_ diff --git a/libdex/ZipArchive.h b/libdex/ZipArchive.h deleted file mode 100644 index 206afd55c..000000000 --- a/libdex/ZipArchive.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * Read-only access to Zip archives, with minimal heap allocation. - */ -#ifndef LIBDEX_ZIPARCHIVE_H_ -#define LIBDEX_ZIPARCHIVE_H_ - -#include <ziparchive/zip_archive.h> - -#include "SysUtil.h" -#include "DexFile.h" // need DEX_INLINE - -/* - * Open a Zip archive. - * - * On success, returns 0 and populates "pArchive". Returns nonzero errno - * value on failure. - */ -DEX_INLINE int dexZipOpenArchive(const char* fileName, ZipArchiveHandle* pArchive) { - return OpenArchive(fileName, pArchive); -} - -/* - * Like dexZipOpenArchive, but takes a file descriptor open for reading - * at the start of the file. The descriptor must be mappable (this does - * not allow access to a stream). - * - * "debugFileName" will appear in error messages, but is not otherwise used. - */ -DEX_INLINE int dexZipOpenArchiveFd(int fd, const char* debugFileName, - ZipArchiveHandle* pArchive) { - return OpenArchiveFd(fd, debugFileName, pArchive); -} - -/* - * Close archive, releasing resources associated with it. - * - * Depending on the implementation this could unmap pages used by classes - * stored in a Jar. This should only be done after unloading classes. - */ -DEX_INLINE void dexZipCloseArchive(ZipArchiveHandle archive) { - CloseArchive(archive); -} - -/* - * Return the archive's file descriptor. - */ -DEX_INLINE int dexZipGetArchiveFd(const ZipArchiveHandle pArchive) { - return GetFileDescriptor(pArchive); -} - -/* - * Find an entry in the Zip archive, by name. Returns NULL if the entry - * was not found. - */ -DEX_INLINE int dexZipFindEntry(const ZipArchiveHandle pArchive, - const char* entryName, ZipEntry* data) { - return FindEntry(pArchive, ZipString(entryName), data); -} - -/* - * Uncompress and write an entry to a file descriptor. - * - * Returns 0 on success. - */ -DEX_INLINE int dexZipExtractEntryToFile(ZipArchiveHandle handle, - ZipEntry* entry, int fd) { - return ExtractEntryToFile(handle, entry, fd); -} - -#endif // LIBDEX_ZIPARCHIVE_H_ diff --git a/libdex/sha1.cpp b/libdex/sha1.cpp deleted file mode 100644 index d59493451..000000000 --- a/libdex/sha1.cpp +++ /dev/null @@ -1,512 +0,0 @@ -/* - * Tweaked in various ways for Google/Android: - * - Changed from .cpp to .c. - * - Made argument to SHA1Update a const pointer, and enabled - * SHA1HANDSOFF. This incurs a speed penalty but prevents us from - * trashing the input. - * - Include <endian.h> to get endian info. - * - Split a small piece into a header file. - */ - -/* -sha1sum: inspired by md5sum. - -SHA-1 in C -By Steve Reid <steve@edmweb.com> -100% Public Domain - ------------------ -Modified 7/98 -By James H. Brown <jbrown@burgoyne.com> -Still 100% Public Domain - -bit machines -Routine SHA1Update changed from - void SHA1Update(SHA1_CTX* context, unsigned char* data, - unsigned int len) -to - void SHA1Update(SHA1_CTX* context, unsigned char* data, - unsigned long len) - -The 'len' parameter was declared an int which works fine on 32 -bit machines. However, on 16 bit machines an int is too small -for the shifts being done against it. This caused the hash -function to generate incorrect values if len was greater than -8191 (8K - 1) due to the 'len << 3' on line 3 of SHA1Update(). - -Since the file IO in main() reads 16K at a time, any file 8K or -larger would be guaranteed to generate the wrong hash (e.g. -Test Vector #3, a million "a"s). - -I also changed the declaration of variables i & j in SHA1Update -to unsigned long from unsigned int for the same reason. - -These changes should make no difference to any 32 bit -implementations since an int and a long are the same size in -those environments. - --- -I also corrected a few compiler warnings generated by Borland -C. -1. Added #include <process.h> for exit() prototype -2. Removed unused variable 'j' in SHA1Final -3. Changed exit(0) to return(0) at end of main. - -ALL changes I made can be located by searching for comments -containing 'JHB' - ------------------ -Modified 13 August 2000 -By Michael Paul Johnson <mpj@cryptography.org> -Still 100% Public Domain - -Changed command line syntax, added feature to automatically -check files against their previous SHA-1 check values, kind of -like md5sum does. Added functions hexval, verifyfile, -and sha1file. Rewrote main(). ------------------ - -Test Vectors (from FIPS PUB 180-1) -"abc" - A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D -"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" - 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 -A million repetitions of "a" - 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F -*/ - -#define SHA1HANDSOFF /*Copies data before messing with it.*/ - -/*#define CMDLINE * include main() and file processing */ - -#include "sha1.h" - -#include <stdio.h> -#include <string.h> -#ifdef __BORLANDC__ -#include <dir.h> -#include <dos.h> -#include <process.h> /* prototype for exit() - JHB - needed for Win32, but chokes Linux - MPJ */ -#define X_LITTLE_ENDIAN /* This should be #define'd if true.*/ -#else -# include <unistd.h> -# include <stdlib.h> -//# include <endian.h> -//# if __BYTE_ORDER == __LITTLE_ENDIAN -# define X_LITTLE_ENDIAN -//# endif -#endif -#include <ctype.h> - -#define LINESIZE 2048 - -static void SHA1Transform(unsigned long state[5], - const unsigned char buffer[64]); - -#define rol(value,bits) \ - (((value)<<(bits))|((value)>>(32-(bits)))) - -/* blk0() and blk() perform the initial expand. */ -/* I got the idea of expanding during the round function from - SSLeay */ -#ifdef X_LITTLE_ENDIAN -#define blk0(i) (block->l[i]=(rol(block->l[i],24)&0xFF00FF00) \ - |(rol(block->l[i],8)&0x00FF00FF)) -#else -#define blk0(i) block->l[i] -#endif -#define blk(i) (block->l[(i)&15] = rol(block->l[((i)+13)&15]^block->l[((i)+8)&15] \ - ^block->l[((i)+2)&15]^block->l[(i)&15],1)) - -/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ -#define R0(v,w,x,y,z,i) z+=(((w)&((x)^(y)))^(y))+blk0(i)+0x5A827999+rol(v,5);(w)=rol(w,30); -#define R1(v,w,x,y,z,i) z+=(((w)&((x)^(y)))^(y))+blk(i)+0x5A827999+rol(v,5);(w)=rol(w,30); -#define R2(v,w,x,y,z,i) z+=((w)^(x)^(y))+blk(i)+0x6ED9EBA1+rol(v,5);(w)=rol(w,30); -#define R3(v,w,x,y,z,i) z+=((((w)|(x))&(y))|((w)&(x)))+blk(i)+0x8F1BBCDC+rol(v,5);(w)=rol(w,30); -#define R4(v,w,x,y,z,i) z+=((w)^(x)^(y))+blk(i)+0xCA62C1D6+rol(v,5);(w)=rol(w,30); - - -/* Hash a single 512-bit block. This is the core of the algorithm. */ - -static void SHA1Transform(unsigned long state[5], - const unsigned char buffer[64]) -{ -unsigned long a, b, c, d, e; -union CHAR64LONG16 { - unsigned char c[64]; - unsigned long l[16]; -}; -CHAR64LONG16* block; -#ifdef SHA1HANDSOFF -static unsigned char workspace[64]; - block = (CHAR64LONG16*)workspace; - memcpy(block, buffer, 64); -#else - block = (CHAR64LONG16*)buffer; -#endif - /* Copy context->state[] to working vars */ - a = state[0]; - b = state[1]; - c = state[2]; - d = state[3]; - e = state[4]; - /* 4 rounds of 20 operations each. Loop unrolled. */ - R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); - R0(c,d,e,a,b, 3); R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); - R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); R0(c,d,e,a,b, 8); - R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); - R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); - R0(a,b,c,d,e,15); R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); - R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); R2(a,b,c,d,e,20); - R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); - R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); - R2(d,e,a,b,c,27); R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); - R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); R2(d,e,a,b,c,32); - R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); - R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); - R2(b,c,d,e,a,39); R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); - R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); R3(b,c,d,e,a,44); - R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); - R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); - R3(e,a,b,c,d,51); R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); - R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); R3(e,a,b,c,d,56); - R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); - R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); - R4(c,d,e,a,b,63); R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); - R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); R4(c,d,e,a,b,68); - R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); - R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); - R4(a,b,c,d,e,75); R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); - R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); - - /* Add the working vars back into context.state[] */ - state[0] += a; - state[1] += b; - state[2] += c; - state[3] += d; - state[4] += e; - /* Wipe variables */ -/* a = b = c = d = e = 0; Nice try, but the compiler -optimizes this out, anyway, and it produces an annoying -warning. */ -} - - -/* SHA1Init - Initialize new context */ - -void SHA1Init(SHA1_CTX* context) -{ - /* SHA1 initialization constants */ - context->state[0] = 0x67452301; - context->state[1] = 0xEFCDAB89; - context->state[2] = 0x98BADCFE; - context->state[3] = 0x10325476; - context->state[4] = 0xC3D2E1F0; - context->count[0] = context->count[1] = 0; -} - - -/* Run your data through this. */ - -void SHA1Update(SHA1_CTX* context, const unsigned char* data, - unsigned long len) /* JHB */ -{ - unsigned long i, j; /* JHB */ - - j = (context->count[0] >> 3) & 63; - if ((context->count[0] += len << 3) < (len << 3)) - context->count[1]++; - context->count[1] += (len >> 29); - if ((j + len) > 63) - { - memcpy(&context->buffer[j], data, (i = 64-j)); - SHA1Transform(context->state, context->buffer); - for ( ; i + 63 < len; i += 64) { - SHA1Transform(context->state, &data[i]); - } - j = 0; - } - else - i = 0; - memcpy(&context->buffer[j], &data[i], len - i); -} - - -/* Add padding and return the message digest. */ - -void SHA1Final(unsigned char digest[HASHSIZE], SHA1_CTX* -context) -{ -unsigned long i; /* JHB */ -unsigned char finalcount[8]; - - for (i = 0; i < 8; i++) - { - finalcount[i] = (unsigned char)((context->count[(i>=4? - 0:1)]>>((3-(i&3))*8))&255); - /* Endian independent */ - } - SHA1Update(context, (unsigned char *)"\200", 1); - while ((context->count[0] & 504) != 448) { - SHA1Update(context, (unsigned char *)"\0", 1); - } - SHA1Update(context, finalcount, 8); - /* Should cause a SHA1Transform() */ - for (i = 0; i < HASHSIZE; i++) { - digest[i] = (unsigned char) - ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); - } - /* Wipe variables */ - memset(context->buffer, 0, 64); - memset(context->state, 0, HASHSIZE); - memset(context->count, 0, 8); - memset(&finalcount, 0, 8); -#ifdef SHA1HANDSOFF - /* make SHA1Transform overwrite it's own static vars */ - SHA1Transform(context->state, context->buffer); -#endif -} - - - -#ifdef CMDLINE - -/* sha1file computes the SHA-1 hash of the named file and puts - it in the 20-byte array digest. If fname is NULL, stdin is - assumed. -*/ -void sha1file(char *fname, unsigned char* digest) -{ - int bytesread; - SHA1_CTX context; - unsigned char buffer[16384]; - FILE* f; - - if (fname) - { - f = fopen(fname, "rb"); - if (!f) - { - fprintf(stderr, "Can't open %s\n", fname); - memset(digest, 0, HASHSIZE); - return; - } - } - else - { - f = stdin; - } - SHA1Init(&context); - while (!feof(f)) - { - bytesread = fread(buffer, 1, 16384, f); - SHA1Update(&context, buffer, bytesread); - } - SHA1Final(digest, &context); - if (fname) - fclose(f); -} - -/* Convert ASCII hexidecimal digit to 4-bit value. */ -unsigned char hexval(char c) -{ - unsigned char h; - - c = toupper(c); - if (c >= 'A') - h = c - 'A' + 10; - else - h = c - '0'; - return h; -} - -/* Verify a file created with sha1sum by redirecting output - to a file. */ -int verifyfile(char *fname) -{ - int j, k; - int found = 0; - unsigned char digest[HASHSIZE]; - unsigned char expected_digest[HASHSIZE]; - FILE *checkfile; - char checkline[LINESIZE]; - char *s; - unsigned char err; - - checkfile = fopen(fname, "rt"); - if (!checkfile) - { - fprintf(stderr, "Can't open %s\n", fname); - return(0); - } - do - { - s = fgets(checkline, LINESIZE, checkfile); - if (s) - { - if ((strlen(checkline)>26)&& - 1 /*(!strncmp(checkline,"SHA1=", 5))*/) - { - /* Overwrite newline. */ - checkline[strlen(checkline)-1]=0; - found = 1; - - /* Read expected check value. */ - for (k=0, j=5; k < HASHSIZE; k++) - { - expected_digest[k]=hexval(checkline[j++]); - expected_digest[k]=(expected_digest[k]<<4) - +hexval(checkline[j++]); - } - - /* Compute fingerprints */ - s = checkline+46; - sha1file(s, digest); - - /* Compare fingerprints */ - err = 0; - for (k=0; k<HASHSIZE; k++) - err |= digest[k]- - expected_digest[k]; - if (err) - { - fprintf(stderr, "FAILED: %s\n" - " EXPECTED: ", s); - for (k=0; k<HASHSIZE; k++) - fprintf(stderr, "%02X", - expected_digest[k]); - fprintf(stderr,"\n FOUND: "); - for (k=0; k<HASHSIZE; k++) - fprintf(stderr, "%02X", digest[k]); - fprintf(stderr, "\n"); - } - else - { - printf("OK: %s\n", s); - } - } - } - } while (s); - fclose(checkfile); - return found; -} - - - -void syntax(char *progname) -{ - printf("\nsyntax:\n" - "%s [-c|-h][-q] file name[s]\n" - " -c = check files against previous check values\n" - " -g = generate SHA-1 check values (default action)\n" - " -h = display this help\n" - "For example,\n" - "sha1sum test.txt > check.txt\n" - "generates check value for test.txt in check.txt, and\n" - "sha1sum -c check.txt\n" - "checks test.txt against the check value in check.txt\n", - progname); - exit(1); -} - - -/**********************************************************/ - -int main(int argc, char** argv) -{ - int i, j, k; - int check = 0; - int found = 0; - unsigned char digest[HASHSIZE]; - unsigned char expected_digest[HASHSIZE]; - FILE *checkfile; - char checkline[LINESIZE]; - char *s; -#ifdef __BORLANDC__ - struct ffblk f; - int done; - char path[MAXPATH]; - char drive[MAXDRIVE]; - char dir[MAXDIR]; - char name[MAXFILE]; - char ext[MAXEXT]; -#endif - unsigned char err; - - for (i = 1; i < argc; i++) - { - if (argv[i][0] == '-') - { - switch (argv[i][1]) - { - case 'c': - case 'C': - check = 1; - break; - case 'g': - case 'G': - check = 0; - break; - default: - syntax(argv[0]); - } - } - } - - for (i=1; i<argc; i++) - { - if (argv[i][0] != '-') - { -#ifdef __BORLANDC__ - fnsplit(argv[i], drive, dir, name, ext); - done = findfirst(argv[i], &f, FA_RDONLY | - FA_HIDDEN|FA_SYSTEM|FA_ARCH); - while (!done) - { - sprintf(path, "%s%s%s", drive, dir, f.ff_name); - s = path; -#else - s = argv[i]; -#endif - - if (check) - { /* Check fingerprint file. */ - found |= verifyfile(s); - } - else - { /* Generate fingerprints & write to - stdout. */ - sha1file(s, digest); - //printf("SHA1="); - for (j=0; j<HASHSIZE; j++) - printf("%02x", digest[j]); - printf(" %s\n", s); - found = 1; - } - -#ifdef __BORLANDC__ - done = findnext(&f); - } -#endif - - } - } - if (!found) - { - if (check) - { - fprintf(stderr, - "No SHA1 lines found in %s\n", - argv[i]); - } - else - { - fprintf(stderr, "No files checked.\n"); - syntax(argv[0]); - } - } - return(0); /* JHB */ -} - -#endif /*CMDLINE*/ diff --git a/libdex/sha1.h b/libdex/sha1.h deleted file mode 100644 index 28907dedc..000000000 --- a/libdex/sha1.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * See "sha1.cpp" for author info. - */ -#ifndef LIBDEX_SHA1_H_ -#define LIBDEX_SHA1_H_ - -struct SHA1_CTX { - unsigned long state[5]; - unsigned long count[2]; - unsigned char buffer[64]; -}; - -#define HASHSIZE 20 - -void SHA1Init(SHA1_CTX* context); -void SHA1Update(SHA1_CTX* context, const unsigned char* data, - unsigned long len); -void SHA1Final(unsigned char digest[HASHSIZE], SHA1_CTX* context); - -#endif // LIBDEX_SHA1_H_ |