Home | History | Annotate | Download | only in ExecutionEngine
      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 
     40 using namespace std;
     41 
     42 
     43 #if USE_MCJIT
     44 namespace bcc {
     45 
     46 MCCacheReader::~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 
     54 ScriptCached *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 
     69 bool 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 
    103 bool 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 
    121 bool 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 
    149 bool 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 
    165 bool 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 
    186 bool 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 
    243 bool 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 
    259 bool 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 
    275 bool MCCacheReader::readDependencyTable() {
    276   CACHE_READER_READ_SECTION(OBCC_DependencyTable, mpCachedDependTable,
    277                             depend_tab);
    278   return true;
    279 }
    280 
    281 
    282 bool 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 
    338 bool 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 
    362 bool 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 
    386 bool 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 
    402 bool MCCacheReader::readObjectSlotList() {
    403   CACHE_READER_READ_SECTION(OBCC_ObjectSlotList,
    404                             mpResult->mpObjectSlotList, object_slot_list);
    405   return true;
    406 }
    407 
    408 void *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 
    426 bool 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 
    447 bool MCCacheReader::readRelocationTable() {
    448   // TODO(logan): Not finished.
    449   return true;
    450 }
    451 
    452 
    453 bool MCCacheReader::relocate() {
    454   return true;
    455 }
    456 
    457 } // namespace bcc
    458 #endif
    459