diff options
Diffstat (limited to 'libdex/DexCatch.h')
-rw-r--r-- | libdex/DexCatch.h | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/libdex/DexCatch.h b/libdex/DexCatch.h new file mode 100644 index 0000000..cfea2d9 --- /dev/null +++ b/libdex/DexCatch.h @@ -0,0 +1,162 @@ +/* + * 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_ |