blob: 692cac310cacc62d101ebacfd9f1aed0679d926a [file] [log] [blame]
Shih-wei Liao5e3e0ce2011-06-17 13:59:46 -07001/*
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 "MCCacheReader.h"
18
19#include "ContextManager.h"
20#include "DebugHelper.h"
21#include "FileHandle.h"
22#include "ScriptCached.h"
23#include "Runtime.h"
24
25#include <bcc/bcc_mccache.h>
26
27#include <llvm/ADT/OwningPtr.h>
28
29#include <errno.h>
30#include <sys/stat.h>
31#include <sys/types.h>
32
33#include <utility>
34#include <vector>
35
36#include <new>
37
38#include <stdlib.h>
39#include <string.h>
40
41using namespace std;
42
43
44#if USE_MCJIT
45namespace bcc {
46
47MCCacheReader::~MCCacheReader() {
48 if (mpHeader) { free(mpHeader); }
49 if (mpCachedDependTable) { free(mpCachedDependTable); }
50 if (mpPragmaList) { free(mpPragmaList); }
51 if (mpFuncTable) { free(mpFuncTable); }
52}
53
54ScriptCached *MCCacheReader::readCacheFile(FileHandle *objFile, FileHandle *infoFile, Script *S) {
55 // Check file handle
56 if (!objFile || objFile->getFD() < 0 || !infoFile || infoFile->getFD() < 0) {
57 return false;
58 }
59
60 mObjFile = objFile;
61 mInfoFile = infoFile;
62
63 // Allocate ScriptCached object
64 mpResult.reset(new (nothrow) ScriptCached(S));
65
66 if (!mpResult) {
67 LOGE("Unable to allocate ScriptCached object.\n");
68 return NULL;
69 }
70
71 bool result = checkFileSize()
72 && readHeader()
73 && checkHeader()
74 && checkMachineIntType()
75 && checkSectionOffsetAndSize()
76 && readStringPool()
77 && checkStringPool()
78 && readDependencyTable()
79 && checkDependency()
80 && readExportVarList()
81 && readExportFuncList()
82 && readPragmaList()
83 && readFuncTable()
84 && readObjectSlotList()
85 && readObjFile()
86 && relocate()
87 ;
88
89 return result ? mpResult.take() : NULL;
90}
91
92
93bool MCCacheReader::checkFileSize() {
94 struct stat stfile;
95 if (fstat(mInfoFile->getFD(), &stfile) < 0) {
96 LOGE("Unable to stat cache file.\n");
97 return false;
98 }
99
100 mInfoFileSize = stfile.st_size;
101
102 if (mInfoFileSize < (off_t)sizeof(MCO_Header)) {
103 LOGE("Cache file is too small to be correct.\n");
104 return false;
105 }
106
107 return true;
108}
109
110
111bool MCCacheReader::readHeader() {
112 if (mInfoFile->seek(0, SEEK_SET) != 0) {
113 LOGE("Unable to seek to 0. (reason: %s)\n", strerror(errno));
114 return false;
115 }
116
117 mpHeader = (MCO_Header *)malloc(sizeof(MCO_Header));
118 if (!mpHeader) {
119 LOGE("Unable to allocate for cache header.\n");
120 return false;
121 }
122
123 if (mInfoFile->read(reinterpret_cast<char *>(mpHeader), sizeof(MCO_Header)) !=
124 (ssize_t)sizeof(MCO_Header)) {
125 LOGE("Unable to read cache header.\n");
126 return false;
127 }
128
129 // Dirty hack for libRS.
130 // TODO(all): This should be removed in the future.
131 if (mpHeader->libRS_threadable) {
132 mpResult->mLibRSThreadable = true;
133 }
134
135 return true;
136}
137
138
139bool MCCacheReader::checkHeader() {
140 if (memcmp(mpHeader->magic, OBCC_MAGIC, 4) != 0) {
141 LOGE("Bad magic word\n");
142 return false;
143 }
144
145 if (memcmp(mpHeader->version, OBCC_VERSION, 4) != 0) {
146 mpHeader->version[4 - 1] = '\0'; // ensure c-style string terminated
147 LOGI("Cache file format version mismatch: now %s cached %s\n",
148 OBCC_VERSION, mpHeader->version);
149 return false;
150 }
151
152 if (memcmp(mpHeader->libbcc_build_time, libbcc_build_time, 24) != 0) {
153 mpHeader->libbcc_build_time[24 - 1] = '\0'; // ensure terminated
154 LOGW("Build time mismatch: lib %s cached %s\n", libbcc_build_time,
155 mpHeader->libbcc_build_time);
156 return false;
157 }
158
159 return true;
160}
161
162
163bool MCCacheReader::checkMachineIntType() {
164 uint32_t number = 0x00000001;
165
166 bool isLittleEndian = (*reinterpret_cast<char *>(&number) == 1);
167 if ((isLittleEndian && mpHeader->endianness != 'e') ||
168 (!isLittleEndian && mpHeader->endianness != 'E')) {
169 LOGE("Machine endianness mismatch.\n");
170 return false;
171 }
172
173 if ((unsigned int)mpHeader->sizeof_off_t != sizeof(off_t) ||
174 (unsigned int)mpHeader->sizeof_size_t != sizeof(size_t) ||
175 (unsigned int)mpHeader->sizeof_ptr_t != sizeof(void *)) {
176 LOGE("Machine integer size mismatch.\n");
177 return false;
178 }
179
180 return true;
181}
182
183
184bool MCCacheReader::checkSectionOffsetAndSize() {
185#define CHECK_SECTION_OFFSET(NAME) \
186 do { \
187 off_t offset = mpHeader-> NAME##_offset; \
188 off_t size = (off_t)mpHeader-> NAME##_size; \
189 \
190 if (mInfoFileSize < offset || mInfoFileSize < offset + size) { \
191 LOGE(#NAME " section overflow.\n"); \
192 return false; \
193 } \
194 \
195 if (offset % sizeof(int) != 0) { \
196 LOGE(#NAME " offset must aligned to %d.\n", (int)sizeof(int)); \
197 return false; \
198 } \
199 \
200 if (size < static_cast<off_t>(sizeof(size_t))) { \
201 LOGE(#NAME " size is too small to be correct.\n"); \
202 return false; \
203 } \
204 } while (0)
205
206 CHECK_SECTION_OFFSET(str_pool);
207 CHECK_SECTION_OFFSET(depend_tab);
208 //CHECK_SECTION_OFFSET(reloc_tab);
209 CHECK_SECTION_OFFSET(export_var_list);
210 CHECK_SECTION_OFFSET(export_func_list);
211 CHECK_SECTION_OFFSET(pragma_list);
212
213#undef CHECK_SECTION_OFFSET
214
215 return true;
216}
217
218
219#define CACHE_READER_READ_SECTION(TYPE, AUTO_MANAGED_HOLDER, NAME) \
220 TYPE *NAME##_raw = (TYPE *)malloc(mpHeader->NAME##_size); \
221 \
222 if (!NAME##_raw) { \
223 LOGE("Unable to allocate for " #NAME "\n"); \
224 return false; \
225 } \
226 \
227 /* We have to ensure that some one will deallocate NAME##_raw */ \
228 AUTO_MANAGED_HOLDER = NAME##_raw; \
229 \
230 if (mInfoFile->seek(mpHeader->NAME##_offset, SEEK_SET) == -1) { \
231 LOGE("Unable to seek to " #NAME " section\n"); \
232 return false; \
233 } \
234 \
235 if (mInfoFile->read(reinterpret_cast<char *>(NAME##_raw), \
236 mpHeader->NAME##_size) != (ssize_t)mpHeader->NAME##_size) \
237 { \
238 LOGE("Unable to read " #NAME ".\n"); \
239 return false; \
240 }
241
242
243bool MCCacheReader::readStringPool() {
244 CACHE_READER_READ_SECTION(OBCC_StringPool,
245 mpResult->mpStringPoolRaw, str_pool);
246
247 char *str_base = reinterpret_cast<char *>(str_pool_raw);
248
249 vector<char const *> &pool = mpResult->mStringPool;
250 for (size_t i = 0; i < str_pool_raw->count; ++i) {
251 char *str = str_base + str_pool_raw->list[i].offset;
252 pool.push_back(str);
253 }
254
255 return true;
256}
257
258
259bool MCCacheReader::checkStringPool() {
260 OBCC_StringPool *poolR = mpResult->mpStringPoolRaw;
261 vector<char const *> &pool = mpResult->mStringPool;
262
263 // Ensure that every c-style string is ended with '\0'
264 for (size_t i = 0; i < poolR->count; ++i) {
265 if (pool[i][poolR->list[i].length] != '\0') {
266 LOGE("The %lu-th string does not end with '\\0'.\n", (unsigned long)i);
267 return false;
268 }
269 }
270
271 return true;
272}
273
274
275bool MCCacheReader::readDependencyTable() {
276 CACHE_READER_READ_SECTION(OBCC_DependencyTable, mpCachedDependTable,
277 depend_tab);
278 return true;
279}
280
281
282bool MCCacheReader::checkDependency() {
283 if (mDependencies.size() != mpCachedDependTable->count) {
284 LOGE("Dependencies count mismatch. (%lu vs %lu)\n",
285 (unsigned long)mDependencies.size(),
286 (unsigned long)mpCachedDependTable->count);
287 return false;
288 }
289
290 vector<char const *> &strPool = mpResult->mStringPool;
291 map<string, pair<uint32_t, unsigned char const *> >::iterator dep;
292
293 dep = mDependencies.begin();
294 for (size_t i = 0; i < mpCachedDependTable->count; ++i, ++dep) {
295 string const &depName = dep->first;
296 uint32_t depType = dep->second.first;
297 unsigned char const *depSHA1 = dep->second.second;
298
299 OBCC_Dependency *depCached =&mpCachedDependTable->table[i];
300 char const *depCachedName = strPool[depCached->res_name_strp_index];
301 uint32_t depCachedType = depCached->res_type;
302 unsigned char const *depCachedSHA1 = depCached->sha1;
303
304 if (depName != depCachedName) {
305 LOGE("Cache dependency name mismatch:\n");
306 LOGE(" given: %s\n", depName.c_str());
307 LOGE(" cached: %s\n", depCachedName);
308
309 return false;
310 }
311
312 if (memcmp(depSHA1, depCachedSHA1, 20) != 0) {
313 LOGE("Cache dependency %s sha1 mismatch:\n", depCachedName);
314
315#define PRINT_SHA1(PREFIX, X, POSTFIX) \
316 LOGE(PREFIX "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" \
317 "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" POSTFIX, \
318 X[0], X[1], X[2], X[3], X[4], X[5], X[6], X[7], X[8], X[9], \
319 X[10],X[11],X[12],X[13],X[14],X[15],X[16],X[17],X[18],X[19]);
320
321 PRINT_SHA1(" given: ", depSHA1, "\n");
322 PRINT_SHA1(" cached: ", depCachedSHA1, "\n");
323
324#undef PRINT_SHA1
325
326 return false;
327 }
328
329 if (depType != depCachedType) {
330 LOGE("Cache dependency %s resource type mismatch.\n", depCachedName);
331 return false;
332 }
333 }
334
335 return true;
336}
337
338bool MCCacheReader::readExportVarList() {
339 CACHE_READER_READ_SECTION(OBCC_ExportVarList,
340 mpResult->mpExportVars, export_var_list);
341 return true;
342}
343
344
345bool MCCacheReader::readExportFuncList() {
346 CACHE_READER_READ_SECTION(OBCC_ExportFuncList,
347 mpResult->mpExportFuncs, export_func_list);
348 return true;
349}
350
351
352bool MCCacheReader::readPragmaList() {
353 CACHE_READER_READ_SECTION(OBCC_PragmaList, mpPragmaList, pragma_list);
354
355 vector<char const *> const &strPool = mpResult->mStringPool;
356 ScriptCached::PragmaList &pragmas = mpResult->mPragmas;
357
358 for (size_t i = 0; i < pragma_list_raw->count; ++i) {
359 OBCC_Pragma *pragma = &pragma_list_raw->list[i];
360 pragmas.push_back(make_pair(strPool[pragma->key_strp_index],
361 strPool[pragma->value_strp_index]));
362 }
363
364 return true;
365}
366
367
368bool MCCacheReader::readObjectSlotList() {
369 CACHE_READER_READ_SECTION(OBCC_ObjectSlotList,
370 mpResult->mpObjectSlotList, object_slot_list);
371 return true;
372}
373
374void *MCCacheReader::resolveSymbolAdapter(void *context, char const *name) {
375 MCCacheReader *self = reinterpret_cast<MCCacheReader *>(context);
376
377 if (void *Addr = FindRuntimeFunction(name)) {
378 return Addr;
379 }
380
381 if (self->mpSymbolLookupFn) {
382 if (void *Addr = self->mpSymbolLookupFn(self->mpSymbolLookupContext, name)) {
383 return Addr;
384 }
385 }
386
387 LOGE("Unable to resolve symbol: %s\n", name);
388 return NULL;
389}
390
391bool MCCacheReader::readObjFile() {
392 llvm::SmallVector<char, 1024> mEmittedELFExecutable;
393 char readBuffer[1024];
394 int readSize;
395 while ((readSize = mObjFile->read(readBuffer, 1024)) > 0) {
396 mEmittedELFExecutable.append(readBuffer, readBuffer + readSize);
397 }
398 if (readSize != 0) {
399 LOGE("Read file Error");
400 return false;
401 }
402 LOGD("Read object file size %d", mEmittedELFExecutable.size());
403 mpResult->mRSExecutable =
404 rsloaderCreateExec((unsigned char *)&*mEmittedELFExecutable.begin(),
405 mEmittedELFExecutable.size(),
406 &resolveSymbolAdapter, this);
407 return true;
408}
409
410bool MCCacheReader::readFuncTable() {
411 CACHE_READER_READ_SECTION(OBCC_FuncTable, mpFuncTable, func_table);
412
413 vector<char const *> &strPool = mpResult->mStringPool;
414 ScriptCached::FuncTable &table = mpResult->mFunctions;
415 for (size_t i = 0; i < func_table_raw->count; ++i) {
416 OBCC_FuncInfo *func = &func_table_raw->table[i];
417 table.insert(make_pair(strPool[func->name_strp_index],
418 make_pair(func->cached_addr, func->size)));
419 }
420
421 return true;
422}
423
424#undef CACHE_READER_READ_SECTION
425
426bool MCCacheReader::readRelocationTable() {
427 // TODO(logan): Not finished.
428 return true;
429}
430
431
432bool MCCacheReader::relocate() {
433 void *rootPtr = rsloaderGetSymbolAddress(mpResult->mRSExecutable, "root");
434 int mRootOffset = reinterpret_cast<char *>(rootPtr) -
435 reinterpret_cast<char *>(mpHeader->root_base_addr);
436 for (size_t i = 0; i < mpResult->getExportVarCount(); ++i) {
437 mpResult->mpExportVars->cached_addr_list[i] =
438 reinterpret_cast<void *>(reinterpret_cast<char *>(mpResult->mpExportVars->cached_addr_list[i]) + mRootOffset);
439 }
440 for (size_t i = 0; i < mpResult->getExportFuncCount(); ++i) {
441 mpResult->mpExportFuncs->cached_addr_list[i] =
442 reinterpret_cast<void *>(reinterpret_cast<char *>(mpResult->mpExportFuncs->cached_addr_list[i]) + mRootOffset);
443 }
444 return true;
445}
446
447
448} // namespace bcc
449#endif