diff options
Diffstat (limited to 'simpleperf/read_elf.cpp')
-rw-r--r-- | simpleperf/read_elf.cpp | 120 |
1 files changed, 76 insertions, 44 deletions
diff --git a/simpleperf/read_elf.cpp b/simpleperf/read_elf.cpp index 98cf1937..822d1e3e 100644 --- a/simpleperf/read_elf.cpp +++ b/simpleperf/read_elf.cpp @@ -43,6 +43,8 @@ #define ELF_NOTE_GNU "GNU" #define NT_GNU_BUILD_ID 3 +using namespace simpleperf; + std::ostream& operator<<(std::ostream& os, const ElfStatus& status) { switch (status) { case ElfStatus::NO_ERROR: @@ -78,28 +80,14 @@ bool IsValidElfFileMagic(const char* buf, size_t buf_size) { return (buf_size >= 4u && memcmp(buf, elf_magic, 4) == 0); } -ElfStatus IsValidElfFile(int fd) { +ElfStatus IsValidElfFile(int fd, uint64_t file_offset) { char buf[4]; - if (!android::base::ReadFully(fd, buf, 4)) { + if (!android::base::ReadFullyAtOffset(fd, buf, 4, file_offset)) { return ElfStatus::READ_FAILED; } return IsValidElfFileMagic(buf, 4) ? ElfStatus::NO_ERROR : ElfStatus::FILE_MALFORMED; } -ElfStatus IsValidElfPath(const std::string& filename) { - if (!IsRegularFile(filename)) { - return ElfStatus::FILE_NOT_FOUND; - } - std::string mode = std::string("rb") + CLOSE_ON_EXEC_MODE; - FILE* fp = fopen(filename.c_str(), mode.c_str()); - if (fp == nullptr) { - return ElfStatus::READ_FAILED; - } - ElfStatus result = IsValidElfFile(fileno(fp)); - fclose(fp); - return result; -} - bool GetBuildIdFromNoteSection(const char* section, size_t section_size, BuildId* build_id) { const char* p = section; const char* end = p + section_size; @@ -173,15 +161,16 @@ static ElfStatus GetBuildIdFromObjectFile(llvm::object::ObjectFile* obj, BuildId } struct BinaryWrapper { - llvm::object::OwningBinary<llvm::object::Binary> binary; - llvm::object::ObjectFile* obj; - - BinaryWrapper() : obj(nullptr) { - } + std::unique_ptr<llvm::MemoryBuffer> buffer; + std::unique_ptr<llvm::object::Binary> binary; + llvm::object::ObjectFile* obj = nullptr; }; static ElfStatus OpenObjectFile(const std::string& filename, uint64_t file_offset, uint64_t file_size, BinaryWrapper* wrapper) { + if (!IsRegularFile(filename)) { + return ElfStatus::FILE_NOT_FOUND; + } android::base::unique_fd fd = FileHelper::OpenReadOnly(filename); if (fd == -1) { return ElfStatus::READ_FAILED; @@ -192,6 +181,10 @@ static ElfStatus OpenObjectFile(const std::string& filename, uint64_t file_offse return ElfStatus::READ_FAILED; } } + ElfStatus status = IsValidElfFile(fd, file_offset); + if (status != ElfStatus::NO_ERROR) { + return status; + } auto buffer_or_err = llvm::MemoryBuffer::getOpenFileSlice(fd, filename, file_size, file_offset); if (!buffer_or_err) { return ElfStatus::READ_FAILED; @@ -200,9 +193,9 @@ static ElfStatus OpenObjectFile(const std::string& filename, uint64_t file_offse if (!binary_or_err) { return ElfStatus::READ_FAILED; } - wrapper->binary = llvm::object::OwningBinary<llvm::object::Binary>(std::move(binary_or_err.get()), - std::move(buffer_or_err.get())); - wrapper->obj = llvm::dyn_cast<llvm::object::ObjectFile>(wrapper->binary.getBinary()); + wrapper->buffer = std::move(buffer_or_err.get()); + wrapper->binary = std::move(binary_or_err.get()); + wrapper->obj = llvm::dyn_cast<llvm::object::ObjectFile>(wrapper->binary.get()); if (wrapper->obj == nullptr) { return ElfStatus::FILE_MALFORMED; } @@ -215,9 +208,9 @@ static ElfStatus OpenObjectFileInMemory(const char* data, size_t size, BinaryWra if (!binary_or_err) { return ElfStatus::FILE_MALFORMED; } - wrapper->binary = llvm::object::OwningBinary<llvm::object::Binary>(std::move(binary_or_err.get()), - std::move(buffer)); - wrapper->obj = llvm::dyn_cast<llvm::object::ObjectFile>(wrapper->binary.getBinary()); + wrapper->buffer = std::move(buffer); + wrapper->binary = std::move(binary_or_err.get()); + wrapper->obj = llvm::dyn_cast<llvm::object::ObjectFile>(wrapper->binary.get()); if (wrapper->obj == nullptr) { return ElfStatus::FILE_MALFORMED; } @@ -225,10 +218,6 @@ static ElfStatus OpenObjectFileInMemory(const char* data, size_t size, BinaryWra } ElfStatus GetBuildIdFromElfFile(const std::string& filename, BuildId* build_id) { - ElfStatus result = IsValidElfPath(filename); - if (result != ElfStatus::NO_ERROR) { - return result; - } return GetBuildIdFromEmbeddedElfFile(filename, 0, 0, build_id); } @@ -442,10 +431,6 @@ ElfStatus MatchBuildId(llvm::object::ObjectFile* obj, const BuildId& expected_bu ElfStatus ParseSymbolsFromElfFile(const std::string& filename, const BuildId& expected_build_id, const std::function<void(const ElfFileSymbol&)>& callback) { - ElfStatus result = IsValidElfPath(filename); - if (result != ElfStatus::NO_ERROR) { - return result; - } return ParseSymbolsFromEmbeddedElfFile(filename, 0, 0, expected_build_id, callback); } @@ -537,10 +522,6 @@ ElfStatus ReadMinExecutableVirtualAddressFromElfFile(const std::string& filename const BuildId& expected_build_id, uint64_t* min_vaddr, uint64_t* file_offset_of_min_vaddr) { - ElfStatus result = IsValidElfPath(filename); - if (result != ElfStatus::NO_ERROR) { - return result; - } return ReadMinExecutableVirtualAddressFromEmbeddedElfFile(filename, 0, 0, expected_build_id, min_vaddr, file_offset_of_min_vaddr); } @@ -570,12 +551,8 @@ ElfStatus ReadMinExecutableVirtualAddressFromEmbeddedElfFile(const std::string& ElfStatus ReadSectionFromElfFile(const std::string& filename, const std::string& section_name, std::string* content) { - ElfStatus result = IsValidElfPath(filename); - if (result != ElfStatus::NO_ERROR) { - return result; - } BinaryWrapper wrapper; - result = OpenObjectFile(filename, 0, 0, &wrapper); + ElfStatus result = OpenObjectFile(filename, 0, 0, &wrapper); if (result != ElfStatus::NO_ERROR) { return result; } @@ -587,3 +564,58 @@ ElfStatus ReadSectionFromElfFile(const std::string& filename, const std::string& return ElfStatus::FILE_MALFORMED; } } + +namespace { + +template <typename T> +class ElfFileImpl {}; + +template <typename ELFT> +class ElfFileImpl<llvm::object::ELFFile<ELFT>> : public ElfFile { + public: + ElfFileImpl(BinaryWrapper&& wrapper, const llvm::object::ELFFile<ELFT>* elf) + : wrapper_(std::move(wrapper)), elf_(elf) {} + + llvm::MemoryBuffer* GetMemoryBuffer() override { + return wrapper_.buffer.get(); + } + + private: + BinaryWrapper wrapper_; + const llvm::object::ELFFile<ELFT>* elf_; +}; + +} // namespace + +namespace simpleperf { + +std::unique_ptr<ElfFile> ElfFile::Open(const std::string& filename, ElfStatus* status) { + BinaryWrapper wrapper; + auto tuple = SplitUrlInApk(filename); + if (std::get<0>(tuple)) { + EmbeddedElf* elf = ApkInspector::FindElfInApkByName(std::get<1>(tuple), std::get<2>(tuple)); + if (elf == nullptr) { + *status = ElfStatus::FILE_NOT_FOUND; + } else { + *status = OpenObjectFile(elf->filepath(), elf->entry_offset(), elf->entry_size(), &wrapper); + } + } else { + *status = OpenObjectFile(filename, 0, 0, &wrapper); + } + if (*status == ElfStatus::NO_ERROR) { + if (auto obj = llvm::dyn_cast<llvm::object::ELF32LEObjectFile>(wrapper.obj)) { + using elf_t = std::decay_t<decltype(*obj->getELFFile())>; + return std::unique_ptr<ElfFile>( + new ElfFileImpl<elf_t>(std::move(wrapper), obj->getELFFile())); + } + if (auto obj = llvm::dyn_cast<llvm::object::ELF64LEObjectFile>(wrapper.obj)) { + using elf_t = std::decay_t<decltype(*obj->getELFFile())>; + return std::unique_ptr<ElfFile>( + new ElfFileImpl<elf_t>(std::move(wrapper), obj->getELFFile())); + } + *status = ElfStatus::FILE_MALFORMED; + } + return nullptr; +} + +} // namespace simpleperf
\ No newline at end of file |