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