summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYabin Cui <yabinc@google.com>2020-04-23 18:10:45 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2020-04-23 18:10:45 +0000
commit38568ac7cfd893885b3fc9a69724f4d90d3b745c (patch)
tree0d27a71d1ecfef535b282ec814d4e97ae49724ca
parent1b52bd6fb2a70d0b80c93fe5ea49d92ddb94676e (diff)
parentba4e42a893749a9f16de48c53f9cdfbcfa49d3ae (diff)
downloadextras-38568ac7cfd893885b3fc9a69724f4d90d3b745c.tar.gz
simpleperf: add class interface to read elf files. am: ba4e42a893
Change-Id: Ib33f81c7962ab0a61f191a3795abfcc01b2486f3
-rw-r--r--simpleperf/ETMDecoder.cpp14
-rw-r--r--simpleperf/read_apk.cpp6
-rw-r--r--simpleperf/read_elf.cpp120
-rw-r--r--simpleperf/read_elf.h23
-rw-r--r--simpleperf/read_elf_test.cpp9
5 files changed, 112 insertions, 60 deletions
diff --git a/simpleperf/ETMDecoder.cpp b/simpleperf/ETMDecoder.cpp
index 6e65dd59..ae6b6c2f 100644
--- a/simpleperf/ETMDecoder.cpp
+++ b/simpleperf/ETMDecoder.cpp
@@ -210,19 +210,19 @@ class MemAccess : public ITargetMemAccess {
}
llvm::MemoryBuffer* GetMemoryBuffer(Dso* dso) {
- if (auto it = memory_buffers_.find(dso); it != memory_buffers_.end()) {
- return it->second.get();
+ auto it = elf_map_.find(dso);
+ if (it == elf_map_.end()) {
+ ElfStatus status;
+ auto res = elf_map_.emplace(dso, ElfFile::Open(dso->GetDebugFilePath(), &status));
+ it = res.first;
}
- auto buffer_or_err = llvm::MemoryBuffer::getFile(dso->GetDebugFilePath());
- llvm::MemoryBuffer* buffer = buffer_or_err ? buffer_or_err.get().release() : nullptr;
- memory_buffers_.emplace(dso, buffer);
- return buffer;
+ return it->second ? it->second->GetMemoryBuffer() : nullptr;
}
// map from trace id to thread id
std::unordered_map<uint8_t, pid_t> tid_map_;
ThreadTree& thread_tree_;
- std::unordered_map<Dso*, std::unique_ptr<llvm::MemoryBuffer>> memory_buffers_;
+ std::unordered_map<Dso*, std::unique_ptr<ElfFile>> elf_map_;
// cache of the last buffer
uint8_t trace_id_ = 0;
const char* buffer_ = nullptr;
diff --git a/simpleperf/read_apk.cpp b/simpleperf/read_apk.cpp
index a6aae6fe..651a2412 100644
--- a/simpleperf/read_apk.cpp
+++ b/simpleperf/read_apk.cpp
@@ -96,11 +96,7 @@ std::unique_ptr<EmbeddedElf> ApkInspector::FindElfInApkByOffsetWithoutCache(
}
// We found something in the zip file at the right spot. Is it an ELF?
- if (lseek(ahelper->GetFd(), found_entry.offset, SEEK_SET) != found_entry.offset) {
- PLOG(ERROR) << "lseek() failed in " << apk_path << " offset " << found_entry.offset;
- return nullptr;
- }
- if (IsValidElfFile(ahelper->GetFd()) != ElfStatus::NO_ERROR) {
+ if (IsValidElfFile(ahelper->GetFd(), found_entry.offset) != ElfStatus::NO_ERROR) {
// Omit files that are not ELF files.
return nullptr;
}
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
diff --git a/simpleperf/read_elf.h b/simpleperf/read_elf.h
index 1ab9a1f3..f289ee17 100644
--- a/simpleperf/read_elf.h
+++ b/simpleperf/read_elf.h
@@ -84,11 +84,28 @@ ElfStatus ReadMinExecutableVirtualAddressFromEmbeddedElfFile(const std::string&
ElfStatus ReadSectionFromElfFile(const std::string& filename, const std::string& section_name,
std::string* content);
-// Expose the following functions for unit tests.
+namespace llvm {
+class MemoryBuffer;
+}
+
+namespace simpleperf {
+
+class ElfFile {
+ public:
+ static std::unique_ptr<ElfFile> Open(const std::string& filename, ElfStatus* status);
+ virtual ~ElfFile() {}
+
+ virtual llvm::MemoryBuffer* GetMemoryBuffer() = 0;
+
+ protected:
+ ElfFile() {}
+};
+
+} // namespace simpleperf
+
bool IsArmMappingSymbol(const char* name);
-ElfStatus IsValidElfFile(int fd);
+ElfStatus IsValidElfFile(int fd, uint64_t file_offset = 0);
bool IsValidElfFileMagic(const char* buf, size_t buf_size);
-ElfStatus IsValidElfPath(const std::string& filename);
bool GetBuildIdFromNoteSection(const char* section, size_t section_size, BuildId* build_id);
#endif // SIMPLE_PERF_READ_ELF_H_
diff --git a/simpleperf/read_elf_test.cpp b/simpleperf/read_elf_test.cpp
index 9f74366c..cc5aa52b 100644
--- a/simpleperf/read_elf_test.cpp
+++ b/simpleperf/read_elf_test.cpp
@@ -29,6 +29,8 @@
#define ELF_NOTE_GNU "GNU"
#define NT_GNU_BUILD_ID 3
+using namespace simpleperf;
+
TEST(read_elf, GetBuildIdFromNoteSection) {
BuildId build_id;
std::vector<char> data;
@@ -137,7 +139,12 @@ TEST(read_elf, arm_mapping_symbol) {
ASSERT_FALSE(IsArmMappingSymbol("$a_no_dot"));
}
-TEST(read_elf, IsValidElfPath) {
+TEST(read_elf, ElfFile_Open) {
+ auto IsValidElfPath = [](const std::string& path) {
+ ElfStatus status;
+ ElfFile::Open(path, &status);
+ return status;
+ };
ASSERT_NE(ElfStatus::NO_ERROR, IsValidElfPath("/dev/zero"));
TemporaryFile tmp_file;
ASSERT_EQ(ElfStatus::READ_FAILED, IsValidElfPath(tmp_file.path));