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  * Verification-time map of data section items
19  */
20 
21 #include "DexDataMap.h"
22 #include <stdlib.h>
23 
24 /*
25  * Allocate and initialize a DexDataMap. Returns NULL on failure.
26  */
dexDataMapAlloc(u4 maxCount)27 DexDataMap* dexDataMapAlloc(u4 maxCount) {
28     /*
29      * Allocate a single chunk for the DexDataMap itself as well as the
30      * two arrays.
31      */
32     size_t size = 0;
33     DexDataMap* map = NULL;
34 
35     const u4 sizeOfItems = (u4) (sizeof(u4) + sizeof(u2));
36     if (__builtin_mul_overflow(maxCount, sizeOfItems, &size) ||
37         __builtin_add_overflow(size, sizeof(DexDataMap), &size)) {
38       return NULL;
39     }
40 
41     map = (DexDataMap*) malloc(size);
42 
43     if (map == NULL) {
44         return NULL;
45     }
46 
47     map->count = 0;
48     map->max = maxCount;
49     map->offsets = (u4*) (map + 1);
50     map->types = (u2*) (map->offsets + maxCount);
51 
52     return map;
53 }
54 
55 /*
56  * Free a DexDataMap.
57  */
dexDataMapFree(DexDataMap * map)58 void dexDataMapFree(DexDataMap* map) {
59     /*
60      * Since everything got allocated together, everything can be freed
61      * in one fell swoop. Also, free(NULL) is a nop (per spec), so we
62      * don't have to worry about an explicit test for that.
63      */
64     free(map);
65 }
66 
67 /*
68  * Add a new element to the map. The offset must be greater than the
69  * all previously added offsets.
70  */
dexDataMapAdd(DexDataMap * map,u4 offset,u2 type)71 void dexDataMapAdd(DexDataMap* map, u4 offset, u2 type) {
72     assert(map != NULL);
73     assert(map->count < map->max);
74 
75     if ((map->count != 0) &&
76             (map->offsets[map->count - 1] >= offset)) {
77         ALOGE("Out-of-order data map offset: %#x then %#x",
78                 map->offsets[map->count - 1], offset);
79         return;
80     }
81 
82     map->offsets[map->count] = offset;
83     map->types[map->count] = type;
84     map->count++;
85 }
86 
87 /*
88  * Get the type associated with the given offset. This returns -1 if
89  * there is no entry for the given offset.
90  */
dexDataMapGet(DexDataMap * map,u4 offset)91 int dexDataMapGet(DexDataMap* map, u4 offset) {
92     assert(map != NULL);
93 
94     // Note: Signed type is important for max and min.
95     int min = 0;
96     int max = map->count - 1;
97     u4* offsets = map->offsets;
98 
99     while (max >= min) {
100         int guessIdx = (min + max) >> 1;
101         u4 guess = offsets[guessIdx];
102 
103         if (offset < guess) {
104             max = guessIdx - 1;
105         } else if (offset > guess) {
106             min = guessIdx + 1;
107         } else {
108             // We have a winner!
109             return map->types[guessIdx];
110         }
111     }
112 
113     // No match.
114     return -1;
115 }
116 
117 /*
118  * Verify that there is an entry in the map, mapping the given offset to
119  * the given type. This will return true if such an entry exists and
120  * return false as well as log an error if not.
121  */
dexDataMapVerify(DexDataMap * map,u4 offset,u2 type)122 bool dexDataMapVerify(DexDataMap* map, u4 offset, u2 type) {
123     int found = dexDataMapGet(map, offset);
124 
125     if (found == type) {
126         return true;
127     }
128 
129     if (found < 0) {
130         ALOGE("No data map entry found @ %#x; expected %x",
131                 offset, type);
132     } else {
133         ALOGE("Unexpected data map entry @ %#x: expected %x, found %x",
134                 offset, type, found);
135     }
136 
137     return false;
138 }
139