| /* | 
 |  * 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. | 
 |  */ | 
 |  | 
 | /* | 
 |  * Verification-time map of data section items | 
 |  */ | 
 |  | 
 | #include "DexDataMap.h" | 
 | #include <safe_iop.h> | 
 | #include <stdlib.h> | 
 |  | 
 | /* | 
 |  * Allocate and initialize a DexDataMap. Returns NULL on failure. | 
 |  */ | 
 | DexDataMap* dexDataMapAlloc(u4 maxCount) { | 
 |     /* | 
 |      * Allocate a single chunk for the DexDataMap per se as well as the | 
 |      * two arrays. | 
 |      */ | 
 |     size_t size = 0; | 
 |     DexDataMap* map = NULL; | 
 |  | 
 |     /* | 
 |      * Avoiding pulling in safe_iop for safe_iopf. | 
 |      */ | 
 |     if (!safe_mul(&size, maxCount, sizeof(u4) + sizeof(u2)) || | 
 |         !safe_add(&size, size, sizeof(DexDataMap))) { | 
 |       return NULL; | 
 |     } | 
 |  | 
 |     map = malloc(size); | 
 |  | 
 |     if (map == NULL) { | 
 |         return NULL; | 
 |     } | 
 |  | 
 |     map->count = 0; | 
 |     map->max = maxCount; | 
 |     map->offsets = (u4*) (map + 1); | 
 |     map->types = (u2*) (map->offsets + maxCount); | 
 |  | 
 |     return map; | 
 | } | 
 |  | 
 | /* | 
 |  * Free a DexDataMap. | 
 |  */ | 
 | void dexDataMapFree(DexDataMap* map) { | 
 |     /* | 
 |      * Since everything got allocated together, everything can be freed | 
 |      * in one fell swoop. Also, free(NULL) is a nop (per spec), so we | 
 |      * don't have to worry about an explicit test for that. | 
 |      */ | 
 |     free(map); | 
 | } | 
 |  | 
 | /* | 
 |  * Add a new element to the map. The offset must be greater than the | 
 |  * all previously added offsets. | 
 |  */ | 
 | void dexDataMapAdd(DexDataMap* map, u4 offset, u2 type) { | 
 |     assert(map != NULL); | 
 |     assert(map->count < map->max); | 
 |  | 
 |     if ((map->count != 0) && | 
 |             (map->offsets[map->count - 1] >= offset)) { | 
 |         LOGE("Out-of-order data map offset: 0x%x then 0x%x\n", | 
 |                 map->offsets[map->count - 1], offset); | 
 |         return; | 
 |     } | 
 |  | 
 |     map->offsets[map->count] = offset; | 
 |     map->types[map->count] = type; | 
 |     map->count++; | 
 | } | 
 |  | 
 | /* | 
 |  * Get the type associated with the given offset. This returns -1 if | 
 |  * there is no entry for the given offset. | 
 |  */ | 
 | int dexDataMapGet(DexDataMap* map, u4 offset) { | 
 |     assert(map != NULL); | 
 |  | 
 |     // Note: Signed type is important for max and min. | 
 |     int min = 0; | 
 |     int max = map->count - 1; | 
 |     u4* offsets = map->offsets; | 
 |  | 
 |     while (max >= min) { | 
 |         int guessIdx = (min + max) >> 1; | 
 |         u4 guess = offsets[guessIdx]; | 
 |  | 
 |         if (offset < guess) { | 
 |             max = guessIdx - 1; | 
 |         } else if (offset > guess) { | 
 |             min = guessIdx + 1; | 
 |         } else { | 
 |             // We have a winner! | 
 |             return map->types[guessIdx]; | 
 |         } | 
 |     } | 
 |  | 
 |     // No match. | 
 |     return -1; | 
 | } | 
 |  | 
 | /* | 
 |  * Verify that there is an entry in the map, mapping the given offset to | 
 |  * the given type. This will return true if such an entry exists and | 
 |  * return false as well as log an error if not. | 
 |  */ | 
 | bool dexDataMapVerify(DexDataMap* map, u4 offset, u2 type) { | 
 |     int found = dexDataMapGet(map, offset); | 
 |  | 
 |     if (found == type) { | 
 |         return true; | 
 |     } | 
 |  | 
 |     if (found < 0) { | 
 |         LOGE("No data map entry found @ 0x%x; expected %x\n", | 
 |                 offset, type); | 
 |     } else { | 
 |         LOGE("Unexpected data map entry @ 0x%x: expected %x, found %x\n", | 
 |                 offset, type, found); | 
 |     } | 
 |  | 
 |     return false; | 
 | } |