blob: 86775a7174be8586a817b580eb9d9148985b49d9 [file] [log] [blame]
Logana27a83f2011-01-07 10:25:48 +08001/*
2 * Copyright 2010, 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
Logana27a83f2011-01-07 10:25:48 +080017#include "CacheWriter.h"
18
19#include "ContextManager.h"
Logan4dcd6792011-02-28 05:12:00 +080020#include "DebugHelper.h"
Logana27a83f2011-01-07 10:25:48 +080021#include "FileHandle.h"
22#include "Script.h"
23
24#include <map>
25#include <string>
26#include <vector>
27#include <utility>
28
29#include <stdint.h>
30#include <stdlib.h>
31#include <string.h>
32
33using namespace std;
34
35namespace bcc {
36
Logan9d938942011-01-07 10:44:43 +080037CacheWriter::~CacheWriter() {
38#define CHECK_AND_FREE(VAR) if (VAR) { free(VAR); }
39
40 CHECK_AND_FREE(mpHeaderSection);
41 CHECK_AND_FREE(mpStringPoolSection);
42 CHECK_AND_FREE(mpDependencyTableSection);
43 //CHECK_AND_FREE(mpRelocationTableSection);
44 CHECK_AND_FREE(mpExportVarListSection);
45 CHECK_AND_FREE(mpExportFuncListSection);
46 CHECK_AND_FREE(mpPragmaListSection);
47 CHECK_AND_FREE(mpFuncTableSection);
Stephen Hines071288a2011-01-27 14:38:26 -080048 CHECK_AND_FREE(mpObjectSlotSection);
Logan9d938942011-01-07 10:44:43 +080049
50#undef CHECK_AND_FREE
51}
52
Logana27a83f2011-01-07 10:25:48 +080053bool CacheWriter::writeCacheFile(FileHandle *file, Script *S,
54 uint32_t libRS_threadable) {
55 if (!file || file->getFD() < 0) {
56 return false;
57 }
58
59 mFile = file;
60 mpOwner = S;
61
62 bool result = prepareHeader(libRS_threadable)
63 && prepareDependencyTable()
64 && prepareFuncTable()
65 && preparePragmaList()
66 //&& prepareRelocationTable()
67 && prepareStringPool()
68 && prepareExportVarList()
69 && prepareExportFuncList()
Stephen Hines071288a2011-01-27 14:38:26 -080070 && prepareObjectSlotList()
Logana27a83f2011-01-07 10:25:48 +080071 && calcSectionOffset()
72 && calcContextChecksum()
73 && writeAll()
74 ;
75
76 return result;
77}
78
79
80bool CacheWriter::prepareHeader(uint32_t libRS_threadable) {
81 OBCC_Header *header = (OBCC_Header *)malloc(sizeof(OBCC_Header));
82
83 if (!header) {
84 LOGE("Unable to allocate for header.\n");
85 return false;
86 }
87
88 mpHeaderSection = header;
89
90 // Initialize
91 memset(header, '\0', sizeof(OBCC_Header));
92
Shih-wei Liaof7cfc022011-01-07 06:39:53 -080093 // Magic word and version
Logana27a83f2011-01-07 10:25:48 +080094 memcpy(header->magic, OBCC_MAGIC, 4);
95 memcpy(header->version, OBCC_VERSION, 4);
96
97 // Machine Integer Type
98 uint32_t number = 0x00000001;
99 header->endianness = (*reinterpret_cast<char *>(&number) == 1) ? 'e' : 'E';
100 header->sizeof_off_t = sizeof(off_t);
101 header->sizeof_size_t = sizeof(size_t);
102 header->sizeof_ptr_t = sizeof(void *);
103
104 // Context
105 header->context_cached_addr = mpOwner->getContext();
106
107 // libRS is threadable dirty hack
108 // TODO: This should be removed in the future
109 header->libRS_threadable = libRS_threadable;
110
111 return true;
112}
113
114
115bool CacheWriter::prepareDependencyTable() {
116 size_t tableSize = sizeof(OBCC_DependencyTable) +
117 sizeof(OBCC_Dependency) * mDependencies.size();
118
119 OBCC_DependencyTable *tab = (OBCC_DependencyTable *)malloc(tableSize);
Shih-wei Liaof7cfc022011-01-07 06:39:53 -0800120
Logana27a83f2011-01-07 10:25:48 +0800121 if (!tab) {
122 LOGE("Unable to allocate for dependency table section.\n");
123 return false;
124 }
125
126 mpDependencyTableSection = tab;
127 mpHeaderSection->depend_tab_size = tableSize;
128
129 tab->count = mDependencies.size();
130
131 size_t i = 0;
132 for (map<string, pair<uint32_t, unsigned char const *> >::iterator
133 I = mDependencies.begin(), E = mDependencies.end(); I != E; ++I, ++i) {
134 OBCC_Dependency *dep = &tab->table[i];
135
136 dep->res_name_strp_index = addString(I->first.c_str(), I->first.size());
137 dep->res_type = I->second.first;
138 memcpy(dep->sha1, I->second.second, 20);
139 }
140
141 return true;
142}
143
144
145bool CacheWriter::prepareFuncTable() {
Loganbe79ada2011-01-13 01:33:45 +0800146 size_t funcCount = mpOwner->getFuncCount();
Logana27a83f2011-01-07 10:25:48 +0800147
148 size_t tableSize = sizeof(OBCC_FuncTable) +
149 sizeof(OBCC_FuncInfo) * funcCount;
150
151 OBCC_FuncTable *tab = (OBCC_FuncTable *)malloc(tableSize);
152
153 if (!tab) {
154 LOGE("Unable to allocate for function table section.\n");
155 return false;
156 }
157
158 mpFuncTableSection = tab;
Shih-wei Liaof7cfc022011-01-07 06:39:53 -0800159 mpHeaderSection->func_table_size = tableSize;
Logana27a83f2011-01-07 10:25:48 +0800160
161 tab->count = static_cast<size_t>(funcCount);
162
Shih-wei Liaof7cfc022011-01-07 06:39:53 -0800163 // Get the function informations
Loganf340bf72011-01-14 17:51:40 +0800164 vector<FuncInfo> funcInfoList(funcCount);
165 mpOwner->getFuncInfoList(funcCount, &*funcInfoList.begin());
Logana27a83f2011-01-07 10:25:48 +0800166
Loganbe79ada2011-01-13 01:33:45 +0800167 for (size_t i = 0; i < funcCount; ++i) {
Loganf340bf72011-01-14 17:51:40 +0800168 FuncInfo *info = &funcInfoList[i];
169 OBCC_FuncInfo *outputInfo = &tab->table[i];
Logana27a83f2011-01-07 10:25:48 +0800170
Loganf340bf72011-01-14 17:51:40 +0800171 outputInfo->name_strp_index = addString(info->name, strlen(info->name));
172 outputInfo->cached_addr = info->addr;
173 outputInfo->size = info->size;
Logana27a83f2011-01-07 10:25:48 +0800174 }
175
176 return true;
177}
178
179
180bool CacheWriter::preparePragmaList() {
Loganbe79ada2011-01-13 01:33:45 +0800181 size_t pragmaCount = mpOwner->getPragmaCount();
Logana27a83f2011-01-07 10:25:48 +0800182
183 size_t listSize = sizeof(OBCC_PragmaList) +
184 sizeof(OBCC_Pragma) * pragmaCount;
185
186 OBCC_PragmaList *list = (OBCC_PragmaList *)malloc(listSize);
187
188 if (!list) {
189 LOGE("Unable to allocate for pragma list\n");
190 return false;
191 }
192
193 mpPragmaListSection = list;
194 mpHeaderSection->pragma_list_size = listSize;
195
196 list->count = pragmaCount;
197
Loganbe79ada2011-01-13 01:33:45 +0800198 vector<char const *> keyList(pragmaCount);
199 vector<char const *> valueList(pragmaCount);
200 mpOwner->getPragmaList(pragmaCount, &*keyList.begin(), &*valueList.begin());
Logana27a83f2011-01-07 10:25:48 +0800201
202 for (size_t i = 0; i < pragmaCount; ++i) {
Loganbe79ada2011-01-13 01:33:45 +0800203 char const *key = keyList[i];
204 char const *value = valueList[i];
Logana27a83f2011-01-07 10:25:48 +0800205
Loganbe79ada2011-01-13 01:33:45 +0800206 size_t keyLen = strlen(key);
Logana27a83f2011-01-07 10:25:48 +0800207 size_t valueLen = strlen(value);
208
209 OBCC_Pragma *pragma = &list->list[i];
210 pragma->key_strp_index = addString(key, keyLen);
211 pragma->value_strp_index = addString(value, valueLen);
212 }
213
214 return true;
215}
216
217
218bool CacheWriter::prepareRelocationTable() {
219 // TODO(logan): Implement relocation table cache write.
220 return false;
221}
222
223
224bool CacheWriter::prepareStringPool() {
225 // Calculate string pool size
226 size_t size = sizeof(OBCC_StringPool) +
227 sizeof(OBCC_String) * mStringPool.size();
228
229 off_t strOffset = size;
230
231 for (size_t i = 0; i < mStringPool.size(); ++i) {
232 size += mStringPool[i].second + 1;
233 }
234
235 // Create string pool
236 OBCC_StringPool *pool = (OBCC_StringPool *)malloc(size);
237
238 if (!pool) {
239 LOGE("Unable to allocate string pool.\n");
240 return false;
241 }
242
243 mpStringPoolSection = pool;
244 mpHeaderSection->str_pool_size = size;
245
Logana2e15af2011-01-07 11:46:08 +0800246 pool->count = mStringPool.size();
247
Logana27a83f2011-01-07 10:25:48 +0800248 char *strPtr = reinterpret_cast<char *>(pool) + strOffset;
249
250 for (size_t i = 0; i < mStringPool.size(); ++i) {
251 OBCC_String *str = &pool->list[i];
252
253 str->length = mStringPool[i].second;
254 str->offset = strOffset;
255 memcpy(strPtr, mStringPool[i].first, str->length);
256
257 strPtr += str->length;
258 *strPtr++ = '\0';
259
Logana2e15af2011-01-07 11:46:08 +0800260 strOffset += str->length + 1;
Logana27a83f2011-01-07 10:25:48 +0800261 }
262
263 return true;
264}
265
266
267bool CacheWriter::prepareExportVarList() {
Loganbe79ada2011-01-13 01:33:45 +0800268 size_t varCount = mpOwner->getExportVarCount();
Logana27a83f2011-01-07 10:25:48 +0800269 size_t listSize = sizeof(OBCC_ExportVarList) + sizeof(void *) * varCount;
270
271 OBCC_ExportVarList *list = (OBCC_ExportVarList *)malloc(listSize);
272
273 if (!list) {
274 LOGE("Unable to allocate for export variable list\n");
275 return false;
276 }
277
278 mpExportVarListSection = list;
279 mpHeaderSection->export_var_list_size = listSize;
280
281 list->count = static_cast<size_t>(varCount);
282
Loganbe79ada2011-01-13 01:33:45 +0800283 mpOwner->getExportVarList(varCount, list->cached_addr_list);
Logana27a83f2011-01-07 10:25:48 +0800284 return true;
285}
286
287
288bool CacheWriter::prepareExportFuncList() {
Loganbe79ada2011-01-13 01:33:45 +0800289 size_t funcCount = mpOwner->getExportFuncCount();
Logana27a83f2011-01-07 10:25:48 +0800290 size_t listSize = sizeof(OBCC_ExportFuncList) + sizeof(void *) * funcCount;
291
292 OBCC_ExportFuncList *list = (OBCC_ExportFuncList *)malloc(listSize);
293
294 if (!list) {
295 LOGE("Unable to allocate for export function list\n");
296 return false;
297 }
298
299 mpExportFuncListSection = list;
300 mpHeaderSection->export_func_list_size = listSize;
301
302 list->count = static_cast<size_t>(funcCount);
303
Loganbe79ada2011-01-13 01:33:45 +0800304 mpOwner->getExportFuncList(funcCount, list->cached_addr_list);
Logana27a83f2011-01-07 10:25:48 +0800305 return true;
306}
307
308
Stephen Hines071288a2011-01-27 14:38:26 -0800309bool CacheWriter::prepareObjectSlotList() {
310 size_t objectSlotCount = mpOwner->getObjectSlotCount();
311
312 size_t listSize = sizeof(OBCC_ObjectSlotList) +
313 sizeof(uint32_t) * objectSlotCount;
314
315 OBCC_ObjectSlotList *list = (OBCC_ObjectSlotList *)malloc(listSize);
316
317 if (!list) {
318 LOGE("Unable to allocate for object slot list\n");
319 return false;
320 }
321
322 mpObjectSlotSection = list;
323 mpHeaderSection->object_slot_list_size = listSize;
324
325 list->count = objectSlotCount;
326
327 mpOwner->getObjectSlotList(objectSlotCount, list->object_slot_list);
328 return true;
329}
330
331
Logana27a83f2011-01-07 10:25:48 +0800332bool CacheWriter::calcSectionOffset() {
333 size_t offset = sizeof(OBCC_Header);
334
335#define OFFSET_INCREASE(NAME) \
336 do { \
337 /* Align to a word */ \
338 size_t rem = offset % sizeof(int); \
339 if (rem > 0) { \
340 offset += sizeof(int) - rem; \
341 } \
342 \
343 /* Save the offset and increase it */ \
344 mpHeaderSection->NAME##_offset = offset; \
345 offset += mpHeaderSection->NAME##_size; \
346 } while (0)
347
348 OFFSET_INCREASE(str_pool);
349 OFFSET_INCREASE(depend_tab);
350 //OFFSET_INCREASE(reloc_tab);
351 OFFSET_INCREASE(export_var_list);
352 OFFSET_INCREASE(export_func_list);
353 OFFSET_INCREASE(pragma_list);
354 OFFSET_INCREASE(func_table);
Stephen Hines071288a2011-01-27 14:38:26 -0800355 OFFSET_INCREASE(object_slot_list);
Logana27a83f2011-01-07 10:25:48 +0800356
357#undef OFFSET_INCREASE
358
359 // Context
360 long pagesize = sysconf(_SC_PAGESIZE);
361 size_t context_offset_rem = offset % pagesize;
362 if (context_offset_rem) {
363 offset += pagesize - context_offset_rem;
364 }
365
366 mpHeaderSection->context_offset = offset;
367 return true;
368}
369
370
371bool CacheWriter::calcContextChecksum() {
372 uint32_t sum = 0;
373 uint32_t *ptr = reinterpret_cast<uint32_t *>(mpOwner->getContext());
374
Logan1dc63142011-02-25 17:14:51 +0800375 for (size_t i = 0; i < ContextManager::ContextSize / sizeof(uint32_t); ++i) {
Logana27a83f2011-01-07 10:25:48 +0800376 sum ^= *ptr++;
377 }
378
379 mpHeaderSection->context_parity_checksum = sum;
380 return true;
381}
382
383
384bool CacheWriter::writeAll() {
385#define WRITE_SECTION(NAME, OFFSET, SIZE, SECTION) \
386 do { \
387 if (mFile->seek(OFFSET, SEEK_SET) == -1) { \
388 LOGE("Unable to seek to " #NAME " section for writing.\n"); \
389 return false; \
390 } \
391 \
392 if (mFile->write(reinterpret_cast<char *>(SECTION), (SIZE)) != \
393 static_cast<ssize_t>(SIZE)) { \
394 LOGE("Unable to write " #NAME " section to cache file.\n"); \
395 return false; \
396 } \
397 } while (0)
398
399#define WRITE_SECTION_SIMPLE(NAME, SECTION) \
400 WRITE_SECTION(NAME, \
401 mpHeaderSection->NAME##_offset, \
402 mpHeaderSection->NAME##_size, \
403 SECTION)
404
405 WRITE_SECTION(header, 0, sizeof(OBCC_Header), mpHeaderSection);
406
407 WRITE_SECTION_SIMPLE(str_pool, mpStringPoolSection);
408 WRITE_SECTION_SIMPLE(depend_tab, mpDependencyTableSection);
409 //WRITE_SECTION_SIMPLE(reloc_tab, mpRelocationTableSection);
410 WRITE_SECTION_SIMPLE(export_var_list, mpExportVarListSection);
411 WRITE_SECTION_SIMPLE(export_func_list, mpExportFuncListSection);
412 WRITE_SECTION_SIMPLE(pragma_list, mpPragmaListSection);
413 WRITE_SECTION_SIMPLE(func_table, mpFuncTableSection);
Stephen Hines071288a2011-01-27 14:38:26 -0800414 WRITE_SECTION_SIMPLE(object_slot_list, mpObjectSlotSection);
Logana27a83f2011-01-07 10:25:48 +0800415
Logan1dc63142011-02-25 17:14:51 +0800416 WRITE_SECTION(context, mpHeaderSection->context_offset,
417 ContextManager::ContextSize,
Logana27a83f2011-01-07 10:25:48 +0800418 mpOwner->getContext());
419
420#undef WRITE_SECTION_SIMPLE
421#undef WRITE_SECTION
422
423 return true;
424}
425
426
Logana27a83f2011-01-07 10:25:48 +0800427} // namespace bcc