diff options
author | Yabin Cui <yabinc@google.com> | 2019-02-07 15:06:42 -0800 |
---|---|---|
committer | Yabin Cui <yabinc@google.com> | 2019-02-07 15:23:32 -0800 |
commit | db2c493acf984c14c16a0417e6858f0140770208 (patch) | |
tree | d5f7c063dfc8b09c4f560094ea7998e989fd1ad2 /simpleperf/dso.cpp | |
parent | ed1f0357906b3b92bc180b28a6c2fd1f9082fb67 (diff) | |
download | extras-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.cpp | 99 |
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>(); |