1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 /* 18 * Functions for dealing with try-catch info. 19 */ 20 21 #ifndef LIBDEX_DEXCATCH_H_ 22 #define LIBDEX_DEXCATCH_H_ 23 24 #include "DexFile.h" 25 #include "Leb128.h" 26 27 /* 28 * Catch handler entry, used while iterating over catch_handler_items. 29 */ 30 struct DexCatchHandler { 31 u4 typeIdx; /* type index of the caught exception type */ 32 u4 address; /* handler address */ 33 }; 34 35 /* Get the first handler offset for the given DexCode. 36 * It's not 0 because the handlers list is prefixed with its size 37 * (in entries) as a uleb128. */ 38 u4 dexGetFirstHandlerOffset(const DexCode* pCode); 39 40 /* Get count of handler lists for the given DexCode. */ 41 u4 dexGetHandlersSize(const DexCode* pCode); 42 43 /* 44 * Iterator over catch handler data. This structure should be treated as 45 * opaque. 46 */ 47 struct DexCatchIterator { 48 const u1* pEncodedData; 49 bool catchesAll; 50 u4 countRemaining; 51 DexCatchHandler handler; 52 }; 53 54 /* Initialize a DexCatchIterator to emptiness. This mostly exists to 55 * squelch innocuous warnings. */ 56 DEX_INLINE void dexCatchIteratorClear(DexCatchIterator* pIterator) { 57 pIterator->pEncodedData = NULL; 58 pIterator->catchesAll = false; 59 pIterator->countRemaining = 0; 60 pIterator->handler.typeIdx = 0; 61 pIterator->handler.address = 0; 62 } 63 64 /* Initialize a DexCatchIterator with a direct pointer to encoded handlers. */ 65 DEX_INLINE void dexCatchIteratorInitToPointer(DexCatchIterator* pIterator, 66 const u1* pEncodedData) 67 { 68 s4 count = readSignedLeb128(&pEncodedData); 69 70 if (count <= 0) { 71 pIterator->catchesAll = true; 72 count = -count; 73 } else { 74 pIterator->catchesAll = false; 75 } 76 77 pIterator->pEncodedData = pEncodedData; 78 pIterator->countRemaining = count; 79 } 80 81 /* Initialize a DexCatchIterator to a particular handler offset. */ 82 DEX_INLINE void dexCatchIteratorInit(DexCatchIterator* pIterator, 83 const DexCode* pCode, u4 offset) 84 { 85 dexCatchIteratorInitToPointer(pIterator, 86 dexGetCatchHandlerData(pCode) + offset); 87 } 88 89 /* Get the next item from a DexCatchIterator. Returns NULL if at end. */ 90 DEX_INLINE DexCatchHandler* dexCatchIteratorNext(DexCatchIterator* pIterator) { 91 if (pIterator->countRemaining == 0) { 92 if (! pIterator->catchesAll) { 93 return NULL; 94 } 95 96 pIterator->catchesAll = false; 97 pIterator->handler.typeIdx = kDexNoIndex; 98 } else { 99 u4 typeIdx = readUnsignedLeb128(&pIterator->pEncodedData); 100 pIterator->handler.typeIdx = typeIdx; 101 pIterator->countRemaining--; 102 } 103 104 pIterator->handler.address = readUnsignedLeb128(&pIterator->pEncodedData); 105 return &pIterator->handler; 106 } 107 108 /* Get the handler offset just past the end of the one just iterated over. 109 * This ends the iteration if it wasn't already. */ 110 u4 dexCatchIteratorGetEndOffset(DexCatchIterator* pIterator, 111 const DexCode* pCode); 112 113 /* Helper for dexFindCatchHandler(). Do not call directly. */ 114 int dexFindCatchHandlerOffset0(u2 triesSize, const DexTry* pTries, 115 u4 address); 116 117 /* Find the handler associated with a given address, if any. 118 * Initializes the given iterator and returns true if a match is 119 * found. Returns false if there is no applicable handler. */ 120 DEX_INLINE bool dexFindCatchHandler(DexCatchIterator *pIterator, 121 const DexCode* pCode, u4 address) { 122 u2 triesSize = pCode->triesSize; 123 int offset = -1; 124 125 // Short-circuit the overwhelmingly common cases. 126 switch (triesSize) { 127 case 0: { 128 break; 129 } 130 case 1: { 131 const DexTry* tries = dexGetTries(pCode); 132 u4 start = tries[0].startAddr; 133 134 if (address < start) { 135 break; 136 } 137 138 u4 end = start + tries[0].insnCount; 139 140 if (address >= end) { 141 break; 142 } 143 144 offset = tries[0].handlerOff; 145 break; 146 } 147 default: { 148 offset = dexFindCatchHandlerOffset0(triesSize, dexGetTries(pCode), 149 address); 150 } 151 } 152 153 if (offset < 0) { 154 dexCatchIteratorClear(pIterator); // This squelches warnings. 155 return false; 156 } else { 157 dexCatchIteratorInit(pIterator, pCode, offset); 158 return true; 159 } 160 } 161 162 #endif // LIBDEX_DEXCATCH_H_ 163