Home | History | Annotate | Download | only in libdex
      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