summaryrefslogtreecommitdiff
path: root/simpleperf/dso.cpp
diff options
context:
space:
mode:
authorYabin Cui <yabinc@google.com>2019-02-07 15:06:42 -0800
committerYabin Cui <yabinc@google.com>2019-02-07 15:23:32 -0800
commitdb2c493acf984c14c16a0417e6858f0140770208 (patch)
treed5f7c063dfc8b09c4f560094ea7998e989fd1ad2 /simpleperf/dso.cpp
parented1f0357906b3b92bc180b28a6c2fd1f9082fb67 (diff)
downloadextras-db2c493acf984c14c16a0417e6858f0140770208.tar.gz
simpleperf: fix symbolization in multi-executable-segments libraries.
Apps may run with libraries with multiple executable segments. Symbolization ip addresses in these libraries need to use map.pgoff. The old formula converting ip to vaddr_in_file: vaddr_in_file = ip - map.start + min_executable_vaddr The new formula converting ip to vaddr_in_file: offset_in_file = ip - map.start + map.pgoff vaddr_in_file = offset_in_file - file_offset_of_min_executable_vaddr + min_executable_vaddr Bug: 124056476 Test: run simpleperf_unit_test. Test: use simpleperf to profile facebook app, ip addresses hitting libc.so Test: and libart.so are symbolized correctly. Change-Id: I5fd3ed822a916c4d04a9868d6d209c43ee190c5b
Diffstat (limited to 'simpleperf/dso.cpp')
-rw-r--r--simpleperf/dso.cpp99
1 files changed, 69 insertions, 30 deletions
diff --git a/simpleperf/dso.cpp b/simpleperf/dso.cpp
index 7fa7283b..07a10280 100644
--- a/simpleperf/dso.cpp
+++ b/simpleperf/dso.cpp
@@ -416,6 +416,10 @@ class DexFileDso : public Dso {
return &dex_file_offsets_;
}
+ uint64_t IpToVaddrInFile(uint64_t ip, uint64_t map_start, uint64_t map_pgoff) override {
+ return ip - map_start + map_pgoff;
+ }
+
std::vector<Symbol> LoadSymbols() override {
std::vector<Symbol> symbols;
std::vector<DexFileSymbol> dex_file_symbols;
@@ -454,43 +458,63 @@ class DexFileDso : public Dso {
class ElfDso : public Dso {
public:
ElfDso(const std::string& path, const std::string& debug_file_path)
- : Dso(DSO_ELF_FILE, path, debug_file_path),
- min_vaddr_(std::numeric_limits<uint64_t>::max()) {}
+ : Dso(DSO_ELF_FILE, path, debug_file_path) {}
+
+ void SetMinExecutableVaddr(uint64_t min_vaddr, uint64_t file_offset) override {
+ min_vaddr_ = min_vaddr;
+ file_offset_of_min_vaddr_ = file_offset;
+ }
- uint64_t MinVirtualAddress() override {
- if (min_vaddr_ == std::numeric_limits<uint64_t>::max()) {
+ void GetMinExecutableVaddr(uint64_t* min_vaddr, uint64_t* file_offset) override {
+ if (type_ == DSO_DEX_FILE) {
+ return dex_file_dso_->GetMinExecutableVaddr(min_vaddr, file_offset);
+ }
+ if (min_vaddr_ == uninitialized_value) {
min_vaddr_ = 0;
- if (type_ == DSO_ELF_FILE) {
- BuildId build_id = GetExpectedBuildId();
-
- uint64_t addr;
- ElfStatus result;
- auto tuple = SplitUrlInApk(debug_file_path_);
- if (std::get<0>(tuple)) {
- EmbeddedElf* elf = ApkInspector::FindElfInApkByName(std::get<1>(tuple),
- std::get<2>(tuple));
- if (elf == nullptr) {
- result = ElfStatus::FILE_NOT_FOUND;
- } else {
- result = ReadMinExecutableVirtualAddressFromEmbeddedElfFile(
- elf->filepath(), elf->entry_offset(), elf->entry_size(), build_id, &addr);
- }
+ BuildId build_id = GetExpectedBuildId();
+ uint64_t addr;
+ uint64_t offset;
+ ElfStatus result;
+ auto tuple = SplitUrlInApk(debug_file_path_);
+ if (std::get<0>(tuple)) {
+ EmbeddedElf* elf = ApkInspector::FindElfInApkByName(std::get<1>(tuple),
+ std::get<2>(tuple));
+ if (elf == nullptr) {
+ result = ElfStatus::FILE_NOT_FOUND;
} else {
- result = ReadMinExecutableVirtualAddressFromElfFile(debug_file_path_, build_id, &addr);
- }
- if (result != ElfStatus::NO_ERROR) {
- LOG(WARNING) << "failed to read min virtual address of "
- << GetDebugFilePath() << ": " << result;
- } else {
- min_vaddr_ = addr;
+ result = ReadMinExecutableVirtualAddressFromEmbeddedElfFile(
+ elf->filepath(), elf->entry_offset(), elf->entry_size(), build_id, &addr, &offset);
}
+ } else {
+ result = ReadMinExecutableVirtualAddressFromElfFile(debug_file_path_, build_id, &addr,
+ &offset);
+ }
+ if (result != ElfStatus::NO_ERROR) {
+ LOG(WARNING) << "failed to read min virtual address of "
+ << GetDebugFilePath() << ": " << result;
+ } else {
+ min_vaddr_ = addr;
+ file_offset_of_min_vaddr_ = offset;
}
}
- return min_vaddr_;
+ *min_vaddr = min_vaddr_;
+ *file_offset = file_offset_of_min_vaddr_;
}
- void SetMinVirtualAddress(uint64_t min_vaddr) override {
- min_vaddr_ = min_vaddr;
+ uint64_t IpToVaddrInFile(uint64_t ip, uint64_t map_start, uint64_t map_pgoff) override {
+ if (type_ == DSO_DEX_FILE) {
+ return dex_file_dso_->IpToVaddrInFile(ip, map_start, map_pgoff);
+ }
+ uint64_t min_vaddr;
+ uint64_t file_offset_of_min_vaddr;
+ GetMinExecutableVaddr(&min_vaddr, &file_offset_of_min_vaddr);
+ if (file_offset_of_min_vaddr == uninitialized_value) {
+ return ip - map_start + min_vaddr;
+ }
+ // Apps may make part of the executable segment of a shared library writeable, which can
+ // generate multiple executable segments at runtime. So use map_pgoff to calculate
+ // vaddr_in_file.
+ return ip - map_start + map_pgoff - file_offset_of_min_vaddr + min_vaddr;
}
void AddDexFileOffset(uint64_t dex_file_offset) override {
@@ -542,7 +566,10 @@ class ElfDso : public Dso {
}
private:
- uint64_t min_vaddr_;
+ static constexpr uint64_t uninitialized_value = std::numeric_limits<uint64_t>::max();
+
+ uint64_t min_vaddr_ = uninitialized_value;
+ uint64_t file_offset_of_min_vaddr_ = uninitialized_value;
std::unique_ptr<DexFileDso> dex_file_dso_;
};
@@ -551,6 +578,10 @@ class KernelDso : public Dso {
KernelDso(const std::string& path, const std::string& debug_file_path)
: Dso(DSO_KERNEL, path, debug_file_path) {}
+ uint64_t IpToVaddrInFile(uint64_t ip, uint64_t, uint64_t) override {
+ return ip;
+ }
+
protected:
std::vector<Symbol> LoadSymbols() override {
std::vector<Symbol> symbols;
@@ -615,6 +646,10 @@ class KernelModuleDso : public Dso {
KernelModuleDso(const std::string& path, const std::string& debug_file_path)
: Dso(DSO_KERNEL_MODULE, path, debug_file_path) {}
+ uint64_t IpToVaddrInFile(uint64_t ip, uint64_t map_start, uint64_t) override {
+ return ip - map_start;
+ }
+
protected:
std::vector<Symbol> LoadSymbols() override {
std::vector<Symbol> symbols;
@@ -636,6 +671,10 @@ class UnknownDso : public Dso {
public:
UnknownDso(const std::string& path) : Dso(DSO_UNKNOWN_FILE, path, path) {}
+ uint64_t IpToVaddrInFile(uint64_t ip, uint64_t, uint64_t) override {
+ return ip;
+ }
+
protected:
std::vector<Symbol> LoadSymbols() override {
return std::vector<Symbol>();