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