blob: ddb02586ba589b70ddc8933f0574fde8b775abc0 [file] [log] [blame]
Loganf7f0ac52011-01-07 03:53:43 +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 "CacheReader.h"
21
22#include "ContextManager.h"
23#include "FileHandle.h"
24#include "ScriptCached.h"
25
26#include <bcc/bcc_cache.h>
27
28#include <llvm/ADT/OwningPtr.h>
29
30#include <errno.h>
31#include <sys/stat.h>
32#include <sys/types.h>
33
34#include <utility>
35#include <vector>
36
37#include <new>
38
Logan856ceb22011-01-07 05:21:26 +080039#include <stdlib.h>
Loganf7f0ac52011-01-07 03:53:43 +080040#include <string.h>
41
42using namespace std;
43
44
45namespace bcc {
46
Logan856ceb22011-01-07 05:21:26 +080047CacheReader::~CacheReader() {
48 if (mpHeader) { free(mpHeader); }
49 if (mpCachedDependTable) { free(mpCachedDependTable); }
50 if (mpPragmaList) { free(mpPragmaList); }
51 if (mpFuncTable) { free(mpFuncTable); }
52}
53
Logane7eb7732011-01-07 07:11:56 +080054ScriptCached *CacheReader::readCacheFile(FileHandle *file, Script *S) {
Loganf7f0ac52011-01-07 03:53:43 +080055 // Check file handle
56 if (!file || file->getFD() < 0) {
57 return NULL;
58 }
59
60 // Allocate ScriptCached object
Logane7eb7732011-01-07 07:11:56 +080061 mpResult.reset(new (nothrow) ScriptCached(S));
Loganf7f0ac52011-01-07 03:53:43 +080062
Logan856ceb22011-01-07 05:21:26 +080063 if (!mpResult) {
Loganf7f0ac52011-01-07 03:53:43 +080064 LOGE("Unable to allocate ScriptCached object.\n");
65 return NULL;
66 }
67
68 bool result = checkFileSize()
69 && readHeader()
70 && checkHeader()
71 && checkMachineIntType()
72 && checkSectionOffsetAndSize()
73 && readStringPool()
74 && checkStringPool()
75 && readDependencyTable()
76 && checkDependency()
77 && readExportVarList()
78 && readExportFuncList()
79 && readPragmaList()
80 && readFuncTable()
81 && readContext()
82 && checkContext()
83 //&& readRelocationTable()
84 //&& relocate()
85 ;
86
Logan856ceb22011-01-07 05:21:26 +080087 return result ? mpResult.take() : NULL;
Loganf7f0ac52011-01-07 03:53:43 +080088}
89
90
91bool CacheReader::checkFileSize() {
92 struct stat stfile;
93 if (fstat(mFile->getFD(), &stfile) < 0) {
94 LOGE("Unable to stat cache file.\n");
95 return false;
96 }
97
98 mFileSize = stfile.st_size;
99
100 if (mFileSize < (off_t)sizeof(OBCC_Header) ||
101 mFileSize < (off_t)BCC_CONTEXT_SIZE) {
102 LOGE("Cache file is too small to be correct.\n");
103 return false;
104 }
105
Loganf3c83ce2011-01-07 06:36:33 +0800106 // Dirty hack for libRS.
107 // TODO(all): This should be removed in the future.
108 if (mpHeader->libRS_threadable) {
109 mpResult->mLibRSThreadable = true;
110 }
111
Loganf7f0ac52011-01-07 03:53:43 +0800112 return true;
113}
114
115
116bool CacheReader::readHeader() {
117 if (mFile->seek(0, SEEK_SET) != 0) {
118 LOGE("Unable to seek to 0. (reason: %s)\n", strerror(errno));
119 return false;
120 }
121
Logan856ceb22011-01-07 05:21:26 +0800122 mpHeader = (OBCC_Header *)malloc(sizeof(OBCC_Header));
123 if (!mpHeader) {
Loganf7f0ac52011-01-07 03:53:43 +0800124 LOGE("Unable to allocate for cache header.\n");
125 return false;
126 }
127
Logan856ceb22011-01-07 05:21:26 +0800128 if (mFile->read(reinterpret_cast<char *>(mpHeader), sizeof(OBCC_Header)) !=
Loganf7f0ac52011-01-07 03:53:43 +0800129 (ssize_t)sizeof(OBCC_Header)) {
130 LOGE("Unable to read cache header.\n");
131 return false;
132 }
133
134 return true;
135}
136
137
138bool CacheReader::checkHeader() {
Logan856ceb22011-01-07 05:21:26 +0800139 if (memcmp(mpHeader->magic, OBCC_MAGIC, 4) != 0) {
Loganf7f0ac52011-01-07 03:53:43 +0800140 LOGE("Bad magic word\n");
141 return false;
142 }
143
Logan856ceb22011-01-07 05:21:26 +0800144 if (memcmp(mpHeader->version, OBCC_VERSION, 4) != 0) {
Loganf7f0ac52011-01-07 03:53:43 +0800145 LOGE("Bad oBCC version 0x%08x\n",
Logan856ceb22011-01-07 05:21:26 +0800146 *reinterpret_cast<uint32_t *>(mpHeader->version));
Loganf7f0ac52011-01-07 03:53:43 +0800147 return false;
148 }
149
150 return true;
151}
152
153
154bool CacheReader::checkMachineIntType() {
155 uint32_t number = 0x00000001;
156
157 bool isLittleEndian = (*reinterpret_cast<char *>(&number) == 1);
Logan856ceb22011-01-07 05:21:26 +0800158 if ((isLittleEndian && mpHeader->endianness != 'e') ||
159 (!isLittleEndian && mpHeader->endianness != 'E')) {
Loganf7f0ac52011-01-07 03:53:43 +0800160 LOGE("Machine endianness mismatch.\n");
161 return false;
162 }
163
Logan856ceb22011-01-07 05:21:26 +0800164 if ((unsigned int)mpHeader->sizeof_off_t != sizeof(off_t) ||
165 (unsigned int)mpHeader->sizeof_size_t != sizeof(size_t) ||
166 (unsigned int)mpHeader->sizeof_ptr_t != sizeof(void *)) {
Loganf7f0ac52011-01-07 03:53:43 +0800167 LOGE("Machine integer size mismatch.\n");
168 return false;
169 }
170
171 return true;
172}
173
174
175bool CacheReader::checkSectionOffsetAndSize() {
176#define CHECK_SECTION_OFFSET(NAME) \
177 do { \
Logan856ceb22011-01-07 05:21:26 +0800178 off_t offset = mpHeader-> NAME##_offset; \
179 off_t size = (off_t)mpHeader-> NAME##_size; \
Loganf7f0ac52011-01-07 03:53:43 +0800180 \
181 if (mFileSize < offset || mFileSize < offset + size) { \
182 LOGE(#NAME " section overflow.\n"); \
183 return false; \
184 } \
185 \
186 if (offset % sizeof(int) != 0) { \
187 LOGE(#NAME " offset must aligned to %d.\n", sizeof(int)); \
188 return false; \
189 } \
190 \
191 if (size < static_cast<off_t>(sizeof(size_t))) { \
192 LOGE(#NAME " size is too small to be correct.\n"); \
193 return false; \
194 } \
195 } while (0)
196
197 CHECK_SECTION_OFFSET(str_pool);
198 CHECK_SECTION_OFFSET(depend_tab);
199 CHECK_SECTION_OFFSET(reloc_tab);
200 CHECK_SECTION_OFFSET(export_var_list);
201 CHECK_SECTION_OFFSET(export_func_list);
202 CHECK_SECTION_OFFSET(pragma_list);
203
204#undef CHECK_SECTION_OFFSET
205
Logan856ceb22011-01-07 05:21:26 +0800206 if (mFileSize < mpHeader->context_offset ||
207 mFileSize < mpHeader->context_offset + BCC_CONTEXT_SIZE) {
Loganf7f0ac52011-01-07 03:53:43 +0800208 LOGE("context section overflow.\n");
209 return false;
210 }
211
212 long pagesize = sysconf(_SC_PAGESIZE);
Logan856ceb22011-01-07 05:21:26 +0800213 if (mpHeader->context_offset % pagesize != 0) {
Loganf7f0ac52011-01-07 03:53:43 +0800214 LOGE("context offset must aligned to pagesize.\n");
215 return false;
216 }
217
218 // TODO(logan): Move this to some where else.
Logan856ceb22011-01-07 05:21:26 +0800219 if ((uintptr_t)mpHeader->context_cached_addr % pagesize != 0) {
Loganf7f0ac52011-01-07 03:53:43 +0800220 LOGE("cached address is not aligned to pagesize.\n");
221 return false;
222 }
223
224 return true;
225}
226
227
Logan856ceb22011-01-07 05:21:26 +0800228#define CACHE_READER_READ_SECTION(TYPE, AUTO_MANAGED_HOLDER, NAME) \
229 TYPE *NAME##_raw = (TYPE *)malloc(mpHeader->NAME##_size); \
230 \
231 if (!NAME##_raw) { \
232 LOGE("Unable to allocate for " #NAME "\n"); \
233 return false; \
234 } \
235 \
236 /* We have to ensure that some one will deallocate NAME##_raw */ \
237 AUTO_MANAGED_HOLDER = NAME##_raw; \
238 \
239 if (mFile->seek(mpHeader->NAME##_offset, SEEK_SET) == -1) { \
240 LOGE("Unable to seek to " #NAME " section\n"); \
241 return false; \
242 } \
243 \
244 if (mFile->read(reinterpret_cast<char *>(NAME##_raw), \
245 mpHeader->NAME##_size) != (ssize_t)mpHeader->NAME##_size) \
246 { \
247 LOGE("Unable to read " #NAME ".\n"); \
248 return false; \
249 }
250
251
Loganf7f0ac52011-01-07 03:53:43 +0800252bool CacheReader::readStringPool() {
Logan856ceb22011-01-07 05:21:26 +0800253 CACHE_READER_READ_SECTION(OBCC_StringPool,
254 mpResult->mpStringPoolRaw, str_pool);
Loganf7f0ac52011-01-07 03:53:43 +0800255
Logan856ceb22011-01-07 05:21:26 +0800256 char *str_base = reinterpret_cast<char *>(str_pool_raw);
Loganf7f0ac52011-01-07 03:53:43 +0800257
Logan856ceb22011-01-07 05:21:26 +0800258 vector<char const *> &pool = mpResult->mStringPool;
259 for (size_t i = 0; i < str_pool_raw->count; ++i) {
260 char *str = str_base + str_pool_raw->list[i].offset;
Loganf7f0ac52011-01-07 03:53:43 +0800261 pool.push_back(str);
262 }
263
264 return true;
265}
266
267
268bool CacheReader::checkStringPool() {
Logan856ceb22011-01-07 05:21:26 +0800269 OBCC_StringPool *poolR = mpResult->mpStringPoolRaw;
270 vector<char const *> &pool = mpResult->mStringPool;
Loganf7f0ac52011-01-07 03:53:43 +0800271
272 // Ensure that every c-style string is ended with '\0'
273 for (size_t i = 0; i < poolR->count; ++i) {
274 if (pool[i][poolR->list[i].length] != '\0') {
275 LOGE("The %lu-th string does not end with '\\0'.\n", (unsigned long)i);
276 return false;
277 }
278 }
279
280 return true;
281}
282
283
284bool CacheReader::readDependencyTable() {
Logan856ceb22011-01-07 05:21:26 +0800285 CACHE_READER_READ_SECTION(OBCC_DependencyTable, mpCachedDependTable,
286 depend_tab);
Loganf7f0ac52011-01-07 03:53:43 +0800287 return true;
288}
289
290
291bool CacheReader::checkDependency() {
Logan856ceb22011-01-07 05:21:26 +0800292 if (mDependencies.size() != mpCachedDependTable->count) {
293 LOGE("Dependencies count mismatch. (%lu vs %lu)\n",
294 (unsigned long)mDependencies.size(),
295 (unsigned long)mpCachedDependTable->count);
296 return false;
297 }
298
299 vector<char const *> &strPool = mpResult->mStringPool;
Logan75cc8a52011-01-07 06:06:52 +0800300 map<string, pair<uint32_t, unsigned char const *> >::iterator dep;
Logan856ceb22011-01-07 05:21:26 +0800301
302 dep = mDependencies.begin();
303 for (size_t i = 0; i < mpCachedDependTable->count; ++i, ++dep) {
304 string const &depName = dep->first;
Logan856ceb22011-01-07 05:21:26 +0800305 uint32_t depType = dep->second.first;
Logan75cc8a52011-01-07 06:06:52 +0800306 unsigned char const *depSHA1 = dep->second.second;
Logan856ceb22011-01-07 05:21:26 +0800307
308 OBCC_Dependency *depCached =&mpCachedDependTable->table[i];
309 char const *depCachedName = strPool[depCached->res_name_strp_index];
Logan856ceb22011-01-07 05:21:26 +0800310 uint32_t depCachedType = depCached->res_type;
Logan75cc8a52011-01-07 06:06:52 +0800311 unsigned char const *depCachedSHA1 = depCached->sha1;
Logan856ceb22011-01-07 05:21:26 +0800312
313 if (depName != depCachedName) {
314 LOGE("Cache dependency name mismatch:\n");
315 LOGE(" given: %s\n", depName.c_str());
316 LOGE(" cached: %s\n", depCachedName);
317
318 return false;
319 }
320
321 if (memcmp(depSHA1, depCachedSHA1, 20) != 0) {
322 LOGE("Cache dependency %s sha1 mismatch:\n", depCachedName);
323
324#define PRINT_SHA1(PREFIX, X, POSTFIX) \
325 LOGE(PREFIX "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" \
326 "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" POSTFIX, \
327 X[0], X[1], X[2], X[3], X[4], X[5], X[6], X[7], X[8], X[9], \
328 X[10],X[11],X[12],X[13],X[14],X[15],X[16],X[17],X[18],X[19]);
329
330 PRINT_SHA1(" given: ", depSHA1, "\n");
331 PRINT_SHA1(" cached: ", depCachedSHA1, "\n");
332
333#undef PRINT_SHA1
334
335 return false;
336 }
337
338 if (depType != depCachedType) {
339 LOGE("Cache dependency %s resource type mismatch.\n", depCachedName);
340 return false;
341 }
342 }
343
Loganf7f0ac52011-01-07 03:53:43 +0800344 return true;
345}
346
347bool CacheReader::readExportVarList() {
Logan856ceb22011-01-07 05:21:26 +0800348 CACHE_READER_READ_SECTION(OBCC_ExportVarList,
349 mpResult->mpExportVars, export_var_list);
Loganf7f0ac52011-01-07 03:53:43 +0800350 return true;
351}
352
353
354bool CacheReader::readExportFuncList() {
Logan856ceb22011-01-07 05:21:26 +0800355 CACHE_READER_READ_SECTION(OBCC_ExportFuncList,
356 mpResult->mpExportFuncs, export_func_list);
Loganf7f0ac52011-01-07 03:53:43 +0800357 return true;
358}
359
360
361bool CacheReader::readPragmaList() {
Logan856ceb22011-01-07 05:21:26 +0800362 CACHE_READER_READ_SECTION(OBCC_PragmaList, mpPragmaList, pragma_list);
Loganf7f0ac52011-01-07 03:53:43 +0800363
Logan856ceb22011-01-07 05:21:26 +0800364 vector<char const *> const &strPool = mpResult->mStringPool;
365 ScriptCached::PragmaList &pragmas = mpResult->mPragmas;
Loganf7f0ac52011-01-07 03:53:43 +0800366
Logan856ceb22011-01-07 05:21:26 +0800367 for (size_t i = 0; i < pragma_list_raw->count; ++i) {
368 OBCC_Pragma *pragma = &pragma_list_raw->list[i];
Loganf7f0ac52011-01-07 03:53:43 +0800369 pragmas.push_back(make_pair(strPool[pragma->key_strp_index],
370 strPool[pragma->value_strp_index]));
371 }
372
373 return true;
374}
375
376
377bool CacheReader::readFuncTable() {
Logan856ceb22011-01-07 05:21:26 +0800378 CACHE_READER_READ_SECTION(OBCC_FuncTable, mpFuncTable, func_table);
379
380 vector<char const *> &strPool = mpResult->mStringPool;
381 ScriptCached::FuncTable &table = mpResult->mFunctions;
382 for (size_t i = 0; i < func_table_raw->count; ++i) {
383 OBCC_FuncInfo *func = &func_table_raw->table[i];
384 table.insert(make_pair(strPool[func->name_strp_index],
385 make_pair(func->cached_addr, func->size)));
386 }
387
388 return true;
Loganf7f0ac52011-01-07 03:53:43 +0800389}
390
Logan856ceb22011-01-07 05:21:26 +0800391#undef CACHE_READER_READ_SECTION
392
Loganf7f0ac52011-01-07 03:53:43 +0800393
394bool CacheReader::readContext() {
Logan856ceb22011-01-07 05:21:26 +0800395 mpResult->mContext = allocateContext(mpHeader->context_cached_addr,
Loganf7f0ac52011-01-07 03:53:43 +0800396 mFile->getFD(),
Logan856ceb22011-01-07 05:21:26 +0800397 mpHeader->context_offset);
Loganf7f0ac52011-01-07 03:53:43 +0800398
Logan856ceb22011-01-07 05:21:26 +0800399 if (!mpResult->mContext) {
Loganf7f0ac52011-01-07 03:53:43 +0800400 // Unable to allocate at cached address. Give up.
401 return false;
402
403 // TODO(logan): If relocation is fixed, we should try to allocate the
404 // code in different location, and relocate the context.
405 }
406
407 return true;
408}
409
410
411bool CacheReader::checkContext() {
Logan856ceb22011-01-07 05:21:26 +0800412 uint32_t sum = mpHeader->context_parity_checksum;
413 uint32_t *ptr = reinterpret_cast<uint32_t *>(mpResult->mContext);
Loganf7f0ac52011-01-07 03:53:43 +0800414
415 for (size_t i = 0; i < BCC_CONTEXT_SIZE / sizeof(uint32_t); ++i) {
416 sum ^= *ptr++;
417 }
418
419 if (sum != 0) {
420 LOGE("Checksum check failed\n");
421 return false;
422 }
423
424 LOGI("Passed checksum even parity verification.\n");
425 return true;
426}
427
428
429bool CacheReader::readRelocationTable() {
430 // TODO(logan): Not finished.
431 return true;
432}
433
434
435bool CacheReader::relocate() {
436 // TODO(logan): Not finished.
437 return true;
438}
439
440
441} // namespace bcc