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