• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2010-2012, 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 "DebugHelper.h"
20 #include "FileHandle.h"
21 #include "Script.h"
22 
23 #include <map>
24 #include <string>
25 #include <vector>
26 #include <utility>
27 
28 #include <stdint.h>
29 #include <stdlib.h>
30 #include <string.h>
31 
32 using namespace std;
33 
34 namespace bcc {
35 
~MCCacheWriter()36 MCCacheWriter::~MCCacheWriter() {
37 #define CHECK_AND_FREE(VAR) if (VAR) { free(VAR); }
38 
39   CHECK_AND_FREE(mpHeaderSection);
40   CHECK_AND_FREE(mpStringPoolSection);
41   CHECK_AND_FREE(mpDependencyTableSection);
42   CHECK_AND_FREE(mpPragmaListSection);
43   CHECK_AND_FREE(mpObjectSlotSection);
44   CHECK_AND_FREE(mpExportVarNameListSection);
45   CHECK_AND_FREE(mpExportFuncNameListSection);
46 
47 #undef CHECK_AND_FREE
48 }
49 
writeCacheFile(FileHandle * objFile,FileHandle * infoFile,Script * S,uint32_t libRS_threadable)50 bool MCCacheWriter::writeCacheFile(FileHandle *objFile, FileHandle *infoFile,
51                                  Script *S, uint32_t libRS_threadable) {
52   if (!objFile || objFile->getFD() < 0 || !infoFile || infoFile->getFD() < 0) {
53     return false;
54   }
55 
56   mObjFile = objFile;
57   mInfoFile = infoFile;
58   mpOwner = S;
59 
60   bool result = prepareHeader(libRS_threadable)
61              && prepareDependencyTable()
62              && preparePragmaList()
63              && prepareExportVarNameList()
64              && prepareExportFuncNameList()
65              && prepareExportForEachNameList()
66              && prepareStringPool()
67              && prepareObjectSlotList()
68              && calcSectionOffset()
69              && writeAll()
70              ;
71 
72   return result;
73 }
74 
75 
prepareHeader(uint32_t libRS_threadable)76 bool MCCacheWriter::prepareHeader(uint32_t libRS_threadable) {
77   MCO_Header *header = (MCO_Header *)malloc(sizeof(MCO_Header));
78 
79   if (!header) {
80     ALOGE("Unable to allocate for header.\n");
81     return false;
82   }
83 
84   mpHeaderSection = header;
85 
86   // Initialize
87   memset(header, '\0', sizeof(MCO_Header));
88 
89   // Magic word and version
90   memcpy(header->magic, MCO_MAGIC, 4);
91   memcpy(header->version, MCO_VERSION, 4);
92 
93   // Machine Integer Type
94   uint32_t number = 0x00000001;
95   header->endianness = (*reinterpret_cast<char *>(&number) == 1) ? 'e' : 'E';
96   header->sizeof_off_t = sizeof(off_t);
97   header->sizeof_size_t = sizeof(size_t);
98   header->sizeof_ptr_t = sizeof(void *);
99 
100   // libRS is threadable dirty hack
101   // TODO: This should be removed in the future
102   header->libRS_threadable = libRS_threadable;
103 
104   return true;
105 }
106 
107 
prepareDependencyTable()108 bool MCCacheWriter::prepareDependencyTable() {
109   size_t tableSize = sizeof(MCO_DependencyTable) +
110                      sizeof(MCO_Dependency) * mDependencies.size();
111 
112   MCO_DependencyTable *tab = (MCO_DependencyTable *)malloc(tableSize);
113 
114   if (!tab) {
115     ALOGE("Unable to allocate for dependency table section.\n");
116     return false;
117   }
118 
119   mpDependencyTableSection = tab;
120   mpHeaderSection->depend_tab_size = tableSize;
121 
122   tab->count = mDependencies.size();
123 
124   size_t i = 0;
125   for (map<string, pair<uint32_t, unsigned char const *> >::iterator
126        I = mDependencies.begin(), E = mDependencies.end(); I != E; ++I, ++i) {
127     MCO_Dependency *dep = &tab->table[i];
128 
129     dep->res_name_strp_index = addString(I->first.c_str(), I->first.size());
130     dep->res_type = I->second.first;
131     memcpy(dep->sha1, I->second.second, 20);
132   }
133 
134   return true;
135 }
136 
preparePragmaList()137 bool MCCacheWriter::preparePragmaList() {
138   size_t pragmaCount = mpOwner->getPragmaCount();
139 
140   size_t listSize = sizeof(MCO_PragmaList) +
141                     sizeof(MCO_Pragma) * pragmaCount;
142 
143   MCO_PragmaList *list = (MCO_PragmaList *)malloc(listSize);
144 
145   if (!list) {
146     ALOGE("Unable to allocate for pragma list\n");
147     return false;
148   }
149 
150   mpPragmaListSection = list;
151   mpHeaderSection->pragma_list_size = listSize;
152 
153   list->count = pragmaCount;
154 
155   vector<char const *> keyList(pragmaCount);
156   vector<char const *> valueList(pragmaCount);
157   mpOwner->getPragmaList(pragmaCount, &*keyList.begin(), &*valueList.begin());
158 
159   for (size_t i = 0; i < pragmaCount; ++i) {
160     char const *key = keyList[i];
161     char const *value = valueList[i];
162 
163     size_t keyLen = strlen(key);
164     size_t valueLen = strlen(value);
165 
166     MCO_Pragma *pragma = &list->list[i];
167     pragma->key_strp_index = addString(key, keyLen);
168     pragma->value_strp_index = addString(value, valueLen);
169   }
170 
171   return true;
172 }
173 
prepareStringPool()174 bool MCCacheWriter::prepareStringPool() {
175   // Calculate string pool size
176   size_t size = sizeof(MCO_StringPool) +
177                 sizeof(MCO_String) * mStringPool.size();
178 
179   off_t strOffset = size;
180 
181   for (size_t i = 0; i < mStringPool.size(); ++i) {
182     size += mStringPool[i].second + 1;
183   }
184 
185   // Create string pool
186   MCO_StringPool *pool = (MCO_StringPool *)malloc(size);
187 
188   if (!pool) {
189     ALOGE("Unable to allocate string pool.\n");
190     return false;
191   }
192 
193   mpStringPoolSection = pool;
194   mpHeaderSection->str_pool_size = size;
195 
196   pool->count = mStringPool.size();
197 
198   char *strPtr = reinterpret_cast<char *>(pool) + strOffset;
199 
200   for (size_t i = 0; i < mStringPool.size(); ++i) {
201     MCO_String *str = &pool->list[i];
202 
203     str->length = mStringPool[i].second;
204     str->offset = strOffset;
205     memcpy(strPtr, mStringPool[i].first, str->length);
206 
207     strPtr += str->length;
208     *strPtr++ = '\0';
209 
210     strOffset += str->length + 1;
211   }
212 
213   return true;
214 }
215 
216 
prepareExportVarNameList()217 bool MCCacheWriter::prepareExportVarNameList() {
218   size_t varCount = mpOwner->getExportVarCount();
219   size_t listSize = sizeof(MCO_String_Ptr) + sizeof(size_t) * varCount;
220 
221   MCO_String_Ptr *list = (MCO_String_Ptr*)malloc(listSize);
222 
223   if (!list) {
224     ALOGE("Unable to allocate for export variable name list\n");
225     return false;
226   }
227 
228   mpExportVarNameListSection = list;
229   mpHeaderSection->export_var_name_list_size = listSize;
230 
231   list->count = static_cast<size_t>(varCount);
232 
233   mpOwner->getExportVarNameList(varNameList);
234   for (size_t i = 0; i < varCount; ++i) {
235     list->strp_indexs[i] = addString(varNameList[i].c_str(), varNameList[i].length());
236   }
237   return true;
238 }
239 
240 
prepareExportFuncNameList()241 bool MCCacheWriter::prepareExportFuncNameList() {
242   size_t funcCount = mpOwner->getExportFuncCount();
243   size_t listSize = sizeof(MCO_String_Ptr) + sizeof(size_t) * funcCount;
244 
245   MCO_String_Ptr *list = (MCO_String_Ptr*)malloc(listSize);
246 
247   if (!list) {
248     ALOGE("Unable to allocate for export function name list\n");
249     return false;
250   }
251 
252   mpExportFuncNameListSection = list;
253   mpHeaderSection->export_func_name_list_size = listSize;
254 
255   list->count = static_cast<size_t>(funcCount);
256 
257   mpOwner->getExportFuncNameList(funcNameList);
258   for (size_t i = 0; i < funcCount; ++i) {
259     list->strp_indexs[i] = addString(funcNameList[i].c_str(), funcNameList[i].length());
260   }
261   return true;
262 }
263 
264 
prepareExportForEachNameList()265 bool MCCacheWriter::prepareExportForEachNameList() {
266   size_t forEachCount = mpOwner->getExportForEachCount();
267   size_t listSize = sizeof(MCO_String_Ptr) + sizeof(size_t) * forEachCount;
268 
269   MCO_String_Ptr *list = (MCO_String_Ptr*)malloc(listSize);
270 
271   if (!list) {
272     ALOGE("Unable to allocate for export forEach name list\n");
273     return false;
274   }
275 
276   mpExportForEachNameListSection = list;
277   mpHeaderSection->export_foreach_name_list_size = listSize;
278 
279   list->count = static_cast<size_t>(forEachCount);
280 
281   mpOwner->getExportForEachNameList(forEachNameList);
282   for (size_t i = 0; i < forEachCount; ++i) {
283     list->strp_indexs[i] = addString(forEachNameList[i].c_str(), forEachNameList[i].length());
284   }
285   return true;
286 }
287 
288 
prepareObjectSlotList()289 bool MCCacheWriter::prepareObjectSlotList() {
290   size_t objectSlotCount = mpOwner->getObjectSlotCount();
291 
292   size_t listSize = sizeof(MCO_ObjectSlotList) +
293                     sizeof(uint32_t) * objectSlotCount;
294 
295   MCO_ObjectSlotList *list = (MCO_ObjectSlotList *)malloc(listSize);
296 
297   if (!list) {
298     ALOGE("Unable to allocate for object slot list\n");
299     return false;
300   }
301 
302   mpObjectSlotSection = list;
303   mpHeaderSection->object_slot_list_size = listSize;
304 
305   list->count = objectSlotCount;
306 
307   mpOwner->getObjectSlotList(objectSlotCount, list->object_slot_list);
308   return true;
309 }
310 
311 
calcSectionOffset()312 bool MCCacheWriter::calcSectionOffset() {
313   size_t offset = sizeof(MCO_Header);
314 
315 #define OFFSET_INCREASE(NAME)                                               \
316   do {                                                                      \
317     /* Align to a word */                                                   \
318     size_t rem = offset % sizeof(int);                                      \
319     if (rem > 0) {                                                          \
320       offset += sizeof(int) - rem;                                          \
321     }                                                                       \
322                                                                             \
323     /* Save the offset and increase it */                                   \
324     mpHeaderSection->NAME##_offset = offset;                                \
325     offset += mpHeaderSection->NAME##_size;                                 \
326   } while (0)
327 
328   OFFSET_INCREASE(str_pool);
329   OFFSET_INCREASE(depend_tab);
330   OFFSET_INCREASE(pragma_list);
331   OFFSET_INCREASE(func_table);
332   OFFSET_INCREASE(object_slot_list);
333   OFFSET_INCREASE(export_var_name_list);
334   OFFSET_INCREASE(export_func_name_list);
335   OFFSET_INCREASE(export_foreach_name_list);
336 
337 #undef OFFSET_INCREASE
338 
339   return true;
340 }
341 
342 
writeAll()343 bool MCCacheWriter::writeAll() {
344 #define WRITE_SECTION(NAME, OFFSET, SIZE, SECTION)                          \
345   do {                                                                      \
346     if (mInfoFile->seek(OFFSET, SEEK_SET) == -1) {                          \
347       ALOGE("Unable to seek to " #NAME " section for writing.\n");           \
348       return false;                                                         \
349     }                                                                       \
350                                                                             \
351     if (mInfoFile->write(reinterpret_cast<char *>(SECTION), (SIZE)) !=      \
352         static_cast<ssize_t>(SIZE)) {                                       \
353       ALOGE("Unable to write " #NAME " section to cache file.\n");           \
354       return false;                                                         \
355     }                                                                       \
356   } while (0)
357 
358 #define WRITE_SECTION_SIMPLE(NAME, SECTION)                                 \
359   WRITE_SECTION(NAME,                                                       \
360                 mpHeaderSection->NAME##_offset,                             \
361                 mpHeaderSection->NAME##_size,                               \
362                 SECTION)
363 
364   WRITE_SECTION(header, 0, sizeof(MCO_Header), mpHeaderSection);
365 
366   WRITE_SECTION_SIMPLE(str_pool, mpStringPoolSection);
367   WRITE_SECTION_SIMPLE(depend_tab, mpDependencyTableSection);
368   WRITE_SECTION_SIMPLE(pragma_list, mpPragmaListSection);
369   WRITE_SECTION_SIMPLE(object_slot_list, mpObjectSlotSection);
370 
371   WRITE_SECTION_SIMPLE(export_var_name_list, mpExportVarNameListSection);
372   WRITE_SECTION_SIMPLE(export_func_name_list, mpExportFuncNameListSection);
373   WRITE_SECTION_SIMPLE(export_foreach_name_list, mpExportForEachNameListSection);
374 
375 #undef WRITE_SECTION_SIMPLE
376 #undef WRITE_SECTION
377 
378   if (static_cast<size_t>(mObjFile->write(mpOwner->getELF(),
379                                           mpOwner->getELFSize()))
380       != mpOwner->getELFSize()) {
381       ALOGE("Unable to write ELF to cache file.\n");
382       return false;
383   }
384 
385   return true;
386 }
387 
388 } // namespace bcc
389