Home | History | Annotate | Download | only in OldJIT
      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 "CacheReader.h"
     18 
     19 #include "ContextManager.h"
     20 #include "DebugHelper.h"
     21 #include "FileHandle.h"
     22 #include "ScriptCached.h"
     23 
     24 #include <bcc/bcc_cache.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 namespace bcc {
     44 
     45 CacheReader::~CacheReader() {
     46   if (mpHeader) { free(mpHeader); }
     47   if (mpCachedDependTable) { free(mpCachedDependTable); }
     48   if (mpPragmaList) { free(mpPragmaList); }
     49   if (mpFuncTable) { free(mpFuncTable); }
     50 }
     51 
     52 ScriptCached *CacheReader::readCacheFile(FileHandle *objFile,
     53                                          FileHandle *infoFile,
     54                                          Script *S) {
     55   // Check file handle
     56   if (!objFile || objFile->getFD() < 0 ||
     57       !infoFile || infoFile->getFD() < 0) {
     58     return NULL;
     59   }
     60 
     61   mObjFile = objFile;
     62   mInfoFile = infoFile;
     63 
     64   // Allocate ScriptCached object
     65   mpResult.reset(new (nothrow) ScriptCached(S));
     66 
     67   if (!mpResult) {
     68     LOGE("Unable to allocate ScriptCached object.\n");
     69     return NULL;
     70   }
     71 
     72   bool result = checkFileSize()
     73              && readHeader()
     74              && checkHeader()
     75              && checkMachineIntType()
     76              && checkSectionOffsetAndSize()
     77              && readStringPool()
     78              && checkStringPool()
     79              && readDependencyTable()
     80              && checkDependency()
     81              && readExportVarList()
     82              && readExportFuncList()
     83              && readPragmaList()
     84              && readFuncTable()
     85              && readObjectSlotList()
     86              && readContext()
     87              && checkContext()
     88              //&& readRelocationTable()
     89              //&& relocate()
     90              ;
     91 
     92   return result ? mpResult.take() : NULL;
     93 }
     94 
     95 
     96 bool CacheReader::checkFileSize() {
     97   struct stat stfile;
     98 
     99   if (fstat(mInfoFile->getFD(), &stfile) < 0) {
    100     LOGE("Unable to stat metadata information file.\n");
    101     return false;
    102   }
    103 
    104   mInfoFileSize = stfile.st_size;
    105 
    106   if (mInfoFileSize < (off_t)sizeof(OBCC_Header)) {
    107     LOGE("Metadata information file is too small to be correct.\n");
    108     return false;
    109   }
    110 
    111   if (fstat(mObjFile->getFD(), &stfile) < 0) {
    112     LOGE("Unable to stat executable file.\n");
    113     return false;
    114   }
    115 
    116   if (stfile.st_size < (off_t)ContextManager::ContextSize) {
    117     LOGE("Executable file is too small to be correct.\n");
    118     return false;
    119   }
    120 
    121   return true;
    122 }
    123 
    124 
    125 bool CacheReader::readHeader() {
    126   if (mInfoFile->seek(0, SEEK_SET) != 0) {
    127     LOGE("Unable to seek to 0. (reason: %s)\n", strerror(errno));
    128     return false;
    129   }
    130 
    131   mpHeader = (OBCC_Header *)malloc(sizeof(OBCC_Header));
    132   if (!mpHeader) {
    133     LOGE("Unable to allocate for cache header.\n");
    134     return false;
    135   }
    136 
    137   if (mInfoFile->read((char *)mpHeader, sizeof(OBCC_Header)) !=
    138       (ssize_t)sizeof(OBCC_Header)) {
    139     LOGE("Unable to read cache header.\n");
    140     return false;
    141   }
    142 
    143   // Dirty hack for libRS.
    144   // TODO(all): This should be removed in the future.
    145   if (mpHeader->libRS_threadable) {
    146     mpResult->mLibRSThreadable = true;
    147   }
    148 
    149   return true;
    150 }
    151 
    152 
    153 bool CacheReader::checkHeader() {
    154   if (memcmp(mpHeader->magic, OBCC_MAGIC, 4) != 0) {
    155     LOGE("Bad magic word\n");
    156     return false;
    157   }
    158 
    159   if (memcmp(mpHeader->version, OBCC_VERSION, 4) != 0) {
    160     mpHeader->version[4 - 1] = '\0'; // ensure c-style string terminated
    161     LOGI("Cache file format version mismatch: now %s cached %s\n",
    162          OBCC_VERSION, mpHeader->version);
    163     return false;
    164   }
    165   return true;
    166 }
    167 
    168 
    169 bool CacheReader::checkMachineIntType() {
    170   uint32_t number = 0x00000001;
    171 
    172   bool isLittleEndian = (*reinterpret_cast<char *>(&number) == 1);
    173   if ((isLittleEndian && mpHeader->endianness != 'e') ||
    174       (!isLittleEndian && mpHeader->endianness != 'E')) {
    175     LOGE("Machine endianness mismatch.\n");
    176     return false;
    177   }
    178 
    179   if ((unsigned int)mpHeader->sizeof_off_t != sizeof(off_t) ||
    180       (unsigned int)mpHeader->sizeof_size_t != sizeof(size_t) ||
    181       (unsigned int)mpHeader->sizeof_ptr_t != sizeof(void *)) {
    182     LOGE("Machine integer size mismatch.\n");
    183     return false;
    184   }
    185 
    186   return true;
    187 }
    188 
    189 
    190 bool CacheReader::checkSectionOffsetAndSize() {
    191 #define CHECK_SECTION_OFFSET(NAME)                                          \
    192   do {                                                                      \
    193     off_t offset = mpHeader-> NAME##_offset;                                \
    194     off_t size = (off_t)mpHeader-> NAME##_size;                             \
    195                                                                             \
    196     if (mInfoFileSize < offset || mInfoFileSize < offset + size) {          \
    197       LOGE(#NAME " section overflow.\n");                                   \
    198       return false;                                                         \
    199     }                                                                       \
    200                                                                             \
    201     if (offset % sizeof(int) != 0) {                                        \
    202       LOGE(#NAME " offset must aligned to %d.\n", (int)sizeof(int));        \
    203       return false;                                                         \
    204     }                                                                       \
    205                                                                             \
    206     if (size < static_cast<off_t>(sizeof(size_t))) {                        \
    207       LOGE(#NAME " size is too small to be correct.\n");                    \
    208       return false;                                                         \
    209     }                                                                       \
    210   } while (0)
    211 
    212   CHECK_SECTION_OFFSET(str_pool);
    213   CHECK_SECTION_OFFSET(depend_tab);
    214   //CHECK_SECTION_OFFSET(reloc_tab);
    215   CHECK_SECTION_OFFSET(export_var_list);
    216   CHECK_SECTION_OFFSET(export_func_list);
    217   CHECK_SECTION_OFFSET(pragma_list);
    218 
    219 #undef CHECK_SECTION_OFFSET
    220 
    221   // TODO(logan): Move this to some where else.
    222   long pagesize = sysconf(_SC_PAGESIZE);
    223   if ((uintptr_t)mpHeader->context_cached_addr % pagesize != 0) {
    224     LOGE("cached address is not aligned to pagesize.\n");
    225     return false;
    226   }
    227 
    228   return true;
    229 }
    230 
    231 
    232 #define CACHE_READER_READ_SECTION(TYPE, AUTO_MANAGED_HOLDER, NAME)          \
    233   TYPE *NAME##_raw = (TYPE *)malloc(mpHeader->NAME##_size);                 \
    234                                                                             \
    235   if (!NAME##_raw) {                                                        \
    236     LOGE("Unable to allocate for " #NAME "\n");                             \
    237     return false;                                                           \
    238   }                                                                         \
    239                                                                             \
    240   /* We have to ensure that some one will deallocate NAME##_raw */          \
    241   AUTO_MANAGED_HOLDER = NAME##_raw;                                         \
    242                                                                             \
    243   if (mInfoFile->seek(mpHeader->NAME##_offset, SEEK_SET) == -1) {           \
    244     LOGE("Unable to seek to " #NAME " section\n");                          \
    245     return false;                                                           \
    246   }                                                                         \
    247                                                                             \
    248   if (mInfoFile->read(reinterpret_cast<char *>(NAME##_raw),                 \
    249                   mpHeader->NAME##_size) != (ssize_t)mpHeader->NAME##_size) \
    250   {                                                                         \
    251     LOGE("Unable to read " #NAME ".\n");                                    \
    252     return false;                                                           \
    253   }
    254 
    255 
    256 bool CacheReader::readStringPool() {
    257   CACHE_READER_READ_SECTION(OBCC_StringPool,
    258                             mpResult->mpStringPoolRaw, str_pool);
    259 
    260   char *str_base = reinterpret_cast<char *>(str_pool_raw);
    261 
    262   vector<char const *> &pool = mpResult->mStringPool;
    263   for (size_t i = 0; i < str_pool_raw->count; ++i) {
    264     char *str = str_base + str_pool_raw->list[i].offset;
    265     pool.push_back(str);
    266   }
    267 
    268   return true;
    269 }
    270 
    271 
    272 bool CacheReader::checkStringPool() {
    273   OBCC_StringPool *poolR = mpResult->mpStringPoolRaw;
    274   vector<char const *> &pool = mpResult->mStringPool;
    275 
    276   // Ensure that every c-style string is ended with '\0'
    277   for (size_t i = 0; i < poolR->count; ++i) {
    278     if (pool[i][poolR->list[i].length] != '\0') {
    279       LOGE("The %lu-th string does not end with '\\0'.\n", (unsigned long)i);
    280       return false;
    281     }
    282   }
    283 
    284   return true;
    285 }
    286 
    287 
    288 bool CacheReader::readDependencyTable() {
    289   CACHE_READER_READ_SECTION(OBCC_DependencyTable, mpCachedDependTable,
    290                             depend_tab);
    291   return true;
    292 }
    293 
    294 
    295 bool CacheReader::checkDependency() {
    296   if (mDependencies.size() != mpCachedDependTable->count) {
    297     LOGE("Dependencies count mismatch. (%lu vs %lu)\n",
    298          (unsigned long)mDependencies.size(),
    299          (unsigned long)mpCachedDependTable->count);
    300     return false;
    301   }
    302 
    303   vector<char const *> &strPool = mpResult->mStringPool;
    304   map<string, pair<uint32_t, unsigned char const *> >::iterator dep;
    305 
    306   dep = mDependencies.begin();
    307   for (size_t i = 0; i < mpCachedDependTable->count; ++i, ++dep) {
    308     string const &depName = dep->first;
    309     uint32_t depType = dep->second.first;
    310     unsigned char const *depSHA1 = dep->second.second;
    311 
    312     OBCC_Dependency *depCached =&mpCachedDependTable->table[i];
    313     char const *depCachedName = strPool[depCached->res_name_strp_index];
    314     uint32_t depCachedType = depCached->res_type;
    315     unsigned char const *depCachedSHA1 = depCached->sha1;
    316 
    317     if (depName != depCachedName) {
    318       LOGE("Cache dependency name mismatch:\n");
    319       LOGE("  given:  %s\n", depName.c_str());
    320       LOGE("  cached: %s\n", depCachedName);
    321 
    322       return false;
    323     }
    324 
    325     if (memcmp(depSHA1, depCachedSHA1, 20) != 0) {
    326       LOGE("Cache dependency %s sha1 mismatch:\n", depCachedName);
    327 
    328 #define PRINT_SHA1(PREFIX, X, POSTFIX) \
    329       LOGE(PREFIX "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" \
    330                   "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" POSTFIX, \
    331            X[0], X[1], X[2], X[3], X[4], X[5], X[6], X[7], X[8], X[9], \
    332            X[10],X[11],X[12],X[13],X[14],X[15],X[16],X[17],X[18],X[19]);
    333 
    334       PRINT_SHA1("  given:  ", depSHA1, "\n");
    335       PRINT_SHA1("  cached: ", depCachedSHA1, "\n");
    336 
    337 #undef PRINT_SHA1
    338 
    339       return false;
    340     }
    341 
    342     if (depType != depCachedType) {
    343       LOGE("Cache dependency %s resource type mismatch.\n", depCachedName);
    344       return false;
    345     }
    346   }
    347 
    348   return true;
    349 }
    350 
    351 bool CacheReader::readExportVarList() {
    352   CACHE_READER_READ_SECTION(OBCC_ExportVarList,
    353                             mpResult->mpExportVars, export_var_list);
    354   return true;
    355 }
    356 
    357 
    358 bool CacheReader::readExportFuncList() {
    359   CACHE_READER_READ_SECTION(OBCC_ExportFuncList,
    360                             mpResult->mpExportFuncs, export_func_list);
    361   return true;
    362 }
    363 
    364 
    365 bool CacheReader::readPragmaList() {
    366   CACHE_READER_READ_SECTION(OBCC_PragmaList, mpPragmaList, pragma_list);
    367 
    368   vector<char const *> const &strPool = mpResult->mStringPool;
    369   ScriptCached::PragmaList &pragmas = mpResult->mPragmas;
    370 
    371   for (size_t i = 0; i < pragma_list_raw->count; ++i) {
    372     OBCC_Pragma *pragma = &pragma_list_raw->list[i];
    373     pragmas.push_back(make_pair(strPool[pragma->key_strp_index],
    374                                 strPool[pragma->value_strp_index]));
    375   }
    376 
    377   return true;
    378 }
    379 
    380 
    381 bool CacheReader::readObjectSlotList() {
    382   CACHE_READER_READ_SECTION(OBCC_ObjectSlotList,
    383                             mpResult->mpObjectSlotList, object_slot_list);
    384   return true;
    385 }
    386 
    387 
    388 bool CacheReader::readFuncTable() {
    389   CACHE_READER_READ_SECTION(OBCC_FuncTable, mpFuncTable, func_table);
    390 
    391   vector<char const *> &strPool = mpResult->mStringPool;
    392   ScriptCached::FuncTable &table = mpResult->mFunctions;
    393   for (size_t i = 0; i < func_table_raw->count; ++i) {
    394     OBCC_FuncInfo *func = &func_table_raw->table[i];
    395     table.insert(make_pair(strPool[func->name_strp_index],
    396                            make_pair(func->cached_addr, func->size)));
    397   }
    398 
    399   return true;
    400 }
    401 
    402 #undef CACHE_READER_READ_SECTION
    403 
    404 
    405 bool CacheReader::readContext() {
    406   mpResult->mContext =
    407     ContextManager::get().allocateContext(mpHeader->context_cached_addr,
    408                                           mObjFile->getFD(), 0);
    409 
    410   if (!mpResult->mContext) {
    411     // Unable to allocate at cached address.  Give up.
    412     mIsContextSlotNotAvail = true;
    413     return false;
    414 
    415     // TODO(logan): If relocation is fixed, we should try to allocate the
    416     // code in different location, and relocate the context.
    417   }
    418 
    419   return true;
    420 }
    421 
    422 
    423 bool CacheReader::checkContext() {
    424   uint32_t sum = mpHeader->context_parity_checksum;
    425   uint32_t *ptr = reinterpret_cast<uint32_t *>(mpResult->mContext);
    426 
    427   for (size_t i = 0; i < ContextManager::ContextSize / sizeof(uint32_t); ++i) {
    428     sum ^= *ptr++;
    429   }
    430 
    431   if (sum != 0) {
    432     LOGE("Checksum check failed\n");
    433     return false;
    434   }
    435 
    436   LOGI("Passed checksum even parity verification.\n");
    437   return true;
    438 }
    439 
    440 
    441 bool CacheReader::readRelocationTable() {
    442   // TODO(logan): Not finished.
    443   return true;
    444 }
    445 
    446 
    447 bool CacheReader::relocate() {
    448   // TODO(logan): Not finished.
    449   return true;
    450 }
    451 
    452 
    453 } // namespace bcc
    454