The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 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 | */ |
Andy McFadden | b51ea11 | 2009-05-08 16:50:17 -0700 | [diff] [blame] | 16 | |
The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 17 | /* |
| 18 | * Access the contents of a .dex file. |
| 19 | */ |
| 20 | |
| 21 | #include "DexFile.h" |
Dan Bornstein | e377ef6 | 2010-08-31 16:50:00 -0700 | [diff] [blame] | 22 | #include "DexOptData.h" |
The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 23 | #include "DexProto.h" |
Andy McFadden | b51ea11 | 2009-05-08 16:50:17 -0700 | [diff] [blame] | 24 | #include "DexCatch.h" |
The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 25 | #include "Leb128.h" |
| 26 | #include "sha1.h" |
| 27 | #include "ZipArchive.h" |
| 28 | |
| 29 | #include <zlib.h> |
| 30 | |
| 31 | #include <stdlib.h> |
| 32 | #include <stddef.h> |
| 33 | #include <string.h> |
| 34 | #include <fcntl.h> |
| 35 | #include <errno.h> |
| 36 | |
Andy McFadden | 7d18e38 | 2009-12-03 16:08:36 -0800 | [diff] [blame] | 37 | |
The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 38 | /* |
| 39 | * Verifying checksums is good, but it slows things down and causes us to |
| 40 | * touch every page. In the "optimized" world, it doesn't work at all, |
| 41 | * because we rewrite the contents. |
| 42 | */ |
| 43 | static const bool kVerifyChecksum = false; |
| 44 | static const bool kVerifySignature = false; |
| 45 | |
Dan Bornstein | a9c49df | 2011-03-11 12:58:05 -0800 | [diff] [blame] | 46 | /* (documented in header) */ |
| 47 | char dexGetPrimitiveTypeDescriptorChar(PrimitiveType type) { |
| 48 | const char* string = dexGetPrimitiveTypeDescriptor(type); |
| 49 | |
| 50 | return (string == NULL) ? '\0' : string[0]; |
| 51 | } |
| 52 | |
| 53 | /* (documented in header) */ |
| 54 | const char* dexGetPrimitiveTypeDescriptor(PrimitiveType type) { |
| 55 | switch (type) { |
| 56 | case PRIM_VOID: return "V"; |
| 57 | case PRIM_BOOLEAN: return "Z"; |
| 58 | case PRIM_BYTE: return "B"; |
| 59 | case PRIM_SHORT: return "S"; |
| 60 | case PRIM_CHAR: return "C"; |
| 61 | case PRIM_INT: return "I"; |
| 62 | case PRIM_LONG: return "J"; |
| 63 | case PRIM_FLOAT: return "F"; |
| 64 | case PRIM_DOUBLE: return "D"; |
| 65 | default: return NULL; |
| 66 | } |
| 67 | |
| 68 | return NULL; |
| 69 | } |
| 70 | |
Dan Bornstein | 1553988 | 2011-03-11 17:57:13 -0800 | [diff] [blame] | 71 | /* (documented in header) */ |
Dan Bornstein | a9c49df | 2011-03-11 12:58:05 -0800 | [diff] [blame] | 72 | const char* dexGetBoxedTypeDescriptor(PrimitiveType type) { |
| 73 | switch (type) { |
| 74 | case PRIM_VOID: return NULL; |
| 75 | case PRIM_BOOLEAN: return "Ljava/lang/Boolean;"; |
| 76 | case PRIM_BYTE: return "Ljava/lang/Byte;"; |
| 77 | case PRIM_SHORT: return "Ljava/lang/Short;"; |
| 78 | case PRIM_CHAR: return "Ljava/lang/Character;"; |
| 79 | case PRIM_INT: return "Ljava/lang/Integer;"; |
| 80 | case PRIM_LONG: return "Ljava/lang/Long;"; |
| 81 | case PRIM_FLOAT: return "Ljava/lang/Float;"; |
| 82 | case PRIM_DOUBLE: return "Ljava/lang/Double;"; |
| 83 | default: return NULL; |
| 84 | } |
| 85 | } |
| 86 | |
| 87 | /* (documented in header) */ |
| 88 | PrimitiveType dexGetPrimitiveTypeFromDescriptorChar(char descriptorChar) { |
| 89 | switch (descriptorChar) { |
| 90 | case 'V': return PRIM_VOID; |
| 91 | case 'Z': return PRIM_BOOLEAN; |
| 92 | case 'B': return PRIM_BYTE; |
| 93 | case 'S': return PRIM_SHORT; |
| 94 | case 'C': return PRIM_CHAR; |
| 95 | case 'I': return PRIM_INT; |
| 96 | case 'J': return PRIM_LONG; |
| 97 | case 'F': return PRIM_FLOAT; |
| 98 | case 'D': return PRIM_DOUBLE; |
| 99 | default: return PRIM_NOT; |
| 100 | } |
| 101 | } |
| 102 | |
The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 103 | /* Return the UTF-8 encoded string with the specified string_id index, |
| 104 | * also filling in the UTF-16 size (number of 16-bit code points).*/ |
| 105 | const char* dexStringAndSizeById(const DexFile* pDexFile, u4 idx, |
| 106 | u4* utf16Size) { |
| 107 | const DexStringId* pStringId = dexGetStringId(pDexFile, idx); |
| 108 | const u1* ptr = pDexFile->baseAddr + pStringId->stringDataOff; |
| 109 | |
| 110 | *utf16Size = readUnsignedLeb128(&ptr); |
| 111 | return (const char*) ptr; |
| 112 | } |
| 113 | |
| 114 | /* |
| 115 | * Format an SHA-1 digest for printing. tmpBuf must be able to hold at |
| 116 | * least kSHA1DigestOutputLen bytes. |
| 117 | */ |
| 118 | const char* dvmSHA1DigestToStr(const unsigned char digest[], char* tmpBuf); |
| 119 | |
| 120 | /* |
| 121 | * Compute a SHA-1 digest on a range of bytes. |
| 122 | */ |
| 123 | static void dexComputeSHA1Digest(const unsigned char* data, size_t length, |
| 124 | unsigned char digest[]) |
| 125 | { |
| 126 | SHA1_CTX context; |
| 127 | SHA1Init(&context); |
| 128 | SHA1Update(&context, data, length); |
| 129 | SHA1Final(digest, &context); |
| 130 | } |
| 131 | |
| 132 | /* |
| 133 | * Format the SHA-1 digest into the buffer, which must be able to hold at |
| 134 | * least kSHA1DigestOutputLen bytes. Returns a pointer to the buffer, |
| 135 | */ |
| 136 | static const char* dexSHA1DigestToStr(const unsigned char digest[],char* tmpBuf) |
| 137 | { |
| 138 | static const char hexDigit[] = "0123456789abcdef"; |
| 139 | char* cp; |
| 140 | int i; |
| 141 | |
| 142 | cp = tmpBuf; |
| 143 | for (i = 0; i < kSHA1DigestLen; i++) { |
| 144 | *cp++ = hexDigit[digest[i] >> 4]; |
| 145 | *cp++ = hexDigit[digest[i] & 0x0f]; |
| 146 | } |
| 147 | *cp++ = '\0'; |
| 148 | |
| 149 | assert(cp == tmpBuf + kSHA1DigestOutputLen); |
| 150 | |
| 151 | return tmpBuf; |
| 152 | } |
| 153 | |
| 154 | /* |
| 155 | * Compute a hash code on a UTF-8 string, for use with internal hash tables. |
| 156 | * |
| 157 | * This may or may not be compatible with UTF-8 hash functions used inside |
| 158 | * the Dalvik VM. |
| 159 | * |
| 160 | * The basic "multiply by 31 and add" approach does better on class names |
| 161 | * than most other things tried (e.g. adler32). |
| 162 | */ |
| 163 | static u4 classDescriptorHash(const char* str) |
| 164 | { |
| 165 | u4 hash = 1; |
| 166 | |
| 167 | while (*str != '\0') |
| 168 | hash = hash * 31 + *str++; |
| 169 | |
| 170 | return hash; |
| 171 | } |
| 172 | |
| 173 | /* |
| 174 | * Add an entry to the class lookup table. We hash the string and probe |
| 175 | * until we find an open slot. |
| 176 | */ |
| 177 | static void classLookupAdd(DexFile* pDexFile, DexClassLookup* pLookup, |
| 178 | int stringOff, int classDefOff, int* pNumProbes) |
| 179 | { |
| 180 | const char* classDescriptor = |
| 181 | (const char*) (pDexFile->baseAddr + stringOff); |
| 182 | const DexClassDef* pClassDef = |
| 183 | (const DexClassDef*) (pDexFile->baseAddr + classDefOff); |
| 184 | u4 hash = classDescriptorHash(classDescriptor); |
| 185 | int mask = pLookup->numEntries-1; |
| 186 | int idx = hash & mask; |
| 187 | |
| 188 | /* |
| 189 | * Find the first empty slot. We oversized the table, so this is |
| 190 | * guaranteed to finish. |
| 191 | */ |
| 192 | int probes = 0; |
| 193 | while (pLookup->table[idx].classDescriptorOffset != 0) { |
| 194 | idx = (idx + 1) & mask; |
| 195 | probes++; |
| 196 | } |
| 197 | //if (probes > 1) |
Dan Bornstein | 614dca3 | 2011-05-25 16:58:39 -0700 | [diff] [blame] | 198 | // LOGW("classLookupAdd: probes=%d", probes); |
The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 199 | |
| 200 | pLookup->table[idx].classDescriptorHash = hash; |
| 201 | pLookup->table[idx].classDescriptorOffset = stringOff; |
| 202 | pLookup->table[idx].classDefOffset = classDefOff; |
| 203 | *pNumProbes = probes; |
| 204 | } |
| 205 | |
| 206 | /* |
The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 207 | * Create the class lookup hash table. |
| 208 | * |
| 209 | * Returns newly-allocated storage. |
| 210 | */ |
| 211 | DexClassLookup* dexCreateClassLookup(DexFile* pDexFile) |
| 212 | { |
| 213 | DexClassLookup* pLookup; |
| 214 | int allocSize; |
| 215 | int i, numEntries; |
| 216 | int numProbes, totalProbes, maxProbes; |
| 217 | |
| 218 | numProbes = totalProbes = maxProbes = 0; |
| 219 | |
| 220 | assert(pDexFile != NULL); |
| 221 | |
| 222 | /* |
| 223 | * Using a factor of 3 results in far less probing than a factor of 2, |
| 224 | * but almost doubles the flash storage requirements for the bootstrap |
| 225 | * DEX files. The overall impact on class loading performance seems |
| 226 | * to be minor. We could probably get some performance improvement by |
| 227 | * using a secondary hash. |
| 228 | */ |
| 229 | numEntries = dexRoundUpPower2(pDexFile->pHeader->classDefsSize * 2); |
| 230 | allocSize = offsetof(DexClassLookup, table) |
| 231 | + numEntries * sizeof(pLookup->table[0]); |
| 232 | |
| 233 | pLookup = (DexClassLookup*) calloc(1, allocSize); |
| 234 | if (pLookup == NULL) |
| 235 | return NULL; |
| 236 | pLookup->size = allocSize; |
| 237 | pLookup->numEntries = numEntries; |
| 238 | |
| 239 | for (i = 0; i < (int)pDexFile->pHeader->classDefsSize; i++) { |
| 240 | const DexClassDef* pClassDef; |
| 241 | const char* pString; |
| 242 | |
| 243 | pClassDef = dexGetClassDef(pDexFile, i); |
| 244 | pString = dexStringByTypeIdx(pDexFile, pClassDef->classIdx); |
| 245 | |
Carl Shapiro | de75089 | 2010-06-08 16:37:12 -0700 | [diff] [blame] | 246 | classLookupAdd(pDexFile, pLookup, |
The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 247 | (u1*)pString - pDexFile->baseAddr, |
| 248 | (u1*)pClassDef - pDexFile->baseAddr, &numProbes); |
| 249 | |
| 250 | if (numProbes > maxProbes) |
| 251 | maxProbes = numProbes; |
| 252 | totalProbes += numProbes; |
| 253 | } |
| 254 | |
| 255 | LOGV("Class lookup: classes=%d slots=%d (%d%% occ) alloc=%d" |
Dan Bornstein | 6f3c21f | 2011-05-26 12:01:03 -0700 | [diff] [blame^] | 256 | " total=%d max=%d", |
The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 257 | pDexFile->pHeader->classDefsSize, numEntries, |
| 258 | (100 * pDexFile->pHeader->classDefsSize) / numEntries, |
| 259 | allocSize, totalProbes, maxProbes); |
| 260 | |
| 261 | return pLookup; |
| 262 | } |
| 263 | |
| 264 | |
| 265 | /* |
| 266 | * Set up the basic raw data pointers of a DexFile. This function isn't |
| 267 | * meant for general use. |
| 268 | */ |
| 269 | void dexFileSetupBasicPointers(DexFile* pDexFile, const u1* data) { |
| 270 | DexHeader *pHeader = (DexHeader*) data; |
| 271 | |
| 272 | pDexFile->baseAddr = data; |
| 273 | pDexFile->pHeader = pHeader; |
| 274 | pDexFile->pStringIds = (const DexStringId*) (data + pHeader->stringIdsOff); |
| 275 | pDexFile->pTypeIds = (const DexTypeId*) (data + pHeader->typeIdsOff); |
| 276 | pDexFile->pFieldIds = (const DexFieldId*) (data + pHeader->fieldIdsOff); |
| 277 | pDexFile->pMethodIds = (const DexMethodId*) (data + pHeader->methodIdsOff); |
| 278 | pDexFile->pProtoIds = (const DexProtoId*) (data + pHeader->protoIdsOff); |
| 279 | pDexFile->pClassDefs = (const DexClassDef*) (data + pHeader->classDefsOff); |
| 280 | pDexFile->pLinkData = (const DexLink*) (data + pHeader->linkOff); |
| 281 | } |
| 282 | |
The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 283 | /* |
| 284 | * Parse an optimized or unoptimized .dex file sitting in memory. This is |
| 285 | * called after the byte-ordering and structure alignment has been fixed up. |
| 286 | * |
| 287 | * On success, return a newly-allocated DexFile. |
| 288 | */ |
| 289 | DexFile* dexFileParse(const u1* data, size_t length, int flags) |
| 290 | { |
| 291 | DexFile* pDexFile = NULL; |
| 292 | const DexHeader* pHeader; |
| 293 | const u1* magic; |
| 294 | int result = -1; |
| 295 | |
| 296 | if (length < sizeof(DexHeader)) { |
Dan Bornstein | 614dca3 | 2011-05-25 16:58:39 -0700 | [diff] [blame] | 297 | LOGE("too short to be a valid .dex"); |
The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 298 | goto bail; /* bad file format */ |
| 299 | } |
| 300 | |
| 301 | pDexFile = (DexFile*) malloc(sizeof(DexFile)); |
| 302 | if (pDexFile == NULL) |
| 303 | goto bail; /* alloc failure */ |
| 304 | memset(pDexFile, 0, sizeof(DexFile)); |
| 305 | |
| 306 | /* |
| 307 | * Peel off the optimized header. |
| 308 | */ |
| 309 | if (memcmp(data, DEX_OPT_MAGIC, 4) == 0) { |
| 310 | magic = data; |
| 311 | if (memcmp(magic+4, DEX_OPT_MAGIC_VERS, 4) != 0) { |
Dan Bornstein | 614dca3 | 2011-05-25 16:58:39 -0700 | [diff] [blame] | 312 | LOGE("bad opt version (0x%02x %02x %02x %02x)", |
The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 313 | magic[4], magic[5], magic[6], magic[7]); |
| 314 | goto bail; |
| 315 | } |
| 316 | |
| 317 | pDexFile->pOptHeader = (const DexOptHeader*) data; |
Dan Bornstein | 614dca3 | 2011-05-25 16:58:39 -0700 | [diff] [blame] | 318 | LOGV("Good opt header, DEX offset is %d, flags=0x%02x", |
The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 319 | pDexFile->pOptHeader->dexOffset, pDexFile->pOptHeader->flags); |
| 320 | |
Dan Bornstein | e377ef6 | 2010-08-31 16:50:00 -0700 | [diff] [blame] | 321 | /* parse the optimized dex file tables */ |
| 322 | if (!dexParseOptData(data, length, pDexFile)) |
The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 323 | goto bail; |
| 324 | |
| 325 | /* ignore the opt header and appended data from here on out */ |
| 326 | data += pDexFile->pOptHeader->dexOffset; |
| 327 | length -= pDexFile->pOptHeader->dexOffset; |
| 328 | if (pDexFile->pOptHeader->dexLength > length) { |
Dan Bornstein | 614dca3 | 2011-05-25 16:58:39 -0700 | [diff] [blame] | 329 | LOGE("File truncated? stored len=%d, rem len=%d", |
The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 330 | pDexFile->pOptHeader->dexLength, (int) length); |
| 331 | goto bail; |
| 332 | } |
| 333 | length = pDexFile->pOptHeader->dexLength; |
| 334 | } |
| 335 | |
| 336 | dexFileSetupBasicPointers(pDexFile, data); |
| 337 | pHeader = pDexFile->pHeader; |
| 338 | |
Dan Bornstein | 9fdbd91 | 2011-05-25 13:15:47 -0700 | [diff] [blame] | 339 | if (!dexHasValidMagic(pHeader)) { |
The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 340 | goto bail; |
| 341 | } |
| 342 | |
| 343 | /* |
Andy McFadden | 7d18e38 | 2009-12-03 16:08:36 -0800 | [diff] [blame] | 344 | * Verify the checksum(s). This is reasonably quick, but does require |
| 345 | * touching every byte in the DEX file. The base checksum changes after |
The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 346 | * byte-swapping and DEX optimization. |
| 347 | */ |
| 348 | if (flags & kDexParseVerifyChecksum) { |
| 349 | u4 adler = dexComputeChecksum(pHeader); |
| 350 | if (adler != pHeader->checksum) { |
Dan Bornstein | 614dca3 | 2011-05-25 16:58:39 -0700 | [diff] [blame] | 351 | LOGE("ERROR: bad checksum (%08x vs %08x)", |
The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 352 | adler, pHeader->checksum); |
| 353 | if (!(flags & kDexParseContinueOnError)) |
| 354 | goto bail; |
| 355 | } else { |
Dan Bornstein | 614dca3 | 2011-05-25 16:58:39 -0700 | [diff] [blame] | 356 | LOGV("+++ adler32 checksum (%08x) verified", adler); |
The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 357 | } |
Andy McFadden | 7d18e38 | 2009-12-03 16:08:36 -0800 | [diff] [blame] | 358 | |
| 359 | const DexOptHeader* pOptHeader = pDexFile->pOptHeader; |
| 360 | if (pOptHeader != NULL) { |
| 361 | adler = dexComputeOptChecksum(pOptHeader); |
| 362 | if (adler != pOptHeader->checksum) { |
Dan Bornstein | 614dca3 | 2011-05-25 16:58:39 -0700 | [diff] [blame] | 363 | LOGE("ERROR: bad opt checksum (%08x vs %08x)", |
Andy McFadden | 7d18e38 | 2009-12-03 16:08:36 -0800 | [diff] [blame] | 364 | adler, pOptHeader->checksum); |
| 365 | if (!(flags & kDexParseContinueOnError)) |
| 366 | goto bail; |
| 367 | } else { |
Dan Bornstein | 614dca3 | 2011-05-25 16:58:39 -0700 | [diff] [blame] | 368 | LOGV("+++ adler32 opt checksum (%08x) verified", adler); |
Andy McFadden | 7d18e38 | 2009-12-03 16:08:36 -0800 | [diff] [blame] | 369 | } |
| 370 | } |
The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 371 | } |
| 372 | |
| 373 | /* |
| 374 | * Verify the SHA-1 digest. (Normally we don't want to do this -- |
Andy McFadden | 7d18e38 | 2009-12-03 16:08:36 -0800 | [diff] [blame] | 375 | * the digest is used to uniquely identify the original DEX file, and |
| 376 | * can't be computed for verification after the DEX is byte-swapped |
| 377 | * and optimized.) |
The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 378 | */ |
| 379 | if (kVerifySignature) { |
| 380 | unsigned char sha1Digest[kSHA1DigestLen]; |
| 381 | const int nonSum = sizeof(pHeader->magic) + sizeof(pHeader->checksum) + |
| 382 | kSHA1DigestLen; |
| 383 | |
| 384 | dexComputeSHA1Digest(data + nonSum, length - nonSum, sha1Digest); |
| 385 | if (memcmp(sha1Digest, pHeader->signature, kSHA1DigestLen) != 0) { |
| 386 | char tmpBuf1[kSHA1DigestOutputLen]; |
| 387 | char tmpBuf2[kSHA1DigestOutputLen]; |
Dan Bornstein | 614dca3 | 2011-05-25 16:58:39 -0700 | [diff] [blame] | 388 | LOGE("ERROR: bad SHA1 digest (%s vs %s)", |
The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 389 | dexSHA1DigestToStr(sha1Digest, tmpBuf1), |
| 390 | dexSHA1DigestToStr(pHeader->signature, tmpBuf2)); |
| 391 | if (!(flags & kDexParseContinueOnError)) |
| 392 | goto bail; |
| 393 | } else { |
Dan Bornstein | 614dca3 | 2011-05-25 16:58:39 -0700 | [diff] [blame] | 394 | LOGV("+++ sha1 digest verified"); |
The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 395 | } |
| 396 | } |
| 397 | |
| 398 | if (pHeader->fileSize != length) { |
Dan Bornstein | 614dca3 | 2011-05-25 16:58:39 -0700 | [diff] [blame] | 399 | LOGE("ERROR: stored file size (%d) != expected (%d)", |
The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 400 | (int) pHeader->fileSize, (int) length); |
| 401 | if (!(flags & kDexParseContinueOnError)) |
| 402 | goto bail; |
| 403 | } |
| 404 | |
| 405 | if (pHeader->classDefsSize == 0) { |
Dan Bornstein | 614dca3 | 2011-05-25 16:58:39 -0700 | [diff] [blame] | 406 | LOGE("ERROR: DEX file has no classes in it, failing"); |
The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 407 | goto bail; |
| 408 | } |
| 409 | |
| 410 | /* |
| 411 | * Success! |
| 412 | */ |
| 413 | result = 0; |
| 414 | |
| 415 | bail: |
| 416 | if (result != 0 && pDexFile != NULL) { |
| 417 | dexFileFree(pDexFile); |
| 418 | pDexFile = NULL; |
| 419 | } |
| 420 | return pDexFile; |
| 421 | } |
| 422 | |
| 423 | /* |
| 424 | * Free up the DexFile and any associated data structures. |
| 425 | * |
| 426 | * Note we may be called with a partially-initialized DexFile. |
| 427 | */ |
| 428 | void dexFileFree(DexFile* pDexFile) |
| 429 | { |
| 430 | if (pDexFile == NULL) |
| 431 | return; |
| 432 | |
| 433 | free(pDexFile); |
| 434 | } |
| 435 | |
| 436 | /* |
| 437 | * Look up a class definition entry by descriptor. |
| 438 | * |
| 439 | * "descriptor" should look like "Landroid/debug/Stuff;". |
| 440 | */ |
| 441 | const DexClassDef* dexFindClass(const DexFile* pDexFile, |
| 442 | const char* descriptor) |
| 443 | { |
| 444 | const DexClassLookup* pLookup = pDexFile->pClassLookup; |
| 445 | u4 hash; |
| 446 | int idx, mask; |
| 447 | |
| 448 | hash = classDescriptorHash(descriptor); |
| 449 | mask = pLookup->numEntries - 1; |
| 450 | idx = hash & mask; |
| 451 | |
| 452 | /* |
| 453 | * Search until we find a matching entry or an empty slot. |
| 454 | */ |
| 455 | while (true) { |
| 456 | int offset; |
| 457 | |
| 458 | offset = pLookup->table[idx].classDescriptorOffset; |
| 459 | if (offset == 0) |
| 460 | return NULL; |
| 461 | |
| 462 | if (pLookup->table[idx].classDescriptorHash == hash) { |
| 463 | const char* str; |
Carl Shapiro | de75089 | 2010-06-08 16:37:12 -0700 | [diff] [blame] | 464 | |
The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 465 | str = (const char*) (pDexFile->baseAddr + offset); |
| 466 | if (strcmp(str, descriptor) == 0) { |
| 467 | return (const DexClassDef*) |
| 468 | (pDexFile->baseAddr + pLookup->table[idx].classDefOffset); |
| 469 | } |
| 470 | } |
| 471 | |
| 472 | idx = (idx + 1) & mask; |
| 473 | } |
| 474 | } |
| 475 | |
| 476 | |
| 477 | /* |
| 478 | * Compute the DEX file checksum for a memory-mapped DEX file. |
| 479 | */ |
| 480 | u4 dexComputeChecksum(const DexHeader* pHeader) |
| 481 | { |
| 482 | const u1* start = (const u1*) pHeader; |
| 483 | |
| 484 | uLong adler = adler32(0L, Z_NULL, 0); |
| 485 | const int nonSum = sizeof(pHeader->magic) + sizeof(pHeader->checksum); |
| 486 | |
| 487 | return (u4) adler32(adler, start + nonSum, pHeader->fileSize - nonSum); |
| 488 | } |
| 489 | |
Andy McFadden | 7d18e38 | 2009-12-03 16:08:36 -0800 | [diff] [blame] | 490 | /* |
Andy McFadden | b51ea11 | 2009-05-08 16:50:17 -0700 | [diff] [blame] | 491 | * Compute the size, in bytes, of a DexCode. |
| 492 | */ |
| 493 | size_t dexGetDexCodeSize(const DexCode* pCode) |
| 494 | { |
| 495 | /* |
| 496 | * The catch handler data is the last entry. It has a variable number |
| 497 | * of variable-size pieces, so we need to create an iterator. |
| 498 | */ |
| 499 | u4 handlersSize; |
| 500 | u4 offset; |
| 501 | u4 ui; |
| 502 | |
| 503 | if (pCode->triesSize != 0) { |
| 504 | handlersSize = dexGetHandlersSize(pCode); |
| 505 | offset = dexGetFirstHandlerOffset(pCode); |
| 506 | } else { |
| 507 | handlersSize = 0; |
| 508 | offset = 0; |
| 509 | } |
| 510 | |
| 511 | for (ui = 0; ui < handlersSize; ui++) { |
| 512 | DexCatchIterator iterator; |
| 513 | dexCatchIteratorInit(&iterator, pCode, offset); |
| 514 | offset = dexCatchIteratorGetEndOffset(&iterator, pCode); |
| 515 | } |
| 516 | |
| 517 | const u1* handlerData = dexGetCatchHandlerData(pCode); |
| 518 | |
Dan Bornstein | 614dca3 | 2011-05-25 16:58:39 -0700 | [diff] [blame] | 519 | //LOGD("+++ pCode=%p handlerData=%p last offset=%d", |
Andy McFadden | b51ea11 | 2009-05-08 16:50:17 -0700 | [diff] [blame] | 520 | // pCode, handlerData, offset); |
| 521 | |
| 522 | /* return the size of the catch handler + everything before it */ |
| 523 | return (handlerData - (u1*) pCode) + offset; |
| 524 | } |
| 525 | |
Andy McFadden | b51ea11 | 2009-05-08 16:50:17 -0700 | [diff] [blame] | 526 | /* |
Dan Bornstein | 9ea32b0 | 2011-03-09 17:40:41 -0800 | [diff] [blame] | 527 | * Round up to the next highest power of 2. |
The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 528 | * |
Dan Bornstein | 9ea32b0 | 2011-03-09 17:40:41 -0800 | [diff] [blame] | 529 | * Found on http://graphics.stanford.edu/~seander/bithacks.html. |
The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 530 | */ |
Dan Bornstein | 9ea32b0 | 2011-03-09 17:40:41 -0800 | [diff] [blame] | 531 | u4 dexRoundUpPower2(u4 val) |
The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 532 | { |
Dan Bornstein | 9ea32b0 | 2011-03-09 17:40:41 -0800 | [diff] [blame] | 533 | val--; |
| 534 | val |= val >> 1; |
| 535 | val |= val >> 2; |
| 536 | val |= val >> 4; |
| 537 | val |= val >> 8; |
| 538 | val |= val >> 16; |
| 539 | val++; |
The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 540 | |
Dan Bornstein | 9ea32b0 | 2011-03-09 17:40:41 -0800 | [diff] [blame] | 541 | return val; |
The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 542 | } |