summaryrefslogtreecommitdiff
path: root/simpleperf/read_elf.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'simpleperf/read_elf.cpp')
-rw-r--r--simpleperf/read_elf.cpp73
1 files changed, 64 insertions, 9 deletions
diff --git a/simpleperf/read_elf.cpp b/simpleperf/read_elf.cpp
index 028af720..5ec289be 100644
--- a/simpleperf/read_elf.cpp
+++ b/simpleperf/read_elf.cpp
@@ -18,7 +18,10 @@
#include <stdio.h>
#include <string.h>
+
#include <algorithm>
+#include <limits>
+
#include <base/file.h>
#include <base/logging.h>
@@ -168,10 +171,9 @@ void ParseSymbolsFromELFFile(const llvm::object::ELFFile<ELFT>* elf,
continue;
}
symbol.vaddr = elf_symbol.st_value;
- symbol.start_in_file = elf_symbol.st_value - shdr->sh_addr + shdr->sh_offset;
- if ((symbol.start_in_file & 1) != 0 && is_arm) {
+ if ((symbol.vaddr & 1) != 0 && is_arm) {
// Arm sets bit 0 to mark it as thumb code, remove the flag.
- symbol.start_in_file &= ~1;
+ symbol.vaddr &= ~1;
}
symbol.len = elf_symbol.st_size;
int type = elf_symbol.getType();
@@ -196,18 +198,18 @@ void ParseSymbolsFromELFFile(const llvm::object::ELFFile<ELFT>* elf,
}
}
-bool ParseSymbolsFromElfFile(const std::string& filename, const BuildId& expected_build_id,
- std::function<void(const ElfFileSymbol&)> callback) {
- auto owning_binary = llvm::object::createBinary(llvm::StringRef(filename));
+static llvm::object::ObjectFile* GetObjectFile(
+ llvm::ErrorOr<llvm::object::OwningBinary<llvm::object::Binary>>& owning_binary,
+ const std::string& filename, const BuildId& expected_build_id) {
if (owning_binary.getError()) {
PLOG(DEBUG) << "can't open file '" << filename << "'";
- return false;
+ return nullptr;
}
llvm::object::Binary* binary = owning_binary.get().getBinary();
auto obj = llvm::dyn_cast<llvm::object::ObjectFile>(binary);
if (obj == nullptr) {
LOG(DEBUG) << filename << " is not an object file";
- return false;
+ return nullptr;
}
if (!expected_build_id.IsEmpty()) {
BuildId real_build_id;
@@ -217,9 +219,19 @@ bool ParseSymbolsFromElfFile(const std::string& filename, const BuildId& expecte
<< "): expected " << expected_build_id.ToString() << ", real "
<< real_build_id.ToString();
if (!result) {
- return false;
+ return nullptr;
}
}
+ return obj;
+}
+
+bool ParseSymbolsFromElfFile(const std::string& filename, const BuildId& expected_build_id,
+ std::function<void(const ElfFileSymbol&)> callback) {
+ auto owning_binary = llvm::object::createBinary(llvm::StringRef(filename));
+ llvm::object::ObjectFile* obj = GetObjectFile(owning_binary, filename, expected_build_id);
+ if (obj == nullptr) {
+ return false;
+ }
if (auto elf = llvm::dyn_cast<llvm::object::ELF32LEObjectFile>(obj)) {
ParseSymbolsFromELFFile(elf->getELFFile(), callback);
@@ -231,3 +243,46 @@ bool ParseSymbolsFromElfFile(const std::string& filename, const BuildId& expecte
}
return true;
}
+
+template <class ELFT>
+bool ReadMinExecutableVirtualAddress(const llvm::object::ELFFile<ELFT>* elf, uint64_t* p_vaddr) {
+ bool has_vaddr = false;
+ uint64_t min_addr = std::numeric_limits<uint64_t>::max();
+ for (auto it = elf->begin_program_headers(); it != elf->end_program_headers(); ++it) {
+ if ((it->p_type == llvm::ELF::PT_LOAD) && (it->p_flags & llvm::ELF::PF_X)) {
+ if (it->p_vaddr < min_addr) {
+ min_addr = it->p_vaddr;
+ has_vaddr = true;
+ }
+ }
+ }
+ if (has_vaddr) {
+ *p_vaddr = min_addr;
+ }
+ return has_vaddr;
+}
+
+bool ReadMinExecutableVirtualAddressFromElfFile(const std::string& filename,
+ const BuildId& expected_build_id,
+ uint64_t* min_vaddr) {
+ auto owning_binary = llvm::object::createBinary(llvm::StringRef(filename));
+ llvm::object::ObjectFile* obj = GetObjectFile(owning_binary, filename, expected_build_id);
+ if (obj == nullptr) {
+ return false;
+ }
+
+ bool result = false;
+ if (auto elf = llvm::dyn_cast<llvm::object::ELF32LEObjectFile>(obj)) {
+ result = ReadMinExecutableVirtualAddress(elf->getELFFile(), min_vaddr);
+ } else if (auto elf = llvm::dyn_cast<llvm::object::ELF64LEObjectFile>(obj)) {
+ result = ReadMinExecutableVirtualAddress(elf->getELFFile(), min_vaddr);
+ } else {
+ LOG(ERROR) << "unknown elf format in file" << filename;
+ return false;
+ }
+
+ if (!result) {
+ LOG(ERROR) << "no program header in file " << filename;
+ }
+ return result;
+}