1f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
2f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
3f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
4f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
5f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * you may not use this file except in compliance with the License.
6f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * You may obtain a copy of the License at
7f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
8f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
9f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
10f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
12f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * See the License for the specific language governing permissions and
14f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * limitations under the License.
15f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
1696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
17f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
18f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * VM-specific state associated with a DEX file.
19f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
20f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include "Dalvik.h"
215bac60aaafca855f68e1f8b5527d4a4b7897f234Iliyan Malchev#include <sys/mman.h>
2296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
23f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
24f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Create auxillary data structures.
25f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
26f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * We need a 4-byte pointer for every reference to a class, method, field,
27f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * or string constant.  Summed up over all loaded DEX files (including the
28f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * whoppers in the boostrap class path), this adds up to be quite a bit
29f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * of native memory.
30f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
31f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * For more traditional VMs these values could be stuffed into the loaded
32f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * class file constant pool area, but we don't have that luxury since our
33f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * classes are memory-mapped read-only.
34f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
35f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * The DEX optimizer will remove the need for some of these (e.g. we won't
36f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * use the entry for virtual methods that are only called through
37f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * invoke-virtual-quick), creating the possibility of some space reduction
38f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * at dexopt time.
39f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
405bac60aaafca855f68e1f8b5527d4a4b7897f234Iliyan Malchev
41f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic DvmDex* allocateAuxStructures(DexFile* pDexFile)
42f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
43f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    DvmDex* pDvmDex;
44f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    const DexHeader* pHeader;
455bac60aaafca855f68e1f8b5527d4a4b7897f234Iliyan Malchev    u4 stringSize, classSize, methodSize, fieldSize;
46f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
475bac60aaafca855f68e1f8b5527d4a4b7897f234Iliyan Malchev    pHeader = pDexFile->pHeader;
48f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
495bac60aaafca855f68e1f8b5527d4a4b7897f234Iliyan Malchev    stringSize = pHeader->stringIdsSize * sizeof(struct StringObject*);
505bac60aaafca855f68e1f8b5527d4a4b7897f234Iliyan Malchev    classSize  = pHeader->typeIdsSize * sizeof(struct ClassObject*);
515bac60aaafca855f68e1f8b5527d4a4b7897f234Iliyan Malchev    methodSize = pHeader->methodIdsSize * sizeof(struct Method*);
525bac60aaafca855f68e1f8b5527d4a4b7897f234Iliyan Malchev    fieldSize  = pHeader->fieldIdsSize * sizeof(struct Field*);
53f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
545bac60aaafca855f68e1f8b5527d4a4b7897f234Iliyan Malchev    u4 totalSize = sizeof(DvmDex) +
555bac60aaafca855f68e1f8b5527d4a4b7897f234Iliyan Malchev                   stringSize + classSize + methodSize + fieldSize;
56f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
575bac60aaafca855f68e1f8b5527d4a4b7897f234Iliyan Malchev    u1 *blob = (u1 *)dvmAllocRegion(totalSize,
585bac60aaafca855f68e1f8b5527d4a4b7897f234Iliyan Malchev                              PROT_READ | PROT_WRITE, "dalvik-aux-structure");
595bac60aaafca855f68e1f8b5527d4a4b7897f234Iliyan Malchev    if ((void *)blob == MAP_FAILED)
605bac60aaafca855f68e1f8b5527d4a4b7897f234Iliyan Malchev        return NULL;
61f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
625bac60aaafca855f68e1f8b5527d4a4b7897f234Iliyan Malchev    pDvmDex = (DvmDex*)blob;
635bac60aaafca855f68e1f8b5527d4a4b7897f234Iliyan Malchev    blob += sizeof(DvmDex);
64f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
655bac60aaafca855f68e1f8b5527d4a4b7897f234Iliyan Malchev    pDvmDex->pDexFile = pDexFile;
665bac60aaafca855f68e1f8b5527d4a4b7897f234Iliyan Malchev    pDvmDex->pHeader = pHeader;
67f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
685bac60aaafca855f68e1f8b5527d4a4b7897f234Iliyan Malchev    pDvmDex->pResStrings = (struct StringObject**)blob;
695bac60aaafca855f68e1f8b5527d4a4b7897f234Iliyan Malchev    blob += stringSize;
705bac60aaafca855f68e1f8b5527d4a4b7897f234Iliyan Malchev    pDvmDex->pResClasses = (struct ClassObject**)blob;
715bac60aaafca855f68e1f8b5527d4a4b7897f234Iliyan Malchev    blob += classSize;
725bac60aaafca855f68e1f8b5527d4a4b7897f234Iliyan Malchev    pDvmDex->pResMethods = (struct Method**)blob;
735bac60aaafca855f68e1f8b5527d4a4b7897f234Iliyan Malchev    blob += methodSize;
745bac60aaafca855f68e1f8b5527d4a4b7897f234Iliyan Malchev    pDvmDex->pResFields = (struct Field**)blob;
75f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
765bac60aaafca855f68e1f8b5527d4a4b7897f234Iliyan Malchev    ALOGV("+++ DEX %p: allocateAux (%d+%d+%d+%d)*4 = %d bytes",
77bb046193c2da5d43a57b2fa8a17a0f634bf003baElliott Hughes        pDvmDex, stringSize/4, classSize/4, methodSize/4, fieldSize/4,
785bac60aaafca855f68e1f8b5527d4a4b7897f234Iliyan Malchev        stringSize + classSize + methodSize + fieldSize);
79f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
80f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    pDvmDex->pInterfaceCache = dvmAllocAtomicCache(DEX_INTERFACE_CACHE_SIZE);
81f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
82743639415bb123b1517e335bb97f202edbe4e599msg    dvmInitMutex(&pDvmDex->modLock);
83743639415bb123b1517e335bb97f202edbe4e599msg
84f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return pDvmDex;
85f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
86f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
87f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
88f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Given an open optimized DEX file, map it into read-only shared memory and
89f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * parse the contents.
90f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
91f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Returns nonzero on error.
92f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
93f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectint dvmDexFileOpenFromFd(int fd, DvmDex** ppDvmDex)
94f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
95f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    DvmDex* pDvmDex;
96f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    DexFile* pDexFile;
97f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    MemMapping memMap;
98f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    int parseFlags = kDexParseDefault;
99f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    int result = -1;
100f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
101f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (gDvm.verifyDexChecksum)
102f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        parseFlags |= kDexParseVerifyChecksum;
103f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
104f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (lseek(fd, 0, SEEK_SET) < 0) {
105c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block        ALOGE("lseek rewind failed");
106f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        goto bail;
107f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
108f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
109b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden    if (sysMapFileInShmemWritableReadOnly(fd, &memMap) != 0) {
110c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block        ALOGE("Unable to map file");
111f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        goto bail;
112f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
113f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
114fc75f3ed87b55d625b6054e18645da5cbdba31c6Carl Shapiro    pDexFile = dexFileParse((u1*)memMap.addr, memMap.length, parseFlags);
115f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (pDexFile == NULL) {
116c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block        ALOGE("DEX parse failed");
117f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        sysReleaseShmem(&memMap);
118f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        goto bail;
119f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
120f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
121f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    pDvmDex = allocateAuxStructures(pDexFile);
122f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (pDvmDex == NULL) {
123f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        dexFileFree(pDexFile);
124f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        sysReleaseShmem(&memMap);
125f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        goto bail;
126f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
127f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
128f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* tuck this into the DexFile so it gets released later */
129f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    sysCopyMap(&pDvmDex->memMap, &memMap);
13057fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden    pDvmDex->isMappedReadOnly = true;
131f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    *ppDvmDex = pDvmDex;
132f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    result = 0;
133f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
134f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectbail:
135f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return result;
136f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
137f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
138f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
139f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Create a DexFile structure for a "partial" DEX.  This is one that is in
140f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * the process of being optimized.  The optimization header isn't finished
141f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * and we won't have any of the auxillary data tables, so we have to do
142f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * the initialization slightly differently.
143f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
144f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Returns nonzero on error.
145f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
146f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectint dvmDexFileOpenPartial(const void* addr, int len, DvmDex** ppDvmDex)
147f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
148f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    DvmDex* pDvmDex;
149f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    DexFile* pDexFile;
150f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    int parseFlags = kDexParseDefault;
151f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    int result = -1;
152f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
153e1f560a62949e9a673a58a37a8c72dc8b15d9563Andy McFadden    /* -- file is incomplete, new checksum has not yet been calculated
154f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (gDvm.verifyDexChecksum)
155f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        parseFlags |= kDexParseVerifyChecksum;
156e1f560a62949e9a673a58a37a8c72dc8b15d9563Andy McFadden    */
157f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
158fc75f3ed87b55d625b6054e18645da5cbdba31c6Carl Shapiro    pDexFile = dexFileParse((u1*)addr, len, parseFlags);
159f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (pDexFile == NULL) {
160c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block        ALOGE("DEX parse failed");
161f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        goto bail;
162f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
163f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    pDvmDex = allocateAuxStructures(pDexFile);
164f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (pDvmDex == NULL) {
165f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        dexFileFree(pDexFile);
166f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        goto bail;
167f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
168f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
16957fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden    pDvmDex->isMappedReadOnly = false;
170f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    *ppDvmDex = pDvmDex;
171f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    result = 0;
172f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
173f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectbail:
174f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return result;
175f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
176f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
177f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
178f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Free up the DexFile and any associated data structures.
179f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
180f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Note we may be called with a partially-initialized DvmDex.
181f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
182f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectvoid dvmDexFileFree(DvmDex* pDvmDex)
183f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
1845bac60aaafca855f68e1f8b5527d4a4b7897f234Iliyan Malchev    u4 totalSize;
1855bac60aaafca855f68e1f8b5527d4a4b7897f234Iliyan Malchev
186f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (pDvmDex == NULL)
187f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return;
188f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
189743639415bb123b1517e335bb97f202edbe4e599msg    dvmDestroyMutex(&pDvmDex->modLock);
190743639415bb123b1517e335bb97f202edbe4e599msg
1915bac60aaafca855f68e1f8b5527d4a4b7897f234Iliyan Malchev    totalSize  = pDvmDex->pHeader->stringIdsSize * sizeof(struct StringObject*);
1925bac60aaafca855f68e1f8b5527d4a4b7897f234Iliyan Malchev    totalSize += pDvmDex->pHeader->typeIdsSize * sizeof(struct ClassObject*);
1935bac60aaafca855f68e1f8b5527d4a4b7897f234Iliyan Malchev    totalSize += pDvmDex->pHeader->methodIdsSize * sizeof(struct Method*);
1945bac60aaafca855f68e1f8b5527d4a4b7897f234Iliyan Malchev    totalSize += pDvmDex->pHeader->fieldIdsSize * sizeof(struct Field*);
1955bac60aaafca855f68e1f8b5527d4a4b7897f234Iliyan Malchev    totalSize += sizeof(DvmDex);
1965bac60aaafca855f68e1f8b5527d4a4b7897f234Iliyan Malchev
197f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    dexFileFree(pDvmDex->pDexFile);
198f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
19992c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block    ALOGV("+++ DEX %p: freeing aux structs", pDvmDex);
200f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    dvmFreeAtomicCache(pDvmDex->pInterfaceCache);
201f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    sysReleaseShmem(&pDvmDex->memMap);
2025bac60aaafca855f68e1f8b5527d4a4b7897f234Iliyan Malchev    munmap(pDvmDex, totalSize);
203f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
204f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
20596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
20696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden/*
20796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Change the byte at the specified address to a new value.  If the location
20896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * already has the new value, do nothing.
20996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden *
21096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * This requires changing the access permissions to read-write, updating
21196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * the value, and then resetting the permissions.
21296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden *
213fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * We need to ensure mutual exclusion at a page granularity to avoid a race
214fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * where one threads sets read-write, another thread sets read-only, and
215fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * then the first thread does a write.  Since we don't do a lot of updates,
216fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * and the window is small, we just use a lock across the entire DvmDex.
217fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * We're only trying to make the page state change atomic; it's up to the
218fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * caller to ensure that multiple threads aren't stomping on the same
219fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * location (e.g. breakpoints and verifier/optimizer changes happening
220fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * simultaneously).
22196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden *
22296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * TODO: if we're back to the original state of the page, use
22396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * madvise(MADV_DONTNEED) to release the private/dirty copy.
22496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden *
22596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Returns "true" on success.
22696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden */
22796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFaddenbool dvmDexChangeDex1(DvmDex* pDvmDex, u1* addr, u1 newVal)
22896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden{
22996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    if (*addr == newVal) {
23092c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block        ALOGV("+++ byte at %p is already 0x%02x", addr, newVal);
23196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        return true;
23296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    }
23396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
234fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden    /*
235fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden     * We're not holding this for long, so we don't bother with switching
236fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden     * to VMWAIT.
237fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden     */
238fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden    dvmLockMutex(&pDvmDex->modLock);
239fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden
24092c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block    ALOGV("+++ change byte at %p from 0x%02x to 0x%02x", addr, *addr, newVal);
241b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden    if (sysChangeMapAccess(addr, 1, true, &pDvmDex->memMap) != 0) {
242062bf509a77fce9dfcb7e7b2e401cf2a124d83d5Steve Block        ALOGD("NOTE: DEX page access change (->RW) failed");
243b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden        /* expected on files mounted from FAT; keep going (may crash) */
24496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    }
24596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
24696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    *addr = newVal;
24796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
248b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden    if (sysChangeMapAccess(addr, 1, false, &pDvmDex->memMap) != 0) {
249062bf509a77fce9dfcb7e7b2e401cf2a124d83d5Steve Block        ALOGD("NOTE: DEX page access change (->RO) failed");
250b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden        /* expected on files mounted from FAT; keep going */
25196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    }
25296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
253fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden    dvmUnlockMutex(&pDvmDex->modLock);
254fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden
25596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    return true;
25696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden}
25796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
25896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden/*
25996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Change the 2-byte value at the specified address to a new value.  If the
26096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * location already has the new value, do nothing.
26196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden *
26296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Otherwise works like dvmDexChangeDex1.
26396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden */
26496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFaddenbool dvmDexChangeDex2(DvmDex* pDvmDex, u2* addr, u2 newVal)
26596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden{
26696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    if (*addr == newVal) {
26792c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block        ALOGV("+++ value at %p is already 0x%04x", addr, newVal);
26896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        return true;
26996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    }
27096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
271fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden    /*
272fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden     * We're not holding this for long, so we don't bother with switching
273fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden     * to VMWAIT.
274fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden     */
275fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden    dvmLockMutex(&pDvmDex->modLock);
276fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden
27792c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block    ALOGV("+++ change 2byte at %p from 0x%04x to 0x%04x", addr, *addr, newVal);
278b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden    if (sysChangeMapAccess(addr, 2, true, &pDvmDex->memMap) != 0) {
279062bf509a77fce9dfcb7e7b2e401cf2a124d83d5Steve Block        ALOGD("NOTE: DEX page access change (->RW) failed");
280b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden        /* expected on files mounted from FAT; keep going (may crash) */
28196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    }
28296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
28396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    *addr = newVal;
28496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
285b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden    if (sysChangeMapAccess(addr, 2, false, &pDvmDex->memMap) != 0) {
286062bf509a77fce9dfcb7e7b2e401cf2a124d83d5Steve Block        ALOGD("NOTE: DEX page access change (->RO) failed");
287b5ebe47515c9750c7347557075d3714ba7671aa9Andy McFadden        /* expected on files mounted from FAT; keep going */
28896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    }
28996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
290fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden    dvmUnlockMutex(&pDvmDex->modLock);
291fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden
29296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    return true;
29396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden}
294