blob: e51d46893dbb0f6c777dda7f4a5275de3c65a7de [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
17#define LOG_TAG "bcc"
18#include <cutils/log.h>
19
20#include "CacheWriter.h"
21
22#include "ContextManager.h"
23#include "FileHandle.h"
24#include "Script.h"
25
26#include <map>
27#include <string>
28#include <vector>
29#include <utility>
30
31#include <stdint.h>
32#include <stdlib.h>
33#include <string.h>
34
35using namespace std;
36
37namespace bcc {
38
39bool CacheWriter::writeCacheFile(FileHandle *file, Script *S,
40 uint32_t libRS_threadable) {
41 if (!file || file->getFD() < 0) {
42 return false;
43 }
44
45 mFile = file;
46 mpOwner = S;
47
48 bool result = prepareHeader(libRS_threadable)
49 && prepareDependencyTable()
50 && prepareFuncTable()
51 && preparePragmaList()
52 //&& prepareRelocationTable()
53 && prepareStringPool()
54 && prepareExportVarList()
55 && prepareExportFuncList()
56 && calcSectionOffset()
57 && calcContextChecksum()
58 && writeAll()
59 ;
60
61 return result;
62}
63
64
65bool CacheWriter::prepareHeader(uint32_t libRS_threadable) {
66 OBCC_Header *header = (OBCC_Header *)malloc(sizeof(OBCC_Header));
67
68 if (!header) {
69 LOGE("Unable to allocate for header.\n");
70 return false;
71 }
72
73 mpHeaderSection = header;
74
75 // Initialize
76 memset(header, '\0', sizeof(OBCC_Header));
77
78 // Magic word and version
79 memcpy(header->magic, OBCC_MAGIC, 4);
80 memcpy(header->version, OBCC_VERSION, 4);
81
82 // Machine Integer Type
83 uint32_t number = 0x00000001;
84 header->endianness = (*reinterpret_cast<char *>(&number) == 1) ? 'e' : 'E';
85 header->sizeof_off_t = sizeof(off_t);
86 header->sizeof_size_t = sizeof(size_t);
87 header->sizeof_ptr_t = sizeof(void *);
88
89 // Context
90 header->context_cached_addr = mpOwner->getContext();
91
92 // libRS is threadable dirty hack
93 // TODO: This should be removed in the future
94 header->libRS_threadable = libRS_threadable;
95
96 return true;
97}
98
99
100bool CacheWriter::prepareDependencyTable() {
101 size_t tableSize = sizeof(OBCC_DependencyTable) +
102 sizeof(OBCC_Dependency) * mDependencies.size();
103
104 OBCC_DependencyTable *tab = (OBCC_DependencyTable *)malloc(tableSize);
105
106 if (!tab) {
107 LOGE("Unable to allocate for dependency table section.\n");
108 return false;
109 }
110
111 mpDependencyTableSection = tab;
112 mpHeaderSection->depend_tab_size = tableSize;
113
114 tab->count = mDependencies.size();
115
116 size_t i = 0;
117 for (map<string, pair<uint32_t, unsigned char const *> >::iterator
118 I = mDependencies.begin(), E = mDependencies.end(); I != E; ++I, ++i) {
119 OBCC_Dependency *dep = &tab->table[i];
120
121 dep->res_name_strp_index = addString(I->first.c_str(), I->first.size());
122 dep->res_type = I->second.first;
123 memcpy(dep->sha1, I->second.second, 20);
124 }
125
126 return true;
127}
128
129
130bool CacheWriter::prepareFuncTable() {
131 ssize_t funcCount = 0;
132
133 mpOwner->getFunctions(&funcCount, 0, NULL);
134
135 size_t tableSize = sizeof(OBCC_FuncTable) +
136 sizeof(OBCC_FuncInfo) * funcCount;
137
138 OBCC_FuncTable *tab = (OBCC_FuncTable *)malloc(tableSize);
139
140 if (!tab) {
141 LOGE("Unable to allocate for function table section.\n");
142 return false;
143 }
144
145 mpFuncTableSection = tab;
146 mpHeaderSection->func_table_size = tableSize;
147
148 tab->count = static_cast<size_t>(funcCount);
149
150 // Get the function informations
151 vector<char *> funcNameList(funcCount);
152 mpOwner->getFunctions(0, funcCount, &*funcNameList.begin());
153
154 for (int i = 0; i < funcCount; ++i) {
155 char *funcName = funcNameList[i];
156 size_t funcNameLen = strlen(funcName);
157
158 void *funcAddr = NULL;
159 ssize_t funcBinarySize = 0;
160 mpOwner->getFunctionBinary(funcName, &funcAddr, &funcBinarySize);
161
162 OBCC_FuncInfo *funcInfo = &tab->table[i];
163 funcInfo->name_strp_index = addString(funcName, funcNameLen);
164 funcInfo->cached_addr = funcAddr;
165 funcInfo->size = static_cast<size_t>(funcBinarySize);
166 }
167
168 return true;
169}
170
171
172bool CacheWriter::preparePragmaList() {
173 ssize_t stringCount;
174
175 mpOwner->getPragmas(&stringCount, 0, NULL);
176
177 size_t pragmaCount = static_cast<size_t>(stringCount) / 2;
178
179 size_t listSize = sizeof(OBCC_PragmaList) +
180 sizeof(OBCC_Pragma) * pragmaCount;
181
182 OBCC_PragmaList *list = (OBCC_PragmaList *)malloc(listSize);
183
184 if (!list) {
185 LOGE("Unable to allocate for pragma list\n");
186 return false;
187 }
188
189 mpPragmaListSection = list;
190 mpHeaderSection->pragma_list_size = listSize;
191
192 list->count = pragmaCount;
193
194 vector<char *> strings(stringCount);
195 mpOwner->getPragmas(&stringCount, stringCount, &*strings.begin());
196
197 for (size_t i = 0; i < pragmaCount; ++i) {
198 char *key = strings[2 * i];
199 size_t keyLen = strlen(key);
200
201 char *value = strings[2 * i + 1];
202 size_t valueLen = strlen(value);
203
204 OBCC_Pragma *pragma = &list->list[i];
205 pragma->key_strp_index = addString(key, keyLen);
206 pragma->value_strp_index = addString(value, valueLen);
207 }
208
209 return true;
210}
211
212
213bool CacheWriter::prepareRelocationTable() {
214 // TODO(logan): Implement relocation table cache write.
215 return false;
216}
217
218
219bool CacheWriter::prepareStringPool() {
220 // Calculate string pool size
221 size_t size = sizeof(OBCC_StringPool) +
222 sizeof(OBCC_String) * mStringPool.size();
223
224 off_t strOffset = size;
225
226 for (size_t i = 0; i < mStringPool.size(); ++i) {
227 size += mStringPool[i].second + 1;
228 }
229
230 // Create string pool
231 OBCC_StringPool *pool = (OBCC_StringPool *)malloc(size);
232
233 if (!pool) {
234 LOGE("Unable to allocate string pool.\n");
235 return false;
236 }
237
238 mpStringPoolSection = pool;
239 mpHeaderSection->str_pool_size = size;
240
241 char *strPtr = reinterpret_cast<char *>(pool) + strOffset;
242
243 for (size_t i = 0; i < mStringPool.size(); ++i) {
244 OBCC_String *str = &pool->list[i];
245
246 str->length = mStringPool[i].second;
247 str->offset = strOffset;
248 memcpy(strPtr, mStringPool[i].first, str->length);
249
250 strPtr += str->length;
251 *strPtr++ = '\0';
252
253 strOffset += str->length;
254 }
255
256 return true;
257}
258
259
260bool CacheWriter::prepareExportVarList() {
261 ssize_t varCount;
262
263 mpOwner->getExportVars(&varCount, 0, NULL);
264
265 size_t listSize = sizeof(OBCC_ExportVarList) + sizeof(void *) * varCount;
266
267 OBCC_ExportVarList *list = (OBCC_ExportVarList *)malloc(listSize);
268
269 if (!list) {
270 LOGE("Unable to allocate for export variable list\n");
271 return false;
272 }
273
274 mpExportVarListSection = list;
275 mpHeaderSection->export_var_list_size = listSize;
276
277 list->count = static_cast<size_t>(varCount);
278
279 mpOwner->getExportVars(&varCount, varCount, list->cached_addr_list);
280 return true;
281}
282
283
284bool CacheWriter::prepareExportFuncList() {
285 ssize_t funcCount;
286
287 mpOwner->getExportFuncs(&funcCount, 0, NULL);
288
289 size_t listSize = sizeof(OBCC_ExportFuncList) + sizeof(void *) * funcCount;
290
291 OBCC_ExportFuncList *list = (OBCC_ExportFuncList *)malloc(listSize);
292
293 if (!list) {
294 LOGE("Unable to allocate for export function list\n");
295 return false;
296 }
297
298 mpExportFuncListSection = list;
299 mpHeaderSection->export_func_list_size = listSize;
300
301 list->count = static_cast<size_t>(funcCount);
302
303 mpOwner->getExportFuncs(&funcCount, funcCount, list->cached_addr_list);
304 return true;
305}
306
307
308bool CacheWriter::calcSectionOffset() {
309 size_t offset = sizeof(OBCC_Header);
310
311#define OFFSET_INCREASE(NAME) \
312 do { \
313 /* Align to a word */ \
314 size_t rem = offset % sizeof(int); \
315 if (rem > 0) { \
316 offset += sizeof(int) - rem; \
317 } \
318 \
319 /* Save the offset and increase it */ \
320 mpHeaderSection->NAME##_offset = offset; \
321 offset += mpHeaderSection->NAME##_size; \
322 } while (0)
323
324 OFFSET_INCREASE(str_pool);
325 OFFSET_INCREASE(depend_tab);
326 //OFFSET_INCREASE(reloc_tab);
327 OFFSET_INCREASE(export_var_list);
328 OFFSET_INCREASE(export_func_list);
329 OFFSET_INCREASE(pragma_list);
330 OFFSET_INCREASE(func_table);
331
332#undef OFFSET_INCREASE
333
334 // Context
335 long pagesize = sysconf(_SC_PAGESIZE);
336 size_t context_offset_rem = offset % pagesize;
337 if (context_offset_rem) {
338 offset += pagesize - context_offset_rem;
339 }
340
341 mpHeaderSection->context_offset = offset;
342 return true;
343}
344
345
346bool CacheWriter::calcContextChecksum() {
347 uint32_t sum = 0;
348 uint32_t *ptr = reinterpret_cast<uint32_t *>(mpOwner->getContext());
349
350 for (size_t i = 0; i < BCC_CONTEXT_SIZE / sizeof(uint32_t); ++i) {
351 sum ^= *ptr++;
352 }
353
354 mpHeaderSection->context_parity_checksum = sum;
355 return true;
356}
357
358
359bool CacheWriter::writeAll() {
360#define WRITE_SECTION(NAME, OFFSET, SIZE, SECTION) \
361 do { \
362 if (mFile->seek(OFFSET, SEEK_SET) == -1) { \
363 LOGE("Unable to seek to " #NAME " section for writing.\n"); \
364 return false; \
365 } \
366 \
367 if (mFile->write(reinterpret_cast<char *>(SECTION), (SIZE)) != \
368 static_cast<ssize_t>(SIZE)) { \
369 LOGE("Unable to write " #NAME " section to cache file.\n"); \
370 return false; \
371 } \
372 } while (0)
373
374#define WRITE_SECTION_SIMPLE(NAME, SECTION) \
375 WRITE_SECTION(NAME, \
376 mpHeaderSection->NAME##_offset, \
377 mpHeaderSection->NAME##_size, \
378 SECTION)
379
380 WRITE_SECTION(header, 0, sizeof(OBCC_Header), mpHeaderSection);
381
382 WRITE_SECTION_SIMPLE(str_pool, mpStringPoolSection);
383 WRITE_SECTION_SIMPLE(depend_tab, mpDependencyTableSection);
384 //WRITE_SECTION_SIMPLE(reloc_tab, mpRelocationTableSection);
385 WRITE_SECTION_SIMPLE(export_var_list, mpExportVarListSection);
386 WRITE_SECTION_SIMPLE(export_func_list, mpExportFuncListSection);
387 WRITE_SECTION_SIMPLE(pragma_list, mpPragmaListSection);
388 WRITE_SECTION_SIMPLE(func_table, mpFuncTableSection);
389
390 WRITE_SECTION(context, mpHeaderSection->context_offset, BCC_CONTEXT_SIZE,
391 mpOwner->getContext());
392
393#undef WRITE_SECTION_SIMPLE
394#undef WRITE_SECTION
395
396 return true;
397}
398
399
400#if 0
401void Compiler::genCacheFile() {
402
403 // Write Header
404 sysWriteFully(mCacheFd, reinterpret_cast<char const *>(hdr),
405 sizeof(oBCCHeader), "Write oBCC header");
406
407 // Write Relocation Entry Table
408 {
409 size_t allocSize = hdr->relocCount * sizeof(oBCCRelocEntry);
410
411 oBCCRelocEntry const*records = &mCodeEmitter->getCachingRelocations()[0];
412
413 sysWriteFully(mCacheFd, reinterpret_cast<char const *>(records),
414 allocSize, "Write Relocation Entries");
415 }
416
417 // Write Export Variables Table
418 {
419 uint32_t *record, *ptr;
420
421 record = (uint32_t *)calloc(hdr->exportVarsCount, sizeof(uint32_t));
422 ptr = record;
423
424 if (!record) {
425 goto bail;
426 }
427
428 for (ScriptCompiled::ExportVarList::const_iterator
429 I = mpResult->mExportVars.begin(),
430 E = mpResult->mExportVars.end(); I != E; I++) {
431 *ptr++ = reinterpret_cast<uint32_t>(*I);
432 }
433
434 sysWriteFully(mCacheFd, reinterpret_cast<char const *>(record),
435 hdr->exportVarsCount * sizeof(uint32_t),
436 "Write ExportVars");
437
438 free(record);
439 }
440
441 // Write Export Functions Table
442 {
443 uint32_t *record, *ptr;
444
445 record = (uint32_t *)calloc(hdr->exportFuncsCount, sizeof(uint32_t));
446 ptr = record;
447
448 if (!record) {
449 goto bail;
450 }
451
452 for (ScriptCompiled::ExportFuncList::const_iterator
453 I = mpResult->mExportFuncs.begin(),
454 E = mpResult->mExportFuncs.end(); I != E; I++) {
455 *ptr++ = reinterpret_cast<uint32_t>(*I);
456 }
457
458 sysWriteFully(mCacheFd, reinterpret_cast<char const *>(record),
459 hdr->exportFuncsCount * sizeof(uint32_t),
460 "Write ExportFuncs");
461
462 free(record);
463 }
464
465
466 // Write Export Pragmas Table
467 {
468 uint32_t pragmaEntryOffset =
469 hdr->exportPragmasCount * sizeof(oBCCPragmaEntry);
470
471 for (ScriptCompiled::PragmaList::const_iterator
472 I = mpResult->mPragmas.begin(),
473 E = mpResult->mPragmas.end(); I != E; ++I) {
474 oBCCPragmaEntry entry;
475
476 entry.pragmaNameOffset = pragmaEntryOffset;
477 entry.pragmaNameSize = I->first.size();
478 pragmaEntryOffset += entry.pragmaNameSize + 1;
479
480 entry.pragmaValueOffset = pragmaEntryOffset;
481 entry.pragmaValueSize = I->second.size();
482 pragmaEntryOffset += entry.pragmaValueSize + 1;
483
484 sysWriteFully(mCacheFd, (char *)&entry, sizeof(oBCCPragmaEntry),
485 "Write export pragma entry");
486 }
487
488 for (ScriptCompiled::PragmaList::const_iterator
489 I = mpResult->mPragmas.begin(),
490 E = mpResult->mPragmas.end(); I != E; ++I) {
491 sysWriteFully(mCacheFd, I->first.c_str(), I->first.size() + 1,
492 "Write export pragma name string");
493 sysWriteFully(mCacheFd, I->second.c_str(), I->second.size() + 1,
494 "Write export pragma value string");
495 }
496 }
497
498 if (codeOffsetNeedPadding) {
499 // requires additional padding
500 lseek(mCacheFd, hdr->codeOffset, SEEK_SET);
501 }
502
503 // Write Generated Code and Global Variable
504 sysWriteFully(mCacheFd, mCodeDataAddr, MaxCodeSize + MaxGlobalVarSize,
505 "Write code and global variable");
506
507 goto close_return;
508
509bail:
510 if (ftruncate(mCacheFd, 0) != 0) {
511 LOGW("Warning: unable to truncate cache file: %s\n", strerror(errno));
512 }
513
514close_return:
515 free(hdr);
516 close(mCacheFd);
517 mCacheFd = -1;
518}
519#endif
520
521} // namespace bcc