• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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. */
dexCatchIteratorClear(DexCatchIterator * pIterator)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. */
dexCatchIteratorInitToPointer(DexCatchIterator * pIterator,const u1 * pEncodedData)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. */
dexCatchIteratorInit(DexCatchIterator * pIterator,const DexCode * pCode,u4 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. */
dexCatchIteratorNext(DexCatchIterator * pIterator)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. */
dexFindCatchHandler(DexCatchIterator * pIterator,const DexCode * pCode,u4 address)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