1/* 2 * Copyright 2010-2012, 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 42namespace bcc { 43 44MCCacheReader::~MCCacheReader() { 45 if (mpHeader) { free(mpHeader); } 46 if (mpCachedDependTable) { free(mpCachedDependTable); } 47 if (mpPragmaList) { free(mpPragmaList); } 48 if (mpVarNameList) { free(mpVarNameList); } 49 if (mpFuncNameList) { free(mpFuncNameList); } 50} 51 52ScriptCached *MCCacheReader::readCacheFile(FileHandle *objFile, 53 FileHandle *infoFile, 54 Script *S) { 55 bool result = checkCacheFile(objFile, infoFile, S) 56 && readPragmaList() 57 && readObjectSlotList() 58 && readObjFile() 59 && readVarNameList() 60 && readFuncNameList() 61 && readForEachNameList() 62 //&& relocate() 63 ; 64 65 return result ? mpResult.take() : NULL; 66} 67 68bool MCCacheReader::checkCacheFile(FileHandle *objFile, 69 FileHandle *infoFile, 70 Script *S) { 71 // Check file handle 72 if (!objFile || objFile->getFD() < 0 || !infoFile || infoFile->getFD() < 0) { 73 return false; 74 } 75 76 mObjFile = objFile; 77 mInfoFile = infoFile; 78 79 // Allocate ScriptCached object 80 mpResult.reset(new (nothrow) ScriptCached(S)); 81 82 if (!mpResult) { 83 ALOGE("Unable to allocate ScriptCached object.\n"); 84 return false; 85 } 86 87 bool result = checkFileSize() 88 && readHeader() 89 && checkHeader() 90 && checkMachineIntType() 91 && checkSectionOffsetAndSize() 92 && readStringPool() 93 && checkStringPool() 94 && readDependencyTable() 95 && checkDependency() 96 ; 97 98 return result; 99} 100 101 102bool MCCacheReader::checkFileSize() { 103 struct stat stfile; 104 if (fstat(mInfoFile->getFD(), &stfile) < 0) { 105 ALOGE("Unable to stat cache file.\n"); 106 return false; 107 } 108 109 mInfoFileSize = stfile.st_size; 110 111 if (mInfoFileSize < (off_t)sizeof(MCO_Header)) { 112 ALOGE("Cache file is too small to be correct.\n"); 113 return false; 114 } 115 116 return true; 117} 118 119 120bool MCCacheReader::readHeader() { 121 if (mInfoFile->seek(0, SEEK_SET) != 0) { 122 ALOGE("Unable to seek to 0. (reason: %s)\n", strerror(errno)); 123 return false; 124 } 125 126 mpHeader = (MCO_Header *)malloc(sizeof(MCO_Header)); 127 if (!mpHeader) { 128 ALOGE("Unable to allocate for cache header.\n"); 129 return false; 130 } 131 132 if (mInfoFile->read(reinterpret_cast<char *>(mpHeader), sizeof(MCO_Header)) != 133 (ssize_t)sizeof(MCO_Header)) { 134 ALOGE("Unable to read cache header.\n"); 135 return false; 136 } 137 138 // Dirty hack for libRS. 139 // TODO(all): This should be removed in the future. 140 if (mpHeader->libRS_threadable) { 141 mpResult->mLibRSThreadable = true; 142 } 143 144 return true; 145} 146 147 148bool MCCacheReader::checkHeader() { 149 if (memcmp(mpHeader->magic, MCO_MAGIC, 4) != 0) { 150 ALOGE("Bad magic word\n"); 151 return false; 152 } 153 154 if (memcmp(mpHeader->version, MCO_VERSION, 4) != 0) { 155 mpHeader->version[4 - 1] = '\0'; // ensure c-style string terminated 156 ALOGI("Cache file format version mismatch: now %s cached %s\n", 157 MCO_VERSION, mpHeader->version); 158 return false; 159 } 160 return true; 161} 162 163 164bool MCCacheReader::checkMachineIntType() { 165 uint32_t number = 0x00000001; 166 167 bool isLittleEndian = (*reinterpret_cast<char *>(&number) == 1); 168 if ((isLittleEndian && mpHeader->endianness != 'e') || 169 (!isLittleEndian && mpHeader->endianness != 'E')) { 170 ALOGE("Machine endianness mismatch.\n"); 171 return false; 172 } 173 174 if ((unsigned int)mpHeader->sizeof_off_t != sizeof(off_t) || 175 (unsigned int)mpHeader->sizeof_size_t != sizeof(size_t) || 176 (unsigned int)mpHeader->sizeof_ptr_t != sizeof(void *)) { 177 ALOGE("Machine integer size mismatch.\n"); 178 return false; 179 } 180 181 return true; 182} 183 184 185bool MCCacheReader::checkSectionOffsetAndSize() { 186#define CHECK_SECTION_OFFSET(NAME) \ 187 do { \ 188 off_t offset = mpHeader-> NAME##_offset; \ 189 off_t size = (off_t)mpHeader-> NAME##_size; \ 190 \ 191 if (mInfoFileSize < offset || mInfoFileSize < offset + size) { \ 192 ALOGE(#NAME " section overflow.\n"); \ 193 return false; \ 194 } \ 195 \ 196 if (offset % sizeof(int) != 0) { \ 197 ALOGE(#NAME " offset must aligned to %d.\n", (int)sizeof(int)); \ 198 return false; \ 199 } \ 200 \ 201 if (size < static_cast<off_t>(sizeof(size_t))) { \ 202 ALOGE(#NAME " size is too small to be correct.\n"); \ 203 return false; \ 204 } \ 205 } while (0) 206 207 CHECK_SECTION_OFFSET(str_pool); 208 CHECK_SECTION_OFFSET(depend_tab); 209 //CHECK_SECTION_OFFSET(reloc_tab); 210 CHECK_SECTION_OFFSET(pragma_list); 211 212#undef CHECK_SECTION_OFFSET 213 214 return true; 215} 216 217 218#define CACHE_READER_READ_SECTION(TYPE, AUTO_MANAGED_HOLDER, NAME) \ 219 TYPE *NAME##_raw = (TYPE *)malloc(mpHeader->NAME##_size); \ 220 \ 221 if (!NAME##_raw) { \ 222 ALOGE("Unable to allocate for " #NAME "\n"); \ 223 return false; \ 224 } \ 225 \ 226 /* We have to ensure that some one will deallocate NAME##_raw */ \ 227 AUTO_MANAGED_HOLDER = NAME##_raw; \ 228 \ 229 if (mInfoFile->seek(mpHeader->NAME##_offset, SEEK_SET) == -1) { \ 230 ALOGE("Unable to seek to " #NAME " section\n"); \ 231 return false; \ 232 } \ 233 \ 234 if (mInfoFile->read(reinterpret_cast<char *>(NAME##_raw), \ 235 mpHeader->NAME##_size) != (ssize_t)mpHeader->NAME##_size) \ 236 { \ 237 ALOGE("Unable to read " #NAME ".\n"); \ 238 return false; \ 239 } 240 241 242bool MCCacheReader::readStringPool() { 243 CACHE_READER_READ_SECTION(MCO_StringPool, 244 mpResult->mpStringPoolRaw, str_pool); 245 246 char *str_base = reinterpret_cast<char *>(str_pool_raw); 247 248 vector<char const *> &pool = mpResult->mStringPool; 249 for (size_t i = 0; i < str_pool_raw->count; ++i) { 250 char *str = str_base + str_pool_raw->list[i].offset; 251 pool.push_back(str); 252 } 253 254 return true; 255} 256 257 258bool MCCacheReader::checkStringPool() { 259 MCO_StringPool *poolR = mpResult->mpStringPoolRaw; 260 vector<char const *> &pool = mpResult->mStringPool; 261 262 // Ensure that every c-style string is ended with '\0' 263 for (size_t i = 0; i < poolR->count; ++i) { 264 if (pool[i][poolR->list[i].length] != '\0') { 265 ALOGE("The %lu-th string does not end with '\\0'.\n", (unsigned long)i); 266 return false; 267 } 268 } 269 270 return true; 271} 272 273 274bool MCCacheReader::readDependencyTable() { 275 CACHE_READER_READ_SECTION(MCO_DependencyTable, mpCachedDependTable, 276 depend_tab); 277 return true; 278} 279 280 281bool MCCacheReader::checkDependency() { 282 if (mDependencies.size() != mpCachedDependTable->count) { 283 ALOGE("Dependencies count mismatch. (%lu vs %lu)\n", 284 (unsigned long)mDependencies.size(), 285 (unsigned long)mpCachedDependTable->count); 286 return false; 287 } 288 289 vector<char const *> &strPool = mpResult->mStringPool; 290 map<string, pair<uint32_t, unsigned char const *> >::iterator dep; 291 292 dep = mDependencies.begin(); 293 for (size_t i = 0; i < mpCachedDependTable->count; ++i, ++dep) { 294 string const &depName = dep->first; 295 uint32_t depType = dep->second.first; 296 unsigned char const *depSHA1 = dep->second.second; 297 298 MCO_Dependency *depCached =&mpCachedDependTable->table[i]; 299 char const *depCachedName = strPool[depCached->res_name_strp_index]; 300 uint32_t depCachedType = depCached->res_type; 301 unsigned char const *depCachedSHA1 = depCached->sha1; 302 303 if (depName != depCachedName) { 304 ALOGE("Cache dependency name mismatch:\n"); 305 ALOGE(" given: %s\n", depName.c_str()); 306 ALOGE(" cached: %s\n", depCachedName); 307 308 return false; 309 } 310 311 if (memcmp(depSHA1, depCachedSHA1, 20) != 0) { 312 ALOGE("Cache dependency %s sha1 mismatch:\n", depCachedName); 313 314#define PRINT_SHA1(PREFIX, X, POSTFIX) \ 315 ALOGE(PREFIX "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" \ 316 "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" POSTFIX, \ 317 X[0], X[1], X[2], X[3], X[4], X[5], X[6], X[7], X[8], X[9], \ 318 X[10],X[11],X[12],X[13],X[14],X[15],X[16],X[17],X[18],X[19]); 319 320 PRINT_SHA1(" given: ", depSHA1, "\n"); 321 PRINT_SHA1(" cached: ", depCachedSHA1, "\n"); 322 323#undef PRINT_SHA1 324 325 return false; 326 } 327 328 if (depType != depCachedType) { 329 ALOGE("Cache dependency %s resource type mismatch.\n", depCachedName); 330 return false; 331 } 332 } 333 334 return true; 335} 336 337bool MCCacheReader::readVarNameList() { 338 CACHE_READER_READ_SECTION(MCO_String_Ptr, mpVarNameList, export_var_name_list); 339 vector<char const *> const &strPool = mpResult->mStringPool; 340 341 mpResult->mpExportVars = (MCO_ExportVarList*) 342 malloc(sizeof(size_t) + 343 sizeof(void*) * export_var_name_list_raw->count); 344 if (!mpResult->mpExportVars) { 345 ALOGE("Unable to allocate for mpExportVars\n"); 346 return false; 347 } 348 mpResult->mpExportVars->count = export_var_name_list_raw->count; 349 350 for (size_t i = 0; i < export_var_name_list_raw->count; ++i) { 351 mpResult->mpExportVars->cached_addr_list[i] = 352 rsloaderGetSymbolAddress(mpResult->mRSExecutable, strPool[export_var_name_list_raw->strp_indexs[i]]); 353#if DEBUG_MC_REFLECT 354 ALOGD("Get symbol address: %s -> %p", 355 strPool[export_var_name_list_raw->strp_indexs[i]], mpResult->mpExportVars->cached_addr_list[i]); 356#endif 357 } 358 return true; 359} 360 361bool MCCacheReader::readFuncNameList() { 362 CACHE_READER_READ_SECTION(MCO_String_Ptr, mpFuncNameList, export_func_name_list); 363 vector<char const *> const &strPool = mpResult->mStringPool; 364 365 mpResult->mpExportFuncs = (MCO_ExportFuncList*) 366 malloc(sizeof(size_t) + 367 sizeof(void*) * export_func_name_list_raw->count); 368 if (!mpResult->mpExportFuncs) { 369 ALOGE("Unable to allocate for mpExportFuncs\n"); 370 return false; 371 } 372 mpResult->mpExportFuncs->count = export_func_name_list_raw->count; 373 374 for (size_t i = 0; i < export_func_name_list_raw->count; ++i) { 375 mpResult->mpExportFuncs->cached_addr_list[i] = 376 rsloaderGetSymbolAddress(mpResult->mRSExecutable, strPool[export_func_name_list_raw->strp_indexs[i]]); 377#if DEBUG_MC_REFLECT 378 ALOGD("Get function address: %s -> %p", 379 strPool[export_func_name_list_raw->strp_indexs[i]], mpResult->mpExportFuncs->cached_addr_list[i]); 380#endif 381 } 382 return true; 383} 384 385bool MCCacheReader::readForEachNameList() { 386 CACHE_READER_READ_SECTION(MCO_String_Ptr, mpForEachNameList, export_foreach_name_list); 387 vector<char const *> const &strPool = mpResult->mStringPool; 388 389 mpResult->mpExportForEach = (MCO_ExportForEachList*) 390 malloc(sizeof(size_t) + 391 sizeof(void*) * export_foreach_name_list_raw->count); 392 if (!mpResult->mpExportForEach) { 393 ALOGE("Unable to allocate for mpExportForEach\n"); 394 return false; 395 } 396 mpResult->mpExportForEach->count = export_foreach_name_list_raw->count; 397 398 for (size_t i = 0; i < export_foreach_name_list_raw->count; ++i) { 399 mpResult->mpExportForEach->cached_addr_list[i] = 400 rsloaderGetSymbolAddress(mpResult->mRSExecutable, strPool[export_foreach_name_list_raw->strp_indexs[i]]); 401#if DEBUG_MC_REFLECT 402 ALOGE("Get foreach function address: %s -> %p", 403 strPool[export_foreach_name_list_raw->strp_indexs[i]], mpResult->mpExportForEach->cached_addr_list[i]); 404#endif 405 } 406 return true; 407} 408 409bool MCCacheReader::readPragmaList() { 410 CACHE_READER_READ_SECTION(MCO_PragmaList, mpPragmaList, pragma_list); 411 412 vector<char const *> const &strPool = mpResult->mStringPool; 413 ScriptCached::PragmaList &pragmas = mpResult->mPragmas; 414 415 for (size_t i = 0; i < pragma_list_raw->count; ++i) { 416 MCO_Pragma *pragma = &pragma_list_raw->list[i]; 417 pragmas.push_back(make_pair(strPool[pragma->key_strp_index], 418 strPool[pragma->value_strp_index])); 419 } 420 421 return true; 422} 423 424 425bool MCCacheReader::readObjectSlotList() { 426 CACHE_READER_READ_SECTION(MCO_ObjectSlotList, 427 mpResult->mpObjectSlotList, object_slot_list); 428 return true; 429} 430 431void *MCCacheReader::resolveSymbolAdapter(void *context, char const *name) { 432 MCCacheReader *self = reinterpret_cast<MCCacheReader *>(context); 433 434 if (void *Addr = FindRuntimeFunction(name)) { 435 return Addr; 436 } 437 438 if (self->mpSymbolLookupFn) { 439 if (void *Addr = 440 self->mpSymbolLookupFn(self->mpSymbolLookupContext, name)) { 441 return Addr; 442 } 443 } 444 445 ALOGE("Unable to resolve symbol: %s\n", name); 446 return NULL; 447} 448 449bool MCCacheReader::readObjFile() { 450 if (mpResult->mCachedELFExecutable.size() != 0) { 451 ALOGE("Attempted to read cached object into a non-empty script"); 452 return false; 453 } 454 char readBuffer[1024]; 455 int readSize; 456 while ((readSize = mObjFile->read(readBuffer, 1024)) > 0) { 457 mpResult->mCachedELFExecutable.append(readBuffer, readBuffer + readSize); 458 } 459 if (readSize != 0) { 460 ALOGE("Read file Error"); 461 return false; 462 } 463 ALOGD("Read object file size %d", (int)mpResult->mCachedELFExecutable.size()); 464 mpResult->mRSExecutable = 465 rsloaderCreateExec((unsigned char *)&*(mpResult->mCachedELFExecutable.begin()), 466 mpResult->mCachedELFExecutable.size(), 467 &resolveSymbolAdapter, this); 468 469 // Point ELF section headers to location of executable code, otherwise 470 // execution through GDB stops unexpectedly as GDB translates breakpoints 471 // in JITted code incorrectly (and complains about being unable to insert 472 // breakpoint at an invalid address) 473 rsloaderUpdateSectionHeaders(mpResult->mRSExecutable, 474 (unsigned char*) mpResult->mCachedELFExecutable.begin()); 475 476 return true; 477} 478 479#undef CACHE_READER_READ_SECTION 480 481bool MCCacheReader::readRelocationTable() { 482 // TODO(logan): Not finished. 483 return true; 484} 485 486 487bool MCCacheReader::relocate() { 488 return true; 489} 490 491} // namespace bcc 492