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 * VM-specific state associated with a DEX file. 19 */ 20 #include "Dalvik.h" 21 22 23 /* 24 * Create auxillary data structures. 25 * 26 * We need a 4-byte pointer for every reference to a class, method, field, 27 * or string constant. Summed up over all loaded DEX files (including the 28 * whoppers in the boostrap class path), this adds up to be quite a bit 29 * of native memory. 30 * 31 * For more traditional VMs these values could be stuffed into the loaded 32 * class file constant pool area, but we don't have that luxury since our 33 * classes are memory-mapped read-only. 34 * 35 * The DEX optimizer will remove the need for some of these (e.g. we won't 36 * use the entry for virtual methods that are only called through 37 * invoke-virtual-quick), creating the possibility of some space reduction 38 * at dexopt time. 39 */ 40 static DvmDex* allocateAuxStructures(DexFile* pDexFile) 41 { 42 DvmDex* pDvmDex; 43 const DexHeader* pHeader; 44 u4 stringCount, classCount, methodCount, fieldCount; 45 46 pDvmDex = (DvmDex*) calloc(1, sizeof(DvmDex)); 47 if (pDvmDex == NULL) 48 return NULL; 49 50 pDvmDex->pDexFile = pDexFile; 51 pDvmDex->pHeader = pDexFile->pHeader; 52 53 pHeader = pDvmDex->pHeader; 54 55 stringCount = pHeader->stringIdsSize; 56 classCount = pHeader->typeIdsSize; 57 methodCount = pHeader->methodIdsSize; 58 fieldCount = pHeader->fieldIdsSize; 59 60 pDvmDex->pResStrings = (struct StringObject**) 61 calloc(stringCount, sizeof(struct StringObject*)); 62 63 pDvmDex->pResClasses = (struct ClassObject**) 64 calloc(classCount, sizeof(struct ClassObject*)); 65 66 pDvmDex->pResMethods = (struct Method**) 67 calloc(methodCount, sizeof(struct Method*)); 68 69 pDvmDex->pResFields = (struct Field**) 70 calloc(fieldCount, sizeof(struct Field*)); 71 72 LOGV("+++ DEX %p: allocateAux %d+%d+%d+%d * 4 = %d bytes\n", 73 pDvmDex, stringCount, classCount, methodCount, fieldCount, 74 (stringCount + classCount + methodCount + fieldCount) * 4); 75 76 pDvmDex->pInterfaceCache = dvmAllocAtomicCache(DEX_INTERFACE_CACHE_SIZE); 77 78 if (pDvmDex->pResStrings == NULL || 79 pDvmDex->pResClasses == NULL || 80 pDvmDex->pResMethods == NULL || 81 pDvmDex->pResFields == NULL || 82 pDvmDex->pInterfaceCache == NULL) 83 { 84 LOGE("Alloc failure in allocateAuxStructures\n"); 85 free(pDvmDex->pResStrings); 86 free(pDvmDex->pResClasses); 87 free(pDvmDex->pResMethods); 88 free(pDvmDex->pResFields); 89 free(pDvmDex); 90 return NULL; 91 } 92 93 return pDvmDex; 94 95 } 96 97 /* 98 * Given an open optimized DEX file, map it into read-only shared memory and 99 * parse the contents. 100 * 101 * Returns nonzero on error. 102 */ 103 int dvmDexFileOpenFromFd(int fd, DvmDex** ppDvmDex) 104 { 105 DvmDex* pDvmDex; 106 DexFile* pDexFile; 107 MemMapping memMap; 108 int parseFlags = kDexParseDefault; 109 int result = -1; 110 111 if (gDvm.verifyDexChecksum) 112 parseFlags |= kDexParseVerifyChecksum; 113 114 if (lseek(fd, 0, SEEK_SET) < 0) { 115 LOGE("lseek rewind failed\n"); 116 goto bail; 117 } 118 119 if (sysMapFileInShmemWritableReadOnly(fd, &memMap) != 0) { 120 LOGE("Unable to map file\n"); 121 goto bail; 122 } 123 124 pDexFile = dexFileParse(memMap.addr, memMap.length, parseFlags); 125 if (pDexFile == NULL) { 126 LOGE("DEX parse failed\n"); 127 sysReleaseShmem(&memMap); 128 goto bail; 129 } 130 131 pDvmDex = allocateAuxStructures(pDexFile); 132 if (pDvmDex == NULL) { 133 dexFileFree(pDexFile); 134 sysReleaseShmem(&memMap); 135 goto bail; 136 } 137 138 /* tuck this into the DexFile so it gets released later */ 139 sysCopyMap(&pDvmDex->memMap, &memMap); 140 *ppDvmDex = pDvmDex; 141 result = 0; 142 143 bail: 144 return result; 145 } 146 147 /* 148 * Create a DexFile structure for a "partial" DEX. This is one that is in 149 * the process of being optimized. The optimization header isn't finished 150 * and we won't have any of the auxillary data tables, so we have to do 151 * the initialization slightly differently. 152 * 153 * Returns nonzero on error. 154 */ 155 int dvmDexFileOpenPartial(const void* addr, int len, DvmDex** ppDvmDex) 156 { 157 DvmDex* pDvmDex; 158 DexFile* pDexFile; 159 int parseFlags = kDexParseDefault; 160 int result = -1; 161 162 /* -- file is incomplete, new checksum has not yet been calculated 163 if (gDvm.verifyDexChecksum) 164 parseFlags |= kDexParseVerifyChecksum; 165 */ 166 167 pDexFile = dexFileParse(addr, len, parseFlags); 168 if (pDexFile == NULL) { 169 LOGE("DEX parse failed\n"); 170 goto bail; 171 } 172 pDvmDex = allocateAuxStructures(pDexFile); 173 if (pDvmDex == NULL) { 174 dexFileFree(pDexFile); 175 goto bail; 176 } 177 178 *ppDvmDex = pDvmDex; 179 result = 0; 180 181 bail: 182 return result; 183 } 184 185 /* 186 * Free up the DexFile and any associated data structures. 187 * 188 * Note we may be called with a partially-initialized DvmDex. 189 */ 190 void dvmDexFileFree(DvmDex* pDvmDex) 191 { 192 if (pDvmDex == NULL) 193 return; 194 195 dexFileFree(pDvmDex->pDexFile); 196 197 LOGV("+++ DEX %p: freeing aux structs\n", pDvmDex); 198 free(pDvmDex->pResStrings); 199 free(pDvmDex->pResClasses); 200 free(pDvmDex->pResMethods); 201 free(pDvmDex->pResFields); 202 dvmFreeAtomicCache(pDvmDex->pInterfaceCache); 203 204 sysReleaseShmem(&pDvmDex->memMap); 205 free(pDvmDex); 206 } 207 208 209 /* 210 * Change the byte at the specified address to a new value. If the location 211 * already has the new value, do nothing. 212 * 213 * This requires changing the access permissions to read-write, updating 214 * the value, and then resetting the permissions. 215 * 216 * We need to ensure mutual exclusion at a page granularity to avoid a race 217 * where one threads sets read-write, another thread sets read-only, and 218 * then the first thread does a write. Since we don't do a lot of updates, 219 * and the window is small, we just use a lock across the entire DvmDex. 220 * We're only trying to make the page state change atomic; it's up to the 221 * caller to ensure that multiple threads aren't stomping on the same 222 * location (e.g. breakpoints and verifier/optimizer changes happening 223 * simultaneously). 224 * 225 * TODO: if we're back to the original state of the page, use 226 * madvise(MADV_DONTNEED) to release the private/dirty copy. 227 * 228 * Returns "true" on success. 229 */ 230 bool dvmDexChangeDex1(DvmDex* pDvmDex, u1* addr, u1 newVal) 231 { 232 if (*addr == newVal) { 233 LOGV("+++ byte at %p is already 0x%02x\n", addr, newVal); 234 return true; 235 } 236 237 /* 238 * We're not holding this for long, so we don't bother with switching 239 * to VMWAIT. 240 */ 241 dvmLockMutex(&pDvmDex->modLock); 242 243 LOGV("+++ change byte at %p from 0x%02x to 0x%02x\n", addr, *addr, newVal); 244 if (sysChangeMapAccess(addr, 1, true, &pDvmDex->memMap) != 0) { 245 LOGD("NOTE: DEX page access change (->RW) failed\n"); 246 /* expected on files mounted from FAT; keep going (may crash) */ 247 } 248 249 *addr = newVal; 250 251 if (sysChangeMapAccess(addr, 1, false, &pDvmDex->memMap) != 0) { 252 LOGD("NOTE: DEX page access change (->RO) failed\n"); 253 /* expected on files mounted from FAT; keep going */ 254 } 255 256 dvmUnlockMutex(&pDvmDex->modLock); 257 258 return true; 259 } 260 261 /* 262 * Change the 2-byte value at the specified address to a new value. If the 263 * location already has the new value, do nothing. 264 * 265 * Otherwise works like dvmDexChangeDex1. 266 */ 267 bool dvmDexChangeDex2(DvmDex* pDvmDex, u2* addr, u2 newVal) 268 { 269 if (*addr == newVal) { 270 LOGV("+++ value at %p is already 0x%04x\n", addr, newVal); 271 return true; 272 } 273 274 /* 275 * We're not holding this for long, so we don't bother with switching 276 * to VMWAIT. 277 */ 278 dvmLockMutex(&pDvmDex->modLock); 279 280 LOGV("+++ change 2byte at %p from 0x%04x to 0x%04x\n", addr, *addr, newVal); 281 if (sysChangeMapAccess(addr, 2, true, &pDvmDex->memMap) != 0) { 282 LOGD("NOTE: DEX page access change (->RW) failed\n"); 283 /* expected on files mounted from FAT; keep going (may crash) */ 284 } 285 286 *addr = newVal; 287 288 if (sysChangeMapAccess(addr, 2, false, &pDvmDex->memMap) != 0) { 289 LOGD("NOTE: DEX page access change (->RO) failed\n"); 290 /* expected on files mounted from FAT; keep going */ 291 } 292 293 dvmUnlockMutex(&pDvmDex->modLock); 294 295 return true; 296 } 297