blob: 0a97abbde47049b6c8589df4a83fb31c0f955833 [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) {
Doug Kwandeff7392011-07-11 00:48:07 -070060 return NULL;
Shih-wei Liao5e3e0ce2011-06-17 13:59:46 -070061 }
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()
Shih-wei Liao5e3e0ce2011-06-17 13:59:46 -070083 && readPragmaList()
Shih-wei Liao5e3e0ce2011-06-17 13:59:46 -070084 && readObjectSlotList()
85 && readObjFile()
Joseph Wenf36637f2011-07-06 18:27:12 -070086 && readVarNameList()
87 && readFuncNameList()
88 //&& relocate()
Shih-wei Liao5e3e0ce2011-06-17 13:59:46 -070089 ;
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 }
Shih-wei Liao5e3e0ce2011-06-17 13:59:46 -0700153 return true;
154}
155
156
157bool MCCacheReader::checkMachineIntType() {
158 uint32_t number = 0x00000001;
159
160 bool isLittleEndian = (*reinterpret_cast<char *>(&number) == 1);
161 if ((isLittleEndian && mpHeader->endianness != 'e') ||
162 (!isLittleEndian && mpHeader->endianness != 'E')) {
163 LOGE("Machine endianness mismatch.\n");
164 return false;
165 }
166
167 if ((unsigned int)mpHeader->sizeof_off_t != sizeof(off_t) ||
168 (unsigned int)mpHeader->sizeof_size_t != sizeof(size_t) ||
169 (unsigned int)mpHeader->sizeof_ptr_t != sizeof(void *)) {
170 LOGE("Machine integer size mismatch.\n");
171 return false;
172 }
173
174 return true;
175}
176
177
178bool MCCacheReader::checkSectionOffsetAndSize() {
179#define CHECK_SECTION_OFFSET(NAME) \
180 do { \
181 off_t offset = mpHeader-> NAME##_offset; \
182 off_t size = (off_t)mpHeader-> NAME##_size; \
183 \
184 if (mInfoFileSize < offset || mInfoFileSize < offset + size) { \
185 LOGE(#NAME " section overflow.\n"); \
186 return false; \
187 } \
188 \
189 if (offset % sizeof(int) != 0) { \
190 LOGE(#NAME " offset must aligned to %d.\n", (int)sizeof(int)); \
191 return false; \
192 } \
193 \
194 if (size < static_cast<off_t>(sizeof(size_t))) { \
195 LOGE(#NAME " size is too small to be correct.\n"); \
196 return false; \
197 } \
198 } while (0)
199
200 CHECK_SECTION_OFFSET(str_pool);
201 CHECK_SECTION_OFFSET(depend_tab);
202 //CHECK_SECTION_OFFSET(reloc_tab);
Shih-wei Liao5e3e0ce2011-06-17 13:59:46 -0700203 CHECK_SECTION_OFFSET(pragma_list);
204
205#undef CHECK_SECTION_OFFSET
206
207 return true;
208}
209
210
211#define CACHE_READER_READ_SECTION(TYPE, AUTO_MANAGED_HOLDER, NAME) \
212 TYPE *NAME##_raw = (TYPE *)malloc(mpHeader->NAME##_size); \
213 \
214 if (!NAME##_raw) { \
215 LOGE("Unable to allocate for " #NAME "\n"); \
216 return false; \
217 } \
218 \
219 /* We have to ensure that some one will deallocate NAME##_raw */ \
220 AUTO_MANAGED_HOLDER = NAME##_raw; \
221 \
222 if (mInfoFile->seek(mpHeader->NAME##_offset, SEEK_SET) == -1) { \
223 LOGE("Unable to seek to " #NAME " section\n"); \
224 return false; \
225 } \
226 \
227 if (mInfoFile->read(reinterpret_cast<char *>(NAME##_raw), \
228 mpHeader->NAME##_size) != (ssize_t)mpHeader->NAME##_size) \
229 { \
230 LOGE("Unable to read " #NAME ".\n"); \
231 return false; \
232 }
233
234
235bool MCCacheReader::readStringPool() {
236 CACHE_READER_READ_SECTION(OBCC_StringPool,
237 mpResult->mpStringPoolRaw, str_pool);
238
239 char *str_base = reinterpret_cast<char *>(str_pool_raw);
240
241 vector<char const *> &pool = mpResult->mStringPool;
242 for (size_t i = 0; i < str_pool_raw->count; ++i) {
243 char *str = str_base + str_pool_raw->list[i].offset;
244 pool.push_back(str);
245 }
246
247 return true;
248}
249
250
251bool MCCacheReader::checkStringPool() {
252 OBCC_StringPool *poolR = mpResult->mpStringPoolRaw;
253 vector<char const *> &pool = mpResult->mStringPool;
254
255 // Ensure that every c-style string is ended with '\0'
256 for (size_t i = 0; i < poolR->count; ++i) {
257 if (pool[i][poolR->list[i].length] != '\0') {
258 LOGE("The %lu-th string does not end with '\\0'.\n", (unsigned long)i);
259 return false;
260 }
261 }
262
263 return true;
264}
265
266
267bool MCCacheReader::readDependencyTable() {
268 CACHE_READER_READ_SECTION(OBCC_DependencyTable, mpCachedDependTable,
269 depend_tab);
270 return true;
271}
272
273
274bool MCCacheReader::checkDependency() {
275 if (mDependencies.size() != mpCachedDependTable->count) {
276 LOGE("Dependencies count mismatch. (%lu vs %lu)\n",
277 (unsigned long)mDependencies.size(),
278 (unsigned long)mpCachedDependTable->count);
279 return false;
280 }
281
282 vector<char const *> &strPool = mpResult->mStringPool;
283 map<string, pair<uint32_t, unsigned char const *> >::iterator dep;
284
285 dep = mDependencies.begin();
286 for (size_t i = 0; i < mpCachedDependTable->count; ++i, ++dep) {
287 string const &depName = dep->first;
288 uint32_t depType = dep->second.first;
289 unsigned char const *depSHA1 = dep->second.second;
290
291 OBCC_Dependency *depCached =&mpCachedDependTable->table[i];
292 char const *depCachedName = strPool[depCached->res_name_strp_index];
293 uint32_t depCachedType = depCached->res_type;
294 unsigned char const *depCachedSHA1 = depCached->sha1;
295
296 if (depName != depCachedName) {
297 LOGE("Cache dependency name mismatch:\n");
298 LOGE(" given: %s\n", depName.c_str());
299 LOGE(" cached: %s\n", depCachedName);
300
301 return false;
302 }
303
304 if (memcmp(depSHA1, depCachedSHA1, 20) != 0) {
305 LOGE("Cache dependency %s sha1 mismatch:\n", depCachedName);
306
307#define PRINT_SHA1(PREFIX, X, POSTFIX) \
308 LOGE(PREFIX "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" \
309 "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" POSTFIX, \
310 X[0], X[1], X[2], X[3], X[4], X[5], X[6], X[7], X[8], X[9], \
311 X[10],X[11],X[12],X[13],X[14],X[15],X[16],X[17],X[18],X[19]);
312
313 PRINT_SHA1(" given: ", depSHA1, "\n");
314 PRINT_SHA1(" cached: ", depCachedSHA1, "\n");
315
316#undef PRINT_SHA1
317
318 return false;
319 }
320
321 if (depType != depCachedType) {
322 LOGE("Cache dependency %s resource type mismatch.\n", depCachedName);
323 return false;
324 }
325 }
326
327 return true;
328}
329
Joseph Wenf36637f2011-07-06 18:27:12 -0700330bool MCCacheReader::readVarNameList() {
331 CACHE_READER_READ_SECTION(OBCC_String_Ptr, mpVarNameList, export_var_name_list);
332 vector<char const *> const &strPool = mpResult->mStringPool;
333
Joseph Wen8eabcbf2011-07-07 12:37:48 -0700334 mpResult->mpExportVars = (OBCC_ExportVarList*)
335 malloc(sizeof(size_t) +
336 sizeof(void*) * export_var_name_list_raw->count);
337 if (!mpResult->mpExportVars) {
338 LOGE("Unable to allocate for mpExportVars\n");
339 return false;
340 }
341 mpResult->mpExportVars->count = export_var_name_list_raw->count;
342
Joseph Wenf36637f2011-07-06 18:27:12 -0700343 for (size_t i = 0; i < export_var_name_list_raw->count; ++i) {
344 mpResult->mpExportVars->cached_addr_list[i] =
345 rsloaderGetSymbolAddress(mpResult->mRSExecutable, strPool[export_var_name_list_raw->strp_indexs[i]]);
346#if DEBUG_MCJIT_REFLECT
347 LOGD("Get symbol address: %s -> %p",
348 strPool[export_var_name_list_raw->strp_indexs[i]], mpResult->mpExportVars->cached_addr_list[i]);
349#endif
350 }
351 return true;
352}
Shih-wei Liao5e3e0ce2011-06-17 13:59:46 -0700353
Joseph Wenf36637f2011-07-06 18:27:12 -0700354bool MCCacheReader::readFuncNameList() {
355 CACHE_READER_READ_SECTION(OBCC_String_Ptr, mpFuncNameList, export_func_name_list);
356 vector<char const *> const &strPool = mpResult->mStringPool;
357
Joseph Wen8eabcbf2011-07-07 12:37:48 -0700358 mpResult->mpExportFuncs = (OBCC_ExportFuncList*)
359 malloc(sizeof(size_t) +
360 sizeof(void*) * export_func_name_list_raw->count);
361 if (!mpResult->mpExportFuncs) {
362 LOGE("Unable to allocate for mpExportFuncs\n");
363 return false;
364 }
365 mpResult->mpExportFuncs->count = export_func_name_list_raw->count;
366
Joseph Wenf36637f2011-07-06 18:27:12 -0700367 for (size_t i = 0; i < export_func_name_list_raw->count; ++i) {
368 mpResult->mpExportFuncs->cached_addr_list[i] =
369 rsloaderGetSymbolAddress(mpResult->mRSExecutable, strPool[export_func_name_list_raw->strp_indexs[i]]);
370#if DEBUG_MCJIT_REFLECT
371 LOGD("Get function address: %s -> %p",
372 strPool[export_func_name_list_raw->strp_indexs[i]], mpResult->mpExportFuncs->cached_addr_list[i]);
373#endif
374 }
375 return true;
376}
377
Shih-wei Liao5e3e0ce2011-06-17 13:59:46 -0700378bool MCCacheReader::readPragmaList() {
379 CACHE_READER_READ_SECTION(OBCC_PragmaList, mpPragmaList, pragma_list);
380
381 vector<char const *> const &strPool = mpResult->mStringPool;
382 ScriptCached::PragmaList &pragmas = mpResult->mPragmas;
383
384 for (size_t i = 0; i < pragma_list_raw->count; ++i) {
385 OBCC_Pragma *pragma = &pragma_list_raw->list[i];
386 pragmas.push_back(make_pair(strPool[pragma->key_strp_index],
387 strPool[pragma->value_strp_index]));
388 }
389
390 return true;
391}
392
393
394bool MCCacheReader::readObjectSlotList() {
395 CACHE_READER_READ_SECTION(OBCC_ObjectSlotList,
396 mpResult->mpObjectSlotList, object_slot_list);
397 return true;
398}
399
400void *MCCacheReader::resolveSymbolAdapter(void *context, char const *name) {
401 MCCacheReader *self = reinterpret_cast<MCCacheReader *>(context);
402
403 if (void *Addr = FindRuntimeFunction(name)) {
404 return Addr;
405 }
406
407 if (self->mpSymbolLookupFn) {
Shih-wei Liao6d0804b2011-06-19 11:30:00 -0700408 if (void *Addr =
409 self->mpSymbolLookupFn(self->mpSymbolLookupContext, name)) {
Shih-wei Liao5e3e0ce2011-06-17 13:59:46 -0700410 return Addr;
411 }
412 }
413
414 LOGE("Unable to resolve symbol: %s\n", name);
415 return NULL;
416}
417
418bool MCCacheReader::readObjFile() {
419 llvm::SmallVector<char, 1024> mEmittedELFExecutable;
420 char readBuffer[1024];
421 int readSize;
422 while ((readSize = mObjFile->read(readBuffer, 1024)) > 0) {
423 mEmittedELFExecutable.append(readBuffer, readBuffer + readSize);
424 }
425 if (readSize != 0) {
426 LOGE("Read file Error");
427 return false;
428 }
Ying Wanga61d5012011-07-01 15:54:00 -0700429 LOGD("Read object file size %d", (int)mEmittedELFExecutable.size());
Shih-wei Liao5e3e0ce2011-06-17 13:59:46 -0700430 mpResult->mRSExecutable =
431 rsloaderCreateExec((unsigned char *)&*mEmittedELFExecutable.begin(),
432 mEmittedELFExecutable.size(),
433 &resolveSymbolAdapter, this);
434 return true;
435}
436
Shih-wei Liao5e3e0ce2011-06-17 13:59:46 -0700437#undef CACHE_READER_READ_SECTION
438
439bool MCCacheReader::readRelocationTable() {
440 // TODO(logan): Not finished.
441 return true;
442}
443
444
445bool MCCacheReader::relocate() {
Shih-wei Liao5e3e0ce2011-06-17 13:59:46 -0700446 return true;
447}
448
Shih-wei Liao5e3e0ce2011-06-17 13:59:46 -0700449} // namespace bcc
450#endif