blob: a0b5da247c53621d3892b41361ef82873f5d677e [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
Logan9d938942011-01-07 10:44:43 +080039CacheWriter::~CacheWriter() {
40#define CHECK_AND_FREE(VAR) if (VAR) { free(VAR); }
41
42 CHECK_AND_FREE(mpHeaderSection);
43 CHECK_AND_FREE(mpStringPoolSection);
44 CHECK_AND_FREE(mpDependencyTableSection);
45 //CHECK_AND_FREE(mpRelocationTableSection);
46 CHECK_AND_FREE(mpExportVarListSection);
47 CHECK_AND_FREE(mpExportFuncListSection);
48 CHECK_AND_FREE(mpPragmaListSection);
49 CHECK_AND_FREE(mpFuncTableSection);
50
51#undef CHECK_AND_FREE
52}
53
Logana27a83f2011-01-07 10:25:48 +080054bool CacheWriter::writeCacheFile(FileHandle *file, Script *S,
55 uint32_t libRS_threadable) {
56 if (!file || file->getFD() < 0) {
57 return false;
58 }
59
60 mFile = file;
61 mpOwner = S;
62
63 bool result = prepareHeader(libRS_threadable)
64 && prepareDependencyTable()
65 && prepareFuncTable()
66 && preparePragmaList()
67 //&& prepareRelocationTable()
68 && prepareStringPool()
69 && prepareExportVarList()
70 && prepareExportFuncList()
71 && 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);
Logane1323992011-01-12 04:47:13 +080096 memcpy(header->libbcc_build_time, libbcc_build_time, 24);
Logana27a83f2011-01-07 10:25:48 +080097
98 // Machine Integer Type
99 uint32_t number = 0x00000001;
100 header->endianness = (*reinterpret_cast<char *>(&number) == 1) ? 'e' : 'E';
101 header->sizeof_off_t = sizeof(off_t);
102 header->sizeof_size_t = sizeof(size_t);
103 header->sizeof_ptr_t = sizeof(void *);
104
105 // Context
106 header->context_cached_addr = mpOwner->getContext();
107
108 // libRS is threadable dirty hack
109 // TODO: This should be removed in the future
110 header->libRS_threadable = libRS_threadable;
111
112 return true;
113}
114
115
116bool CacheWriter::prepareDependencyTable() {
117 size_t tableSize = sizeof(OBCC_DependencyTable) +
118 sizeof(OBCC_Dependency) * mDependencies.size();
119
120 OBCC_DependencyTable *tab = (OBCC_DependencyTable *)malloc(tableSize);
Shih-wei Liaof7cfc022011-01-07 06:39:53 -0800121
Logana27a83f2011-01-07 10:25:48 +0800122 if (!tab) {
123 LOGE("Unable to allocate for dependency table section.\n");
124 return false;
125 }
126
127 mpDependencyTableSection = tab;
128 mpHeaderSection->depend_tab_size = tableSize;
129
130 tab->count = mDependencies.size();
131
132 size_t i = 0;
133 for (map<string, pair<uint32_t, unsigned char const *> >::iterator
134 I = mDependencies.begin(), E = mDependencies.end(); I != E; ++I, ++i) {
135 OBCC_Dependency *dep = &tab->table[i];
136
137 dep->res_name_strp_index = addString(I->first.c_str(), I->first.size());
138 dep->res_type = I->second.first;
139 memcpy(dep->sha1, I->second.second, 20);
140 }
141
142 return true;
143}
144
145
146bool CacheWriter::prepareFuncTable() {
Loganbe79ada2011-01-13 01:33:45 +0800147 size_t funcCount = mpOwner->getFuncCount();
Logana27a83f2011-01-07 10:25:48 +0800148
149 size_t tableSize = sizeof(OBCC_FuncTable) +
150 sizeof(OBCC_FuncInfo) * funcCount;
151
152 OBCC_FuncTable *tab = (OBCC_FuncTable *)malloc(tableSize);
153
154 if (!tab) {
155 LOGE("Unable to allocate for function table section.\n");
156 return false;
157 }
158
159 mpFuncTableSection = tab;
Shih-wei Liaof7cfc022011-01-07 06:39:53 -0800160 mpHeaderSection->func_table_size = tableSize;
Logana27a83f2011-01-07 10:25:48 +0800161
162 tab->count = static_cast<size_t>(funcCount);
163
Shih-wei Liaof7cfc022011-01-07 06:39:53 -0800164 // Get the function informations
Loganbe79ada2011-01-13 01:33:45 +0800165 vector<char const *> funcNameList(funcCount);
166 mpOwner->getFuncNameList(funcCount, &*funcNameList.begin());
Logana27a83f2011-01-07 10:25:48 +0800167
Loganbe79ada2011-01-13 01:33:45 +0800168 for (size_t i = 0; i < funcCount; ++i) {
169 char const *funcName = funcNameList[i];
Logana27a83f2011-01-07 10:25:48 +0800170 size_t funcNameLen = strlen(funcName);
171
172 void *funcAddr = NULL;
Loganbe79ada2011-01-13 01:33:45 +0800173 size_t funcBinarySize = 0;
174 mpOwner->getFuncBinary(funcName, &funcAddr, &funcBinarySize);
Logana27a83f2011-01-07 10:25:48 +0800175
176 OBCC_FuncInfo *funcInfo = &tab->table[i];
177 funcInfo->name_strp_index = addString(funcName, funcNameLen);
178 funcInfo->cached_addr = funcAddr;
179 funcInfo->size = static_cast<size_t>(funcBinarySize);
180 }
181
182 return true;
183}
184
185
186bool CacheWriter::preparePragmaList() {
Loganbe79ada2011-01-13 01:33:45 +0800187 size_t pragmaCount = mpOwner->getPragmaCount();
Logana27a83f2011-01-07 10:25:48 +0800188
189 size_t listSize = sizeof(OBCC_PragmaList) +
190 sizeof(OBCC_Pragma) * pragmaCount;
191
192 OBCC_PragmaList *list = (OBCC_PragmaList *)malloc(listSize);
193
194 if (!list) {
195 LOGE("Unable to allocate for pragma list\n");
196 return false;
197 }
198
199 mpPragmaListSection = list;
200 mpHeaderSection->pragma_list_size = listSize;
201
202 list->count = pragmaCount;
203
Loganbe79ada2011-01-13 01:33:45 +0800204 vector<char const *> keyList(pragmaCount);
205 vector<char const *> valueList(pragmaCount);
206 mpOwner->getPragmaList(pragmaCount, &*keyList.begin(), &*valueList.begin());
Logana27a83f2011-01-07 10:25:48 +0800207
208 for (size_t i = 0; i < pragmaCount; ++i) {
Loganbe79ada2011-01-13 01:33:45 +0800209 char const *key = keyList[i];
210 char const *value = valueList[i];
Logana27a83f2011-01-07 10:25:48 +0800211
Loganbe79ada2011-01-13 01:33:45 +0800212 size_t keyLen = strlen(key);
Logana27a83f2011-01-07 10:25:48 +0800213 size_t valueLen = strlen(value);
214
215 OBCC_Pragma *pragma = &list->list[i];
216 pragma->key_strp_index = addString(key, keyLen);
217 pragma->value_strp_index = addString(value, valueLen);
218 }
219
220 return true;
221}
222
223
224bool CacheWriter::prepareRelocationTable() {
225 // TODO(logan): Implement relocation table cache write.
226 return false;
227}
228
229
230bool CacheWriter::prepareStringPool() {
231 // Calculate string pool size
232 size_t size = sizeof(OBCC_StringPool) +
233 sizeof(OBCC_String) * mStringPool.size();
234
235 off_t strOffset = size;
236
237 for (size_t i = 0; i < mStringPool.size(); ++i) {
238 size += mStringPool[i].second + 1;
239 }
240
241 // Create string pool
242 OBCC_StringPool *pool = (OBCC_StringPool *)malloc(size);
243
244 if (!pool) {
245 LOGE("Unable to allocate string pool.\n");
246 return false;
247 }
248
249 mpStringPoolSection = pool;
250 mpHeaderSection->str_pool_size = size;
251
Logana2e15af2011-01-07 11:46:08 +0800252 pool->count = mStringPool.size();
253
Logana27a83f2011-01-07 10:25:48 +0800254 char *strPtr = reinterpret_cast<char *>(pool) + strOffset;
255
256 for (size_t i = 0; i < mStringPool.size(); ++i) {
257 OBCC_String *str = &pool->list[i];
258
259 str->length = mStringPool[i].second;
260 str->offset = strOffset;
261 memcpy(strPtr, mStringPool[i].first, str->length);
262
263 strPtr += str->length;
264 *strPtr++ = '\0';
265
Logana2e15af2011-01-07 11:46:08 +0800266 strOffset += str->length + 1;
Logana27a83f2011-01-07 10:25:48 +0800267 }
268
269 return true;
270}
271
272
273bool CacheWriter::prepareExportVarList() {
Loganbe79ada2011-01-13 01:33:45 +0800274 size_t varCount = mpOwner->getExportVarCount();
Logana27a83f2011-01-07 10:25:48 +0800275 size_t listSize = sizeof(OBCC_ExportVarList) + sizeof(void *) * varCount;
276
277 OBCC_ExportVarList *list = (OBCC_ExportVarList *)malloc(listSize);
278
279 if (!list) {
280 LOGE("Unable to allocate for export variable list\n");
281 return false;
282 }
283
284 mpExportVarListSection = list;
285 mpHeaderSection->export_var_list_size = listSize;
286
287 list->count = static_cast<size_t>(varCount);
288
Loganbe79ada2011-01-13 01:33:45 +0800289 mpOwner->getExportVarList(varCount, list->cached_addr_list);
Logana27a83f2011-01-07 10:25:48 +0800290 return true;
291}
292
293
294bool CacheWriter::prepareExportFuncList() {
Loganbe79ada2011-01-13 01:33:45 +0800295 size_t funcCount = mpOwner->getExportFuncCount();
Logana27a83f2011-01-07 10:25:48 +0800296 size_t listSize = sizeof(OBCC_ExportFuncList) + sizeof(void *) * funcCount;
297
298 OBCC_ExportFuncList *list = (OBCC_ExportFuncList *)malloc(listSize);
299
300 if (!list) {
301 LOGE("Unable to allocate for export function list\n");
302 return false;
303 }
304
305 mpExportFuncListSection = list;
306 mpHeaderSection->export_func_list_size = listSize;
307
308 list->count = static_cast<size_t>(funcCount);
309
Loganbe79ada2011-01-13 01:33:45 +0800310 mpOwner->getExportFuncList(funcCount, list->cached_addr_list);
Logana27a83f2011-01-07 10:25:48 +0800311 return true;
312}
313
314
315bool CacheWriter::calcSectionOffset() {
316 size_t offset = sizeof(OBCC_Header);
317
318#define OFFSET_INCREASE(NAME) \
319 do { \
320 /* Align to a word */ \
321 size_t rem = offset % sizeof(int); \
322 if (rem > 0) { \
323 offset += sizeof(int) - rem; \
324 } \
325 \
326 /* Save the offset and increase it */ \
327 mpHeaderSection->NAME##_offset = offset; \
328 offset += mpHeaderSection->NAME##_size; \
329 } while (0)
330
331 OFFSET_INCREASE(str_pool);
332 OFFSET_INCREASE(depend_tab);
333 //OFFSET_INCREASE(reloc_tab);
334 OFFSET_INCREASE(export_var_list);
335 OFFSET_INCREASE(export_func_list);
336 OFFSET_INCREASE(pragma_list);
337 OFFSET_INCREASE(func_table);
338
339#undef OFFSET_INCREASE
340
341 // Context
342 long pagesize = sysconf(_SC_PAGESIZE);
343 size_t context_offset_rem = offset % pagesize;
344 if (context_offset_rem) {
345 offset += pagesize - context_offset_rem;
346 }
347
348 mpHeaderSection->context_offset = offset;
349 return true;
350}
351
352
353bool CacheWriter::calcContextChecksum() {
354 uint32_t sum = 0;
355 uint32_t *ptr = reinterpret_cast<uint32_t *>(mpOwner->getContext());
356
357 for (size_t i = 0; i < BCC_CONTEXT_SIZE / sizeof(uint32_t); ++i) {
358 sum ^= *ptr++;
359 }
360
361 mpHeaderSection->context_parity_checksum = sum;
362 return true;
363}
364
365
366bool CacheWriter::writeAll() {
367#define WRITE_SECTION(NAME, OFFSET, SIZE, SECTION) \
368 do { \
369 if (mFile->seek(OFFSET, SEEK_SET) == -1) { \
370 LOGE("Unable to seek to " #NAME " section for writing.\n"); \
371 return false; \
372 } \
373 \
374 if (mFile->write(reinterpret_cast<char *>(SECTION), (SIZE)) != \
375 static_cast<ssize_t>(SIZE)) { \
376 LOGE("Unable to write " #NAME " section to cache file.\n"); \
377 return false; \
378 } \
379 } while (0)
380
381#define WRITE_SECTION_SIMPLE(NAME, SECTION) \
382 WRITE_SECTION(NAME, \
383 mpHeaderSection->NAME##_offset, \
384 mpHeaderSection->NAME##_size, \
385 SECTION)
386
387 WRITE_SECTION(header, 0, sizeof(OBCC_Header), mpHeaderSection);
388
389 WRITE_SECTION_SIMPLE(str_pool, mpStringPoolSection);
390 WRITE_SECTION_SIMPLE(depend_tab, mpDependencyTableSection);
391 //WRITE_SECTION_SIMPLE(reloc_tab, mpRelocationTableSection);
392 WRITE_SECTION_SIMPLE(export_var_list, mpExportVarListSection);
393 WRITE_SECTION_SIMPLE(export_func_list, mpExportFuncListSection);
394 WRITE_SECTION_SIMPLE(pragma_list, mpPragmaListSection);
395 WRITE_SECTION_SIMPLE(func_table, mpFuncTableSection);
396
397 WRITE_SECTION(context, mpHeaderSection->context_offset, BCC_CONTEXT_SIZE,
398 mpOwner->getContext());
399
400#undef WRITE_SECTION_SIMPLE
401#undef WRITE_SECTION
402
403 return true;
404}
405
406
Logana27a83f2011-01-07 10:25:48 +0800407} // namespace bcc