1 /* 2 * Copyright (C) 2015 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 "read_elf.h" 18 #include "read_apk.h" 19 20 #include <stdio.h> 21 #include <string.h> 22 #include <sys/stat.h> 23 #include <sys/types.h> 24 25 #include <algorithm> 26 #include <limits> 27 28 #include <android-base/file.h> 29 #include <android-base/logging.h> 30 31 #pragma clang diagnostic push 32 #pragma clang diagnostic ignored "-Wunused-parameter" 33 34 #include <llvm/ADT/StringRef.h> 35 #include <llvm/Object/Binary.h> 36 #include <llvm/Object/ELFObjectFile.h> 37 #include <llvm/Object/ObjectFile.h> 38 39 #pragma clang diagnostic pop 40 41 #include "utils.h" 42 43 #define ELF_NOTE_GNU "GNU" 44 #define NT_GNU_BUILD_ID 3 45 46 using namespace simpleperf; 47 48 std::ostream& operator<<(std::ostream& os, const ElfStatus& status) { 49 switch (status) { 50 case ElfStatus::NO_ERROR: 51 os << "No error"; 52 break; 53 case ElfStatus::FILE_NOT_FOUND: 54 os << "File not found"; 55 break; 56 case ElfStatus::READ_FAILED: 57 os << "Read failed"; 58 break; 59 case ElfStatus::FILE_MALFORMED: 60 os << "Malformed file"; 61 break; 62 case ElfStatus::NO_SYMBOL_TABLE: 63 os << "No symbol table"; 64 break; 65 case ElfStatus::NO_BUILD_ID: 66 os << "No build id"; 67 break; 68 case ElfStatus::BUILD_ID_MISMATCH: 69 os << "Build id mismatch"; 70 break; 71 case ElfStatus::SECTION_NOT_FOUND: 72 os << "Section not found"; 73 break; 74 } 75 return os; 76 } 77 78 bool IsValidElfFileMagic(const char* buf, size_t buf_size) { 79 static const char elf_magic[] = {0x7f, 'E', 'L', 'F'}; 80 return (buf_size >= 4u && memcmp(buf, elf_magic, 4) == 0); 81 } 82 83 ElfStatus IsValidElfFile(int fd, uint64_t file_offset) { 84 char buf[4]; 85 if (!android::base::ReadFullyAtOffset(fd, buf, 4, file_offset)) { 86 return ElfStatus::READ_FAILED; 87 } 88 return IsValidElfFileMagic(buf, 4) ? ElfStatus::NO_ERROR : ElfStatus::FILE_MALFORMED; 89 } 90 91 bool GetBuildIdFromNoteSection(const char* section, size_t section_size, BuildId* build_id) { 92 const char* p = section; 93 const char* end = p + section_size; 94 while (p < end) { 95 if (p + 12 >= end) { 96 return false; 97 } 98 uint32_t namesz; 99 uint32_t descsz; 100 uint32_t type; 101 MoveFromBinaryFormat(namesz, p); 102 MoveFromBinaryFormat(descsz, p); 103 MoveFromBinaryFormat(type, p); 104 namesz = Align(namesz, 4); 105 descsz = Align(descsz, 4); 106 if ((type == NT_GNU_BUILD_ID) && (p < end) && (strcmp(p, ELF_NOTE_GNU) == 0)) { 107 const char* desc_start = p + namesz; 108 const char* desc_end = desc_start + descsz; 109 if (desc_start > p && desc_start < desc_end && desc_end <= end) { 110 *build_id = BuildId(p + namesz, descsz); 111 return true; 112 } else { 113 return false; 114 } 115 } 116 p += namesz + descsz; 117 } 118 return false; 119 } 120 121 ElfStatus GetBuildIdFromNoteFile(const std::string& filename, BuildId* build_id) { 122 std::string content; 123 if (!android::base::ReadFileToString(filename, &content)) { 124 return ElfStatus::READ_FAILED; 125 } 126 if (!GetBuildIdFromNoteSection(content.c_str(), content.size(), build_id)) { 127 return ElfStatus::NO_BUILD_ID; 128 } 129 return ElfStatus::NO_ERROR; 130 } 131 132 template <class ELFT> 133 ElfStatus GetBuildIdFromELFFile(const llvm::object::ELFObjectFile<ELFT>* elf, BuildId* build_id) { 134 llvm::StringRef data = elf->getData(); 135 const char* binary_start = data.data(); 136 const char* binary_end = data.data() + data.size(); 137 for (auto it = elf->section_begin(); it != elf->section_end(); ++it) { 138 const llvm::object::ELFSectionRef& section_ref = *it; 139 if (section_ref.getType() == llvm::ELF::SHT_NOTE) { 140 if (it->getContents(data)) { 141 return ElfStatus::READ_FAILED; 142 } 143 if (data.data() < binary_start || data.data() + data.size() > binary_end) { 144 return ElfStatus::NO_BUILD_ID; 145 } 146 if (GetBuildIdFromNoteSection(data.data(), data.size(), build_id)) { 147 return ElfStatus::NO_ERROR; 148 } 149 } 150 } 151 return ElfStatus::NO_BUILD_ID; 152 } 153 154 static ElfStatus GetBuildIdFromObjectFile(llvm::object::ObjectFile* obj, BuildId* build_id) { 155 if (auto elf = llvm::dyn_cast<llvm::object::ELF32LEObjectFile>(obj)) { 156 return GetBuildIdFromELFFile(elf, build_id); 157 } else if (auto elf = llvm::dyn_cast<llvm::object::ELF64LEObjectFile>(obj)) { 158 return GetBuildIdFromELFFile(elf, build_id); 159 } 160 return ElfStatus::FILE_MALFORMED; 161 } 162 163 struct BinaryWrapper { 164 std::unique_ptr<llvm::MemoryBuffer> buffer; 165 std::unique_ptr<llvm::object::Binary> binary; 166 llvm::object::ObjectFile* obj = nullptr; 167 }; 168 169 static ElfStatus OpenObjectFile(const std::string& filename, uint64_t file_offset, 170 uint64_t file_size, BinaryWrapper* wrapper) { 171 if (!IsRegularFile(filename)) { 172 return ElfStatus::FILE_NOT_FOUND; 173 } 174 android::base::unique_fd fd = FileHelper::OpenReadOnly(filename); 175 if (fd == -1) { 176 return ElfStatus::READ_FAILED; 177 } 178 if (file_size == 0) { 179 file_size = GetFileSize(filename); 180 if (file_size == 0) { 181 return ElfStatus::READ_FAILED; 182 } 183 } 184 ElfStatus status = IsValidElfFile(fd, file_offset); 185 if (status != ElfStatus::NO_ERROR) { 186 return status; 187 } 188 auto buffer_or_err = llvm::MemoryBuffer::getOpenFileSlice(fd, filename, file_size, file_offset); 189 if (!buffer_or_err) { 190 return ElfStatus::READ_FAILED; 191 } 192 auto binary_or_err = llvm::object::createBinary(buffer_or_err.get()->getMemBufferRef()); 193 if (!binary_or_err) { 194 return ElfStatus::READ_FAILED; 195 } 196 wrapper->buffer = std::move(buffer_or_err.get()); 197 wrapper->binary = std::move(binary_or_err.get()); 198 wrapper->obj = llvm::dyn_cast<llvm::object::ObjectFile>(wrapper->binary.get()); 199 if (wrapper->obj == nullptr) { 200 return ElfStatus::FILE_MALFORMED; 201 } 202 return ElfStatus::NO_ERROR; 203 } 204 205 static ElfStatus OpenObjectFileInMemory(const char* data, size_t size, BinaryWrapper* wrapper) { 206 auto buffer = llvm::MemoryBuffer::getMemBuffer(llvm::StringRef(data, size)); 207 auto binary_or_err = llvm::object::createBinary(buffer->getMemBufferRef()); 208 if (!binary_or_err) { 209 return ElfStatus::FILE_MALFORMED; 210 } 211 wrapper->buffer = std::move(buffer); 212 wrapper->binary = std::move(binary_or_err.get()); 213 wrapper->obj = llvm::dyn_cast<llvm::object::ObjectFile>(wrapper->binary.get()); 214 if (wrapper->obj == nullptr) { 215 return ElfStatus::FILE_MALFORMED; 216 } 217 return ElfStatus::NO_ERROR; 218 } 219 220 ElfStatus GetBuildIdFromElfFile(const std::string& filename, BuildId* build_id) { 221 return GetBuildIdFromEmbeddedElfFile(filename, 0, 0, build_id); 222 } 223 224 ElfStatus GetBuildIdFromEmbeddedElfFile(const std::string& filename, uint64_t file_offset, 225 uint32_t file_size, BuildId* build_id) { 226 BinaryWrapper wrapper; 227 ElfStatus result = OpenObjectFile(filename, file_offset, file_size, &wrapper); 228 if (result != ElfStatus::NO_ERROR) { 229 return result; 230 } 231 return GetBuildIdFromObjectFile(wrapper.obj, build_id); 232 } 233 234 template <class ELFT> 235 ElfStatus ReadSectionFromELFFile(const llvm::object::ELFObjectFile<ELFT>* elf, const std::string& section_name, 236 std::string* content) { 237 for (llvm::object::section_iterator it = elf->section_begin(); it != elf->section_end(); ++it) { 238 llvm::StringRef name; 239 if (it->getName(name) || name != section_name) { 240 continue; 241 } 242 llvm::StringRef data; 243 std::error_code err = it->getContents(data); 244 if (err) { 245 return ElfStatus::READ_FAILED; 246 } 247 *content = data; 248 return ElfStatus::NO_ERROR; 249 } 250 return ElfStatus::SECTION_NOT_FOUND; 251 } 252 253 bool IsArmMappingSymbol(const char* name) { 254 // Mapping symbols in arm, which are described in "ELF for ARM Architecture" and 255 // "ELF for ARM 64-bit Architecture". The regular expression to match mapping symbol 256 // is ^\$(a|d|t|x)(\..*)?$ 257 return name[0] == '$' && strchr("adtx", name[1]) != nullptr && (name[2] == '\0' || name[2] == '.'); 258 } 259 260 void ReadSymbolTable(llvm::object::symbol_iterator sym_begin, 261 llvm::object::symbol_iterator sym_end, 262 const std::function<void(const ElfFileSymbol&)>& callback, 263 bool is_arm, 264 const llvm::object::section_iterator& section_end) { 265 for (; sym_begin != sym_end; ++sym_begin) { 266 ElfFileSymbol symbol; 267 auto symbol_ref = static_cast<const llvm::object::ELFSymbolRef*>(&*sym_begin); 268 // Exclude undefined symbols, otherwise we may wrongly use them as labels in functions. 269 if (symbol_ref->getFlags() & symbol_ref->SF_Undefined) { 270 continue; 271 } 272 llvm::Expected<llvm::object::section_iterator> section_it_or_err = symbol_ref->getSection(); 273 if (!section_it_or_err) { 274 continue; 275 } 276 // Symbols in .dynsym section don't have associated section. 277 if (section_it_or_err.get() != section_end) { 278 llvm::StringRef section_name; 279 if (section_it_or_err.get()->getName(section_name) || section_name.empty()) { 280 continue; 281 } 282 if (section_name == ".text") { 283 symbol.is_in_text_section = true; 284 } 285 } 286 287 llvm::Expected<llvm::StringRef> symbol_name_or_err = symbol_ref->getName(); 288 if (!symbol_name_or_err || symbol_name_or_err.get().empty()) { 289 continue; 290 } 291 292 symbol.name = symbol_name_or_err.get(); 293 symbol.vaddr = symbol_ref->getValue(); 294 if ((symbol.vaddr & 1) != 0 && is_arm) { 295 // Arm sets bit 0 to mark it as thumb code, remove the flag. 296 symbol.vaddr &= ~1; 297 } 298 symbol.len = symbol_ref->getSize(); 299 llvm::object::SymbolRef::Type symbol_type = *symbol_ref->getType(); 300 if (symbol_type == llvm::object::SymbolRef::ST_Function) { 301 symbol.is_func = true; 302 } else if (symbol_type == llvm::object::SymbolRef::ST_Unknown) { 303 if (symbol.is_in_text_section) { 304 symbol.is_label = true; 305 if (is_arm) { 306 // Remove mapping symbols in arm. 307 const char* p = (symbol.name.compare(0, linker_prefix.size(), linker_prefix) == 0) 308 ? symbol.name.c_str() + linker_prefix.size() 309 : symbol.name.c_str(); 310 if (IsArmMappingSymbol(p)) { 311 symbol.is_label = false; 312 } 313 } 314 } 315 } 316 317 callback(symbol); 318 } 319 } 320 321 template <class ELFT> 322 void AddSymbolForPltSection(const llvm::object::ELFObjectFile<ELFT>* elf, 323 const std::function<void(const ElfFileSymbol&)>& callback) { 324 // We may sample instructions in .plt section if the program 325 // calls functions from shared libraries. Different architectures use 326 // different formats to store .plt section, so it needs a lot of work to match 327 // instructions in .plt section to symbols. As samples in .plt section rarely 328 // happen, and .plt section can hardly be a performance bottleneck, we can 329 // just use a symbol @plt to represent instructions in .plt section. 330 for (auto it = elf->section_begin(); it != elf->section_end(); ++it) { 331 const llvm::object::ELFSectionRef& section_ref = *it; 332 llvm::StringRef section_name; 333 std::error_code err = section_ref.getName(section_name); 334 if (err || section_name != ".plt") { 335 continue; 336 } 337 const auto* shdr = elf->getSection(section_ref.getRawDataRefImpl()); 338 if (shdr == nullptr) { 339 return; 340 } 341 ElfFileSymbol symbol; 342 symbol.vaddr = shdr->sh_addr; 343 symbol.len = shdr->sh_size; 344 symbol.is_func = true; 345 symbol.is_label = true; 346 symbol.is_in_text_section = true; 347 symbol.name = "@plt"; 348 callback(symbol); 349 return; 350 } 351 } 352 353 template <class ELFT> 354 void CheckSymbolSections(const llvm::object::ELFObjectFile<ELFT>* elf, 355 bool* has_symtab, bool* has_dynsym) { 356 *has_symtab = false; 357 *has_dynsym = false; 358 for (auto it = elf->section_begin(); it != elf->section_end(); ++it) { 359 const llvm::object::ELFSectionRef& section_ref = *it; 360 llvm::StringRef section_name; 361 std::error_code err = section_ref.getName(section_name); 362 if (err) { 363 continue; 364 } 365 if (section_name == ".dynsym") { 366 *has_dynsym = true; 367 } else if (section_name == ".symtab") { 368 *has_symtab = true; 369 } 370 } 371 } 372 373 template <class ELFT> 374 ElfStatus ParseSymbolsFromELFFile(const llvm::object::ELFObjectFile<ELFT>* elf, 375 const std::function<void(const ElfFileSymbol&)>& callback) { 376 auto machine = elf->getELFFile()->getHeader()->e_machine; 377 bool is_arm = (machine == llvm::ELF::EM_ARM || machine == llvm::ELF::EM_AARCH64); 378 AddSymbolForPltSection(elf, callback); 379 // Some applications deliberately ship elf files with broken section tables. 380 // So check the existence of .symtab section and .dynsym section before reading symbols. 381 bool has_symtab; 382 bool has_dynsym; 383 CheckSymbolSections(elf, &has_symtab, &has_dynsym); 384 if (has_symtab && elf->symbol_begin() != elf->symbol_end()) { 385 ReadSymbolTable(elf->symbol_begin(), elf->symbol_end(), callback, is_arm, elf->section_end()); 386 return ElfStatus::NO_ERROR; 387 } else if (has_dynsym && 388 elf->dynamic_symbol_begin()->getRawDataRefImpl() != llvm::object::DataRefImpl()) { 389 ReadSymbolTable(elf->dynamic_symbol_begin(), elf->dynamic_symbol_end(), callback, is_arm, 390 elf->section_end()); 391 } 392 std::string debugdata; 393 ElfStatus result = ReadSectionFromELFFile(elf, ".gnu_debugdata", &debugdata); 394 if (result == ElfStatus::SECTION_NOT_FOUND) { 395 return ElfStatus::NO_SYMBOL_TABLE; 396 } else if (result == ElfStatus::NO_ERROR) { 397 std::string decompressed_data; 398 if (XzDecompress(debugdata, &decompressed_data)) { 399 BinaryWrapper wrapper; 400 result = OpenObjectFileInMemory(decompressed_data.data(), decompressed_data.size(), 401 &wrapper); 402 if (result == ElfStatus::NO_ERROR) { 403 if (auto elf = llvm::dyn_cast<llvm::object::ELF32LEObjectFile>(wrapper.obj)) { 404 return ParseSymbolsFromELFFile(elf, callback); 405 } else if (auto elf = llvm::dyn_cast<llvm::object::ELF64LEObjectFile>(wrapper.obj)) { 406 return ParseSymbolsFromELFFile(elf, callback); 407 } else { 408 return ElfStatus::FILE_MALFORMED; 409 } 410 } 411 } 412 } 413 return result; 414 } 415 416 ElfStatus MatchBuildId(llvm::object::ObjectFile* obj, const BuildId& expected_build_id) { 417 if (expected_build_id.IsEmpty()) { 418 return ElfStatus::NO_ERROR; 419 } 420 BuildId real_build_id; 421 ElfStatus result = GetBuildIdFromObjectFile(obj, &real_build_id); 422 if (result != ElfStatus::NO_ERROR) { 423 return result; 424 } 425 if (expected_build_id != real_build_id) { 426 return ElfStatus::BUILD_ID_MISMATCH; 427 } 428 return ElfStatus::NO_ERROR; 429 } 430 431 ElfStatus ParseSymbolsFromElfFile(const std::string& filename, 432 const BuildId& expected_build_id, 433 const std::function<void(const ElfFileSymbol&)>& callback) { 434 return ParseSymbolsFromEmbeddedElfFile(filename, 0, 0, expected_build_id, callback); 435 } 436 437 ElfStatus ParseSymbolsFromEmbeddedElfFile(const std::string& filename, uint64_t file_offset, 438 uint32_t file_size, const BuildId& expected_build_id, 439 const std::function<void(const ElfFileSymbol&)>& callback) { 440 BinaryWrapper wrapper; 441 ElfStatus result = OpenObjectFile(filename, file_offset, file_size, &wrapper); 442 if (result != ElfStatus::NO_ERROR) { 443 return result; 444 } 445 result = MatchBuildId(wrapper.obj, expected_build_id); 446 if (result != ElfStatus::NO_ERROR) { 447 return result; 448 } 449 if (auto elf = llvm::dyn_cast<llvm::object::ELF32LEObjectFile>(wrapper.obj)) { 450 return ParseSymbolsFromELFFile(elf, callback); 451 } else if (auto elf = llvm::dyn_cast<llvm::object::ELF64LEObjectFile>(wrapper.obj)) { 452 return ParseSymbolsFromELFFile(elf, callback); 453 } 454 return ElfStatus::FILE_MALFORMED; 455 } 456 457 ElfStatus ParseSymbolsFromElfFileInMemory(const char* data, size_t size, 458 const std::function<void(const ElfFileSymbol&)>& callback) { 459 BinaryWrapper wrapper; 460 ElfStatus result = OpenObjectFileInMemory(data, size, &wrapper); 461 if (result != ElfStatus::NO_ERROR) { 462 return result; 463 } 464 if (auto elf = llvm::dyn_cast<llvm::object::ELF32LEObjectFile>(wrapper.obj)) { 465 return ParseSymbolsFromELFFile(elf, callback); 466 } else if (auto elf = llvm::dyn_cast<llvm::object::ELF64LEObjectFile>(wrapper.obj)) { 467 return ParseSymbolsFromELFFile(elf, callback); 468 } 469 return ElfStatus::FILE_MALFORMED; 470 } 471 472 template <class ELFT> 473 ElfStatus ParseDynamicSymbolsFromELFFile(const llvm::object::ELFObjectFile<ELFT>* elf, 474 const std::function<void(const ElfFileSymbol&)>& callback) { 475 auto machine = elf->getELFFile()->getHeader()->e_machine; 476 bool is_arm = (machine == llvm::ELF::EM_ARM || machine == llvm::ELF::EM_AARCH64); 477 ReadSymbolTable(elf->dynamic_symbol_begin(), elf->dynamic_symbol_end(), callback, is_arm, 478 elf->section_end()); 479 return ElfStatus::NO_ERROR; 480 } 481 482 ElfStatus ParseDynamicSymbolsFromElfFile(const std::string& filename, 483 const std::function<void(const ElfFileSymbol&)>& callback) { 484 BinaryWrapper wrapper; 485 ElfStatus result = OpenObjectFile(filename, 0, 0, &wrapper); 486 if (result != ElfStatus::NO_ERROR) { 487 return result; 488 } 489 if (auto elf = llvm::dyn_cast<llvm::object::ELF32LEObjectFile>(wrapper.obj)) { 490 return ParseDynamicSymbolsFromELFFile(elf, callback); 491 } else if (auto elf = llvm::dyn_cast<llvm::object::ELF64LEObjectFile>(wrapper.obj)) { 492 return ParseDynamicSymbolsFromELFFile(elf, callback); 493 } 494 return ElfStatus::FILE_MALFORMED; 495 } 496 497 template <class ELFT> 498 ElfStatus ReadMinExecutableVirtualAddress(const llvm::object::ELFFile<ELFT>* elf, 499 uint64_t* p_vaddr, 500 uint64_t* file_offset) { 501 bool has_vaddr = false; 502 uint64_t min_addr = std::numeric_limits<uint64_t>::max(); 503 for (auto it = elf->program_header_begin(); it != elf->program_header_end(); ++it) { 504 if ((it->p_type == llvm::ELF::PT_LOAD) && (it->p_flags & llvm::ELF::PF_X)) { 505 if (it->p_vaddr < min_addr) { 506 min_addr = it->p_vaddr; 507 *file_offset = it->p_offset; 508 has_vaddr = true; 509 } 510 } 511 } 512 if (!has_vaddr) { 513 // JIT symfiles don't have program headers. 514 min_addr = 0; 515 *file_offset = 0; 516 } 517 *p_vaddr = min_addr; 518 return ElfStatus::NO_ERROR; 519 } 520 521 ElfStatus ReadMinExecutableVirtualAddressFromElfFile(const std::string& filename, 522 const BuildId& expected_build_id, 523 uint64_t* min_vaddr, 524 uint64_t* file_offset_of_min_vaddr) { 525 return ReadMinExecutableVirtualAddressFromEmbeddedElfFile(filename, 0, 0, expected_build_id, 526 min_vaddr, file_offset_of_min_vaddr); 527 } 528 529 ElfStatus ReadMinExecutableVirtualAddressFromEmbeddedElfFile(const std::string& filename, 530 uint64_t file_offset, 531 uint32_t file_size, 532 const BuildId& expected_build_id, 533 uint64_t* min_vaddr, 534 uint64_t* file_offset_of_min_vaddr) { 535 BinaryWrapper wrapper; 536 ElfStatus result = OpenObjectFile(filename, file_offset, file_size, &wrapper); 537 if (result != ElfStatus::NO_ERROR) { 538 return result; 539 } 540 result = MatchBuildId(wrapper.obj, expected_build_id); 541 if (result != ElfStatus::NO_ERROR) { 542 return result; 543 } 544 if (auto elf = llvm::dyn_cast<llvm::object::ELF32LEObjectFile>(wrapper.obj)) { 545 return ReadMinExecutableVirtualAddress(elf->getELFFile(), min_vaddr, file_offset_of_min_vaddr); 546 } else if (auto elf = llvm::dyn_cast<llvm::object::ELF64LEObjectFile>(wrapper.obj)) { 547 return ReadMinExecutableVirtualAddress(elf->getELFFile(), min_vaddr, file_offset_of_min_vaddr); 548 } 549 return ElfStatus::FILE_MALFORMED; 550 } 551 552 ElfStatus ReadSectionFromElfFile(const std::string& filename, const std::string& section_name, 553 std::string* content) { 554 BinaryWrapper wrapper; 555 ElfStatus result = OpenObjectFile(filename, 0, 0, &wrapper); 556 if (result != ElfStatus::NO_ERROR) { 557 return result; 558 } 559 if (auto elf = llvm::dyn_cast<llvm::object::ELF32LEObjectFile>(wrapper.obj)) { 560 return ReadSectionFromELFFile(elf, section_name, content); 561 } else if (auto elf = llvm::dyn_cast<llvm::object::ELF64LEObjectFile>(wrapper.obj)) { 562 return ReadSectionFromELFFile(elf, section_name, content); 563 } else { 564 return ElfStatus::FILE_MALFORMED; 565 } 566 } 567 568 namespace { 569 570 template <typename T> 571 class ElfFileImpl {}; 572 573 template <typename ELFT> 574 class ElfFileImpl<llvm::object::ELFFile<ELFT>> : public ElfFile { 575 public: 576 ElfFileImpl(BinaryWrapper&& wrapper, const llvm::object::ELFFile<ELFT>* elf) 577 : wrapper_(std::move(wrapper)), elf_(elf) {} 578 579 llvm::MemoryBuffer* GetMemoryBuffer() override { 580 return wrapper_.buffer.get(); 581 } 582 583 private: 584 BinaryWrapper wrapper_; 585 const llvm::object::ELFFile<ELFT>* elf_; 586 }; 587 588 } // namespace 589 590 namespace simpleperf { 591 592 std::unique_ptr<ElfFile> ElfFile::Open(const std::string& filename, ElfStatus* status) { 593 BinaryWrapper wrapper; 594 auto tuple = SplitUrlInApk(filename); 595 if (std::get<0>(tuple)) { 596 EmbeddedElf* elf = ApkInspector::FindElfInApkByName(std::get<1>(tuple), std::get<2>(tuple)); 597 if (elf == nullptr) { 598 *status = ElfStatus::FILE_NOT_FOUND; 599 } else { 600 *status = OpenObjectFile(elf->filepath(), elf->entry_offset(), elf->entry_size(), &wrapper); 601 } 602 } else { 603 *status = OpenObjectFile(filename, 0, 0, &wrapper); 604 } 605 if (*status == ElfStatus::NO_ERROR) { 606 if (auto obj = llvm::dyn_cast<llvm::object::ELF32LEObjectFile>(wrapper.obj)) { 607 using elf_t = std::decay_t<decltype(*obj->getELFFile())>; 608 return std::unique_ptr<ElfFile>( 609 new ElfFileImpl<elf_t>(std::move(wrapper), obj->getELFFile())); 610 } 611 if (auto obj = llvm::dyn_cast<llvm::object::ELF64LEObjectFile>(wrapper.obj)) { 612 using elf_t = std::decay_t<decltype(*obj->getELFFile())>; 613 return std::unique_ptr<ElfFile>( 614 new ElfFileImpl<elf_t>(std::move(wrapper), obj->getELFFile())); 615 } 616 *status = ElfStatus::FILE_MALFORMED; 617 } 618 return nullptr; 619 } 620 621 } // namespace simpleperf