blob: 87c554c641b3243405681b0b4ca4c37686e208d7 [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
93 // Magic word and version
94 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);
120
121 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() {
146 ssize_t funcCount = 0;
147
148 mpOwner->getFunctions(&funcCount, 0, NULL);
149
150 size_t tableSize = sizeof(OBCC_FuncTable) +
151 sizeof(OBCC_FuncInfo) * funcCount;
152
153 OBCC_FuncTable *tab = (OBCC_FuncTable *)malloc(tableSize);
154
155 if (!tab) {
156 LOGE("Unable to allocate for function table section.\n");
157 return false;
158 }
159
160 mpFuncTableSection = tab;
161 mpHeaderSection->func_table_size = tableSize;
162
163 tab->count = static_cast<size_t>(funcCount);
164
165 // Get the function informations
166 vector<char *> funcNameList(funcCount);
167 mpOwner->getFunctions(0, funcCount, &*funcNameList.begin());
168
169 for (int i = 0; i < funcCount; ++i) {
170 char *funcName = funcNameList[i];
171 size_t funcNameLen = strlen(funcName);
172
173 void *funcAddr = NULL;
174 ssize_t funcBinarySize = 0;
175 mpOwner->getFunctionBinary(funcName, &funcAddr, &funcBinarySize);
176
177 OBCC_FuncInfo *funcInfo = &tab->table[i];
178 funcInfo->name_strp_index = addString(funcName, funcNameLen);
179 funcInfo->cached_addr = funcAddr;
180 funcInfo->size = static_cast<size_t>(funcBinarySize);
181 }
182
183 return true;
184}
185
186
187bool CacheWriter::preparePragmaList() {
188 ssize_t stringCount;
189
190 mpOwner->getPragmas(&stringCount, 0, NULL);
191
192 size_t pragmaCount = static_cast<size_t>(stringCount) / 2;
193
194 size_t listSize = sizeof(OBCC_PragmaList) +
195 sizeof(OBCC_Pragma) * pragmaCount;
196
197 OBCC_PragmaList *list = (OBCC_PragmaList *)malloc(listSize);
198
199 if (!list) {
200 LOGE("Unable to allocate for pragma list\n");
201 return false;
202 }
203
204 mpPragmaListSection = list;
205 mpHeaderSection->pragma_list_size = listSize;
206
207 list->count = pragmaCount;
208
209 vector<char *> strings(stringCount);
210 mpOwner->getPragmas(&stringCount, stringCount, &*strings.begin());
211
212 for (size_t i = 0; i < pragmaCount; ++i) {
213 char *key = strings[2 * i];
214 size_t keyLen = strlen(key);
215
216 char *value = strings[2 * i + 1];
217 size_t valueLen = strlen(value);
218
219 OBCC_Pragma *pragma = &list->list[i];
220 pragma->key_strp_index = addString(key, keyLen);
221 pragma->value_strp_index = addString(value, valueLen);
222 }
223
224 return true;
225}
226
227
228bool CacheWriter::prepareRelocationTable() {
229 // TODO(logan): Implement relocation table cache write.
230 return false;
231}
232
233
234bool CacheWriter::prepareStringPool() {
235 // Calculate string pool size
236 size_t size = sizeof(OBCC_StringPool) +
237 sizeof(OBCC_String) * mStringPool.size();
238
239 off_t strOffset = size;
240
241 for (size_t i = 0; i < mStringPool.size(); ++i) {
242 size += mStringPool[i].second + 1;
243 }
244
245 // Create string pool
246 OBCC_StringPool *pool = (OBCC_StringPool *)malloc(size);
247
248 if (!pool) {
249 LOGE("Unable to allocate string pool.\n");
250 return false;
251 }
252
253 mpStringPoolSection = pool;
254 mpHeaderSection->str_pool_size = size;
255
Logana2e15af2011-01-07 11:46:08 +0800256 pool->count = mStringPool.size();
257
Logana27a83f2011-01-07 10:25:48 +0800258 char *strPtr = reinterpret_cast<char *>(pool) + strOffset;
259
260 for (size_t i = 0; i < mStringPool.size(); ++i) {
261 OBCC_String *str = &pool->list[i];
262
263 str->length = mStringPool[i].second;
264 str->offset = strOffset;
265 memcpy(strPtr, mStringPool[i].first, str->length);
266
267 strPtr += str->length;
268 *strPtr++ = '\0';
269
Logana2e15af2011-01-07 11:46:08 +0800270 strOffset += str->length + 1;
Logana27a83f2011-01-07 10:25:48 +0800271 }
272
273 return true;
274}
275
276
277bool CacheWriter::prepareExportVarList() {
278 ssize_t varCount;
279
280 mpOwner->getExportVars(&varCount, 0, NULL);
281
282 size_t listSize = sizeof(OBCC_ExportVarList) + sizeof(void *) * varCount;
283
284 OBCC_ExportVarList *list = (OBCC_ExportVarList *)malloc(listSize);
285
286 if (!list) {
287 LOGE("Unable to allocate for export variable list\n");
288 return false;
289 }
290
291 mpExportVarListSection = list;
292 mpHeaderSection->export_var_list_size = listSize;
293
294 list->count = static_cast<size_t>(varCount);
295
296 mpOwner->getExportVars(&varCount, varCount, list->cached_addr_list);
297 return true;
298}
299
300
301bool CacheWriter::prepareExportFuncList() {
302 ssize_t funcCount;
303
304 mpOwner->getExportFuncs(&funcCount, 0, NULL);
305
306 size_t listSize = sizeof(OBCC_ExportFuncList) + sizeof(void *) * funcCount;
307
308 OBCC_ExportFuncList *list = (OBCC_ExportFuncList *)malloc(listSize);
309
310 if (!list) {
311 LOGE("Unable to allocate for export function list\n");
312 return false;
313 }
314
315 mpExportFuncListSection = list;
316 mpHeaderSection->export_func_list_size = listSize;
317
318 list->count = static_cast<size_t>(funcCount);
319
320 mpOwner->getExportFuncs(&funcCount, funcCount, list->cached_addr_list);
321 return true;
322}
323
324
325bool CacheWriter::calcSectionOffset() {
326 size_t offset = sizeof(OBCC_Header);
327
328#define OFFSET_INCREASE(NAME) \
329 do { \
330 /* Align to a word */ \
331 size_t rem = offset % sizeof(int); \
332 if (rem > 0) { \
333 offset += sizeof(int) - rem; \
334 } \
335 \
336 /* Save the offset and increase it */ \
337 mpHeaderSection->NAME##_offset = offset; \
338 offset += mpHeaderSection->NAME##_size; \
339 } while (0)
340
341 OFFSET_INCREASE(str_pool);
342 OFFSET_INCREASE(depend_tab);
343 //OFFSET_INCREASE(reloc_tab);
344 OFFSET_INCREASE(export_var_list);
345 OFFSET_INCREASE(export_func_list);
346 OFFSET_INCREASE(pragma_list);
347 OFFSET_INCREASE(func_table);
348
349#undef OFFSET_INCREASE
350
351 // Context
352 long pagesize = sysconf(_SC_PAGESIZE);
353 size_t context_offset_rem = offset % pagesize;
354 if (context_offset_rem) {
355 offset += pagesize - context_offset_rem;
356 }
357
358 mpHeaderSection->context_offset = offset;
359 return true;
360}
361
362
363bool CacheWriter::calcContextChecksum() {
364 uint32_t sum = 0;
365 uint32_t *ptr = reinterpret_cast<uint32_t *>(mpOwner->getContext());
366
367 for (size_t i = 0; i < BCC_CONTEXT_SIZE / sizeof(uint32_t); ++i) {
368 sum ^= *ptr++;
369 }
370
371 mpHeaderSection->context_parity_checksum = sum;
372 return true;
373}
374
375
376bool CacheWriter::writeAll() {
377#define WRITE_SECTION(NAME, OFFSET, SIZE, SECTION) \
378 do { \
379 if (mFile->seek(OFFSET, SEEK_SET) == -1) { \
380 LOGE("Unable to seek to " #NAME " section for writing.\n"); \
381 return false; \
382 } \
383 \
384 if (mFile->write(reinterpret_cast<char *>(SECTION), (SIZE)) != \
385 static_cast<ssize_t>(SIZE)) { \
386 LOGE("Unable to write " #NAME " section to cache file.\n"); \
387 return false; \
388 } \
389 } while (0)
390
391#define WRITE_SECTION_SIMPLE(NAME, SECTION) \
392 WRITE_SECTION(NAME, \
393 mpHeaderSection->NAME##_offset, \
394 mpHeaderSection->NAME##_size, \
395 SECTION)
396
397 WRITE_SECTION(header, 0, sizeof(OBCC_Header), mpHeaderSection);
398
399 WRITE_SECTION_SIMPLE(str_pool, mpStringPoolSection);
400 WRITE_SECTION_SIMPLE(depend_tab, mpDependencyTableSection);
401 //WRITE_SECTION_SIMPLE(reloc_tab, mpRelocationTableSection);
402 WRITE_SECTION_SIMPLE(export_var_list, mpExportVarListSection);
403 WRITE_SECTION_SIMPLE(export_func_list, mpExportFuncListSection);
404 WRITE_SECTION_SIMPLE(pragma_list, mpPragmaListSection);
405 WRITE_SECTION_SIMPLE(func_table, mpFuncTableSection);
406
407 WRITE_SECTION(context, mpHeaderSection->context_offset, BCC_CONTEXT_SIZE,
408 mpOwner->getContext());
409
410#undef WRITE_SECTION_SIMPLE
411#undef WRITE_SECTION
412
413 return true;
414}
415
416
Logana27a83f2011-01-07 10:25:48 +0800417} // namespace bcc