MCCacheWriter.cpp revision 5e3e0ce19d80c9a42b89ca95f22d98fbbe6ffb14
1/*
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#include "MCCacheWriter.h"
18
19#include "ContextManager.h"
20#include "DebugHelper.h"
21#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
35#if USE_MCJIT
36namespace bcc {
37
38MCCacheWriter::~MCCacheWriter() {
39#define CHECK_AND_FREE(VAR) if (VAR) { free(VAR); }
40
41  CHECK_AND_FREE(mpHeaderSection);
42  CHECK_AND_FREE(mpStringPoolSection);
43  CHECK_AND_FREE(mpDependencyTableSection);
44  CHECK_AND_FREE(mpExportVarListSection);
45  CHECK_AND_FREE(mpExportFuncListSection);
46  CHECK_AND_FREE(mpPragmaListSection);
47  CHECK_AND_FREE(mpFuncTableSection);
48  CHECK_AND_FREE(mpObjectSlotSection);
49
50#undef CHECK_AND_FREE
51}
52
53bool MCCacheWriter::writeCacheFile(FileHandle *objFile, FileHandle *infoFile,
54                                 Script *S, uint32_t libRS_threadable) {
55  if (!objFile || objFile->getFD() < 0 || !infoFile || infoFile->getFD() < 0) {
56    return false;
57  }
58
59  mObjFile = objFile;
60  mInfoFile = infoFile;
61  mpOwner = S;
62
63  bool result = prepareHeader(libRS_threadable)
64             && prepareDependencyTable()
65             && prepareFuncTable()
66             && preparePragmaList()
67             && prepareStringPool()
68             && prepareExportVarList()
69             && prepareExportFuncList()
70             && prepareObjectSlotList()
71             && calcSectionOffset()
72             && writeAll()
73             ;
74
75  return result;
76}
77
78
79bool MCCacheWriter::prepareHeader(uint32_t libRS_threadable) {
80  MCO_Header *header = (MCO_Header *)malloc(sizeof(MCO_Header));
81
82  if (!header) {
83    LOGE("Unable to allocate for header.\n");
84    return false;
85  }
86
87  mpHeaderSection = header;
88
89  // Initialize
90  memset(header, '\0', sizeof(MCO_Header));
91
92  // Magic word and version
93  memcpy(header->magic, OBCC_MAGIC, 4);
94  memcpy(header->version, OBCC_VERSION, 4);
95  memcpy(header->libbcc_build_time, libbcc_build_time, 24);
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  header->root_base_addr = mpOwner->lookup("root");
105
106  LOGD("Lookup root() address [%p]", header->root_base_addr);
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 MCCacheWriter::prepareDependencyTable() {
117  size_t tableSize = sizeof(OBCC_DependencyTable) +
118                     sizeof(OBCC_Dependency) * mDependencies.size();
119
120  OBCC_DependencyTable *tab = (OBCC_DependencyTable *)malloc(tableSize);
121
122  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 MCCacheWriter::prepareFuncTable() {
147  size_t funcCount = mpOwner->getFuncCount();
148
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;
160  mpHeaderSection->func_table_size = tableSize;
161
162  tab->count = static_cast<size_t>(funcCount);
163
164  // Get the function informations
165  vector<FuncInfo> funcInfoList(funcCount);
166  mpOwner->getFuncInfoList(funcCount, &*funcInfoList.begin());
167
168  for (size_t i = 0; i < funcCount; ++i) {
169    FuncInfo *info = &funcInfoList[i];
170    OBCC_FuncInfo *outputInfo = &tab->table[i];
171
172    outputInfo->name_strp_index = addString(info->name, strlen(info->name));
173    outputInfo->cached_addr = info->addr;
174    outputInfo->size = info->size;
175  }
176
177  return true;
178}
179
180
181bool MCCacheWriter::preparePragmaList() {
182  size_t pragmaCount = mpOwner->getPragmaCount();
183
184  size_t listSize = sizeof(OBCC_PragmaList) +
185                    sizeof(OBCC_Pragma) * pragmaCount;
186
187  OBCC_PragmaList *list = (OBCC_PragmaList *)malloc(listSize);
188
189  if (!list) {
190    LOGE("Unable to allocate for pragma list\n");
191    return false;
192  }
193
194  mpPragmaListSection = list;
195  mpHeaderSection->pragma_list_size = listSize;
196
197  list->count = pragmaCount;
198
199  vector<char const *> keyList(pragmaCount);
200  vector<char const *> valueList(pragmaCount);
201  mpOwner->getPragmaList(pragmaCount, &*keyList.begin(), &*valueList.begin());
202
203  for (size_t i = 0; i < pragmaCount; ++i) {
204    char const *key = keyList[i];
205    char const *value = valueList[i];
206
207    size_t keyLen = strlen(key);
208    size_t valueLen = strlen(value);
209
210    OBCC_Pragma *pragma = &list->list[i];
211    pragma->key_strp_index = addString(key, keyLen);
212    pragma->value_strp_index = addString(value, valueLen);
213  }
214
215  return true;
216}
217
218bool MCCacheWriter::prepareStringPool() {
219  // Calculate string pool size
220  size_t size = sizeof(OBCC_StringPool) +
221                sizeof(OBCC_String) * mStringPool.size();
222
223  off_t strOffset = size;
224
225  for (size_t i = 0; i < mStringPool.size(); ++i) {
226    size += mStringPool[i].second + 1;
227  }
228
229  // Create string pool
230  OBCC_StringPool *pool = (OBCC_StringPool *)malloc(size);
231
232  if (!pool) {
233    LOGE("Unable to allocate string pool.\n");
234    return false;
235  }
236
237  mpStringPoolSection = pool;
238  mpHeaderSection->str_pool_size = size;
239
240  pool->count = mStringPool.size();
241
242  char *strPtr = reinterpret_cast<char *>(pool) + strOffset;
243
244  for (size_t i = 0; i < mStringPool.size(); ++i) {
245    OBCC_String *str = &pool->list[i];
246
247    str->length = mStringPool[i].second;
248    str->offset = strOffset;
249    memcpy(strPtr, mStringPool[i].first, str->length);
250
251    strPtr += str->length;
252    *strPtr++ = '\0';
253
254    strOffset += str->length + 1;
255  }
256
257  return true;
258}
259
260
261bool MCCacheWriter::prepareExportVarList() {
262  size_t varCount = mpOwner->getExportVarCount();
263  size_t listSize = sizeof(OBCC_ExportVarList) + sizeof(void *) * varCount;
264
265  OBCC_ExportVarList *list = (OBCC_ExportVarList *)malloc(listSize);
266
267  if (!list) {
268    LOGE("Unable to allocate for export variable list\n");
269    return false;
270  }
271
272  mpExportVarListSection = list;
273  mpHeaderSection->export_var_list_size = listSize;
274
275  list->count = static_cast<size_t>(varCount);
276
277  mpOwner->getExportVarList(varCount, list->cached_addr_list);
278  return true;
279}
280
281
282bool MCCacheWriter::prepareExportFuncList() {
283  size_t funcCount = mpOwner->getExportFuncCount();
284  size_t listSize = sizeof(OBCC_ExportFuncList) + sizeof(void *) * funcCount;
285
286  OBCC_ExportFuncList *list = (OBCC_ExportFuncList *)malloc(listSize);
287
288  if (!list) {
289    LOGE("Unable to allocate for export function list\n");
290    return false;
291  }
292
293  mpExportFuncListSection = list;
294  mpHeaderSection->export_func_list_size = listSize;
295
296  list->count = static_cast<size_t>(funcCount);
297
298  mpOwner->getExportFuncList(funcCount, list->cached_addr_list);
299  return true;
300}
301
302
303bool MCCacheWriter::prepareObjectSlotList() {
304  size_t objectSlotCount = mpOwner->getObjectSlotCount();
305
306  size_t listSize = sizeof(OBCC_ObjectSlotList) +
307                    sizeof(uint32_t) * objectSlotCount;
308
309  OBCC_ObjectSlotList *list = (OBCC_ObjectSlotList *)malloc(listSize);
310
311  if (!list) {
312    LOGE("Unable to allocate for object slot list\n");
313    return false;
314  }
315
316  mpObjectSlotSection = list;
317  mpHeaderSection->object_slot_list_size = listSize;
318
319  list->count = objectSlotCount;
320
321  mpOwner->getObjectSlotList(objectSlotCount, list->object_slot_list);
322  return true;
323}
324
325
326bool MCCacheWriter::calcSectionOffset() {
327  size_t offset = sizeof(MCO_Header);
328
329#define OFFSET_INCREASE(NAME)                                               \
330  do {                                                                      \
331    /* Align to a word */                                                   \
332    size_t rem = offset % sizeof(int);                                      \
333    if (rem > 0) {                                                          \
334      offset += sizeof(int) - rem;                                          \
335    }                                                                       \
336                                                                            \
337    /* Save the offset and increase it */                                   \
338    mpHeaderSection->NAME##_offset = offset;                                \
339    offset += mpHeaderSection->NAME##_size;                                 \
340  } while (0)
341
342  OFFSET_INCREASE(str_pool);
343  OFFSET_INCREASE(depend_tab);
344  OFFSET_INCREASE(export_var_list);
345  OFFSET_INCREASE(export_func_list);
346  OFFSET_INCREASE(pragma_list);
347  OFFSET_INCREASE(func_table);
348  OFFSET_INCREASE(object_slot_list);
349
350#undef OFFSET_INCREASE
351
352  return true;
353}
354
355
356bool MCCacheWriter::writeAll() {
357#define WRITE_SECTION(NAME, OFFSET, SIZE, SECTION)                          \
358  do {                                                                      \
359    if (mInfoFile->seek(OFFSET, SEEK_SET) == -1) {                              \
360      LOGE("Unable to seek to " #NAME " section for writing.\n");           \
361      return false;                                                         \
362    }                                                                       \
363                                                                            \
364    if (mInfoFile->write(reinterpret_cast<char *>(SECTION), (SIZE)) !=          \
365        static_cast<ssize_t>(SIZE)) {                                       \
366      LOGE("Unable to write " #NAME " section to cache file.\n");           \
367      return false;                                                         \
368    }                                                                       \
369  } while (0)
370
371#define WRITE_SECTION_SIMPLE(NAME, SECTION)                                 \
372  WRITE_SECTION(NAME,                                                       \
373                mpHeaderSection->NAME##_offset,                             \
374                mpHeaderSection->NAME##_size,                               \
375                SECTION)
376
377  WRITE_SECTION(header, 0, sizeof(MCO_Header), mpHeaderSection);
378
379  WRITE_SECTION_SIMPLE(str_pool, mpStringPoolSection);
380  WRITE_SECTION_SIMPLE(depend_tab, mpDependencyTableSection);
381  WRITE_SECTION_SIMPLE(export_var_list, mpExportVarListSection);
382  WRITE_SECTION_SIMPLE(export_func_list, mpExportFuncListSection);
383  WRITE_SECTION_SIMPLE(pragma_list, mpPragmaListSection);
384  WRITE_SECTION_SIMPLE(func_table, mpFuncTableSection);
385  WRITE_SECTION_SIMPLE(object_slot_list, mpObjectSlotSection);
386
387#undef WRITE_SECTION_SIMPLE
388#undef WRITE_SECTION
389
390  if (static_cast<size_t>(mObjFile->write(mpOwner->getELF(), mpOwner->getELFSize()))
391      != mpOwner->getELFSize()) {
392      LOGE("Unable to write ELF to cache file.\n");
393      return false;
394  }
395
396  return true;
397}
398
399
400} // namespace bcc
401#endif
402