/* * 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_