1/*
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 "DebugHelper.h"
20#include "FileHandle.h"
21#include "ScriptCached.h"
22#include "Runtime.h"
23
24#include <bcc/bcc_mccache.h>
25
26#include <llvm/ADT/OwningPtr.h>
27
28#include <errno.h>
29#include <sys/stat.h>
30#include <sys/types.h>
31
32#include <utility>
33#include <vector>
34
35#include <new>
36
37#include <stdlib.h>
38#include <string.h>
39
40using namespace std;
41
42
43#if USE_MCJIT
44namespace bcc {
45
46MCCacheReader::~MCCacheReader() {
47  if (mpHeader) { free(mpHeader); }
48  if (mpCachedDependTable) { free(mpCachedDependTable); }
49  if (mpPragmaList) { free(mpPragmaList); }
50  if (mpVarNameList) { free(mpVarNameList); }
51  if (mpFuncNameList) { free(mpFuncNameList); }
52}
53
54ScriptCached *MCCacheReader::readCacheFile(FileHandle *objFile,
55                                           FileHandle *infoFile,
56                                           Script *S) {
57  bool result = checkCacheFile(objFile, infoFile, S)
58             && readPragmaList()
59             && readObjectSlotList()
60             && readObjFile()
61             && readVarNameList()
62             && readFuncNameList()
63             //&& relocate()
64             ;
65
66  return result ? mpResult.take() : NULL;
67}
68
69bool MCCacheReader::checkCacheFile(FileHandle *objFile,
70                                            FileHandle *infoFile,
71                                            Script *S) {
72  // Check file handle
73  if (!objFile || objFile->getFD() < 0 || !infoFile || infoFile->getFD() < 0) {
74    return false;
75  }
76
77  mObjFile = objFile;
78  mInfoFile = infoFile;
79
80  // Allocate ScriptCached object
81  mpResult.reset(new (nothrow) ScriptCached(S));
82
83  if (!mpResult) {
84    LOGE("Unable to allocate ScriptCached object.\n");
85    return false;
86  }
87
88  bool result = checkFileSize()
89             && readHeader()
90             && checkHeader()
91             && checkMachineIntType()
92             && checkSectionOffsetAndSize()
93             && readStringPool()
94             && checkStringPool()
95             && readDependencyTable()
96             && checkDependency()
97             ;
98
99  return result;
100}
101
102
103bool MCCacheReader::checkFileSize() {
104  struct stat stfile;
105  if (fstat(mInfoFile->getFD(), &stfile) < 0) {
106    LOGE("Unable to stat cache file.\n");
107    return false;
108  }
109
110  mInfoFileSize = stfile.st_size;
111
112  if (mInfoFileSize < (off_t)sizeof(MCO_Header)) {
113    LOGE("Cache file is too small to be correct.\n");
114    return false;
115  }
116
117  return true;
118}
119
120
121bool MCCacheReader::readHeader() {
122  if (mInfoFile->seek(0, SEEK_SET) != 0) {
123    LOGE("Unable to seek to 0. (reason: %s)\n", strerror(errno));
124    return false;
125  }
126
127  mpHeader = (MCO_Header *)malloc(sizeof(MCO_Header));
128  if (!mpHeader) {
129    LOGE("Unable to allocate for cache header.\n");
130    return false;
131  }
132
133  if (mInfoFile->read(reinterpret_cast<char *>(mpHeader), sizeof(MCO_Header)) !=
134      (ssize_t)sizeof(MCO_Header)) {
135    LOGE("Unable to read cache header.\n");
136    return false;
137  }
138
139  // Dirty hack for libRS.
140  // TODO(all): This should be removed in the future.
141  if (mpHeader->libRS_threadable) {
142    mpResult->mLibRSThreadable = true;
143  }
144
145  return true;
146}
147
148
149bool MCCacheReader::checkHeader() {
150  if (memcmp(mpHeader->magic, OBCC_MAGIC, 4) != 0) {
151    LOGE("Bad magic word\n");
152    return false;
153  }
154
155  if (memcmp(mpHeader->version, OBCC_VERSION, 4) != 0) {
156    mpHeader->version[4 - 1] = '\0'; // ensure c-style string terminated
157    LOGI("Cache file format version mismatch: now %s cached %s\n",
158         OBCC_VERSION, mpHeader->version);
159    return false;
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(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::readVarNameList() {
339  CACHE_READER_READ_SECTION(OBCC_String_Ptr, mpVarNameList, export_var_name_list);
340  vector<char const *> const &strPool = mpResult->mStringPool;
341
342  mpResult->mpExportVars = (OBCC_ExportVarList*)
343                            malloc(sizeof(size_t) +
344                                   sizeof(void*) * export_var_name_list_raw->count);
345  if (!mpResult->mpExportVars) {
346    LOGE("Unable to allocate for mpExportVars\n");
347    return false;
348  }
349  mpResult->mpExportVars->count = export_var_name_list_raw->count;
350
351  for (size_t i = 0; i < export_var_name_list_raw->count; ++i) {
352    mpResult->mpExportVars->cached_addr_list[i] =
353      rsloaderGetSymbolAddress(mpResult->mRSExecutable, strPool[export_var_name_list_raw->strp_indexs[i]]);
354#if DEBUG_MCJIT_REFLECT
355    LOGD("Get symbol address: %s -> %p",
356      strPool[export_var_name_list_raw->strp_indexs[i]], mpResult->mpExportVars->cached_addr_list[i]);
357#endif
358  }
359  return true;
360}
361
362bool 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  mpResult->mpExportFuncs = (OBCC_ExportFuncList*)
367                            malloc(sizeof(size_t) +
368                                   sizeof(void*) * export_func_name_list_raw->count);
369  if (!mpResult->mpExportFuncs) {
370    LOGE("Unable to allocate for mpExportFuncs\n");
371    return false;
372  }
373  mpResult->mpExportFuncs->count = export_func_name_list_raw->count;
374
375  for (size_t i = 0; i < export_func_name_list_raw->count; ++i) {
376    mpResult->mpExportFuncs->cached_addr_list[i] =
377      rsloaderGetSymbolAddress(mpResult->mRSExecutable, strPool[export_func_name_list_raw->strp_indexs[i]]);
378#if DEBUG_MCJIT_REFLECT
379    LOGD("Get function address: %s -> %p",
380      strPool[export_func_name_list_raw->strp_indexs[i]], mpResult->mpExportFuncs->cached_addr_list[i]);
381#endif
382  }
383  return true;
384}
385
386bool MCCacheReader::readPragmaList() {
387  CACHE_READER_READ_SECTION(OBCC_PragmaList, mpPragmaList, pragma_list);
388
389  vector<char const *> const &strPool = mpResult->mStringPool;
390  ScriptCached::PragmaList &pragmas = mpResult->mPragmas;
391
392  for (size_t i = 0; i < pragma_list_raw->count; ++i) {
393    OBCC_Pragma *pragma = &pragma_list_raw->list[i];
394    pragmas.push_back(make_pair(strPool[pragma->key_strp_index],
395                                strPool[pragma->value_strp_index]));
396  }
397
398  return true;
399}
400
401
402bool MCCacheReader::readObjectSlotList() {
403  CACHE_READER_READ_SECTION(OBCC_ObjectSlotList,
404                            mpResult->mpObjectSlotList, object_slot_list);
405  return true;
406}
407
408void *MCCacheReader::resolveSymbolAdapter(void *context, char const *name) {
409  MCCacheReader *self = reinterpret_cast<MCCacheReader *>(context);
410
411  if (void *Addr = FindRuntimeFunction(name)) {
412    return Addr;
413  }
414
415  if (self->mpSymbolLookupFn) {
416    if (void *Addr =
417        self->mpSymbolLookupFn(self->mpSymbolLookupContext, name)) {
418      return Addr;
419    }
420  }
421
422  LOGE("Unable to resolve symbol: %s\n", name);
423  return NULL;
424}
425
426bool MCCacheReader::readObjFile() {
427  llvm::SmallVector<char, 1024> mEmittedELFExecutable;
428  char readBuffer[1024];
429  int readSize;
430  while ((readSize = mObjFile->read(readBuffer, 1024)) > 0) {
431    mEmittedELFExecutable.append(readBuffer, readBuffer + readSize);
432  }
433  if (readSize != 0) {
434    LOGE("Read file Error");
435    return false;
436  }
437  LOGD("Read object file size %d", (int)mEmittedELFExecutable.size());
438  mpResult->mRSExecutable =
439  rsloaderCreateExec((unsigned char *)&*mEmittedELFExecutable.begin(),
440                     mEmittedELFExecutable.size(),
441                     &resolveSymbolAdapter, this);
442  return true;
443}
444
445#undef CACHE_READER_READ_SECTION
446
447bool MCCacheReader::readRelocationTable() {
448  // TODO(logan): Not finished.
449  return true;
450}
451
452
453bool MCCacheReader::relocate() {
454  return true;
455}
456
457} // namespace bcc
458#endif
459