From a3b752cdcf107a3c245f4e9704022dbdcfd0e678 Mon Sep 17 00:00:00 2001 From: Andreas Gampe Date: Tue, 18 Sep 2018 19:25:24 -0700 Subject: Perfprofd: Introduce libsimpleperf_dex_read and read vdex files Add libsimpleperf_dex_read module to allow perfprofd to read and extract symbols from dex files. Use libart to read vdex files for their dex file offsets. Use libsimpleperf_dex_read to find symbols. Bug: 73175642 Test: mmma system/extras/perfprofd Change-Id: Ibe67087692f7ede4caf2d3b98a1cbfad570baa7c --- perfprofd/symbolizer.cc | 111 ++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 93 insertions(+), 18 deletions(-) (limited to 'perfprofd/symbolizer.cc') diff --git a/perfprofd/symbolizer.cc b/perfprofd/symbolizer.cc index bde680f5..58ff280b 100644 --- a/perfprofd/symbolizer.cc +++ b/perfprofd/symbolizer.cc @@ -22,9 +22,11 @@ #include #include - -#include "build_id.h" -#include "read_elf.h" +#include +#include +#include +#include +#include namespace perfprofd { @@ -33,6 +35,8 @@ namespace { struct SimpleperfSymbolizer : public Symbolizer { // For simplicity, we assume non-overlapping symbols. struct Symbol { + Symbol(const std::string& n, uint64_t l) : name(n), length(l) {} + std::string name; uint64_t length; }; @@ -66,28 +70,99 @@ struct SimpleperfSymbolizer : public Symbolizer { } void LoadDso(const std::string& dso) { - SymbolMap data; - auto callback = [&data](const ElfFileSymbol& sym) { - if (sym.is_func) { - Symbol symbol; - symbol.name = sym.name; - symbol.length = sym.len; - if (sym.len == 0) { - LOG(ERROR) << "Symbol size is zero for " << sym.name; + // See whether it's an ELF file. + { + SymbolMap elf_data; + auto callback = [&elf_data](const ElfFileSymbol& sym) { + if (sym.is_func) { + if (sym.len == 0) { + LOG(ERROR) << "Symbol size is zero for " << sym.name; + } + elf_data.emplace(sym.vaddr, Symbol(sym.name, sym.len)); } - data.emplace(sym.vaddr, std::move(symbol)); + }; + ElfStatus status = ParseSymbolsFromElfFile(dso, BuildId(), callback); + if (status == ElfStatus::NO_ERROR) { + dsos.emplace(dso, std::move(elf_data)); + return; + } + } + + // See whether it's a vdex file. + { + ::art::MemMap::Init(); + + using VdexFile = ::art::VdexFile; + std::string error_msg; + std::unique_ptr vdex = VdexFile::Open(dso, + /* writable= */ false, + /* low_4gb= */ false, + /* unquicken= */ false, + &error_msg); + if (vdex != nullptr) { + const uint8_t* cur = nullptr; + std::vector dex_file_offsets; + const uint8_t* base = vdex->Begin(); + for (;;) { + cur = vdex->GetNextDexFileData(cur); + if (cur == nullptr) { + break; + } + dex_file_offsets.push_back(cur - base); + } + + if (!dex_file_offsets.empty()) { + std::vector symbols; + if (ReadSymbolsFromDexFile(dso, dex_file_offsets, &symbols)) { + SymbolMap vdex_data; + for (const DexFileSymbol& symbol : symbols) { + vdex_data.emplace(symbol.offset, Symbol(symbol.name, symbol.len)); + } + dsos.emplace(dso, std::move(vdex_data)); + LOG(INFO) << "Found " << symbols.size() << " dex symbols in " << dso; + return; + } else { + LOG(WARNING) << "Could not read symbols from dex files in " << dso; + } + } else { + LOG(WARNING) << "Could not find dex files for vdex " << dso; + dsos.emplace(dso, SymbolMap()); + } + } else { + LOG(WARNING) << dso << " is not a vdex: " << error_msg; } - }; - ElfStatus status = ParseSymbolsFromElfFile(dso, BuildId(), callback); - if (status != ElfStatus::NO_ERROR) { - LOG(WARNING) << "Could not parse dso " << dso << ": " << status; } - dsos.emplace(dso, std::move(data)); + + // TODO: See whether it's a dex file. + + // OK, give up. + LOG(WARNING) << "Could not symbolize " << dso; + dsos.emplace(dso, SymbolMap()); } bool GetMinExecutableVAddr(const std::string& dso, uint64_t* addr) override { ElfStatus status = ReadMinExecutableVirtualAddressFromElfFile(dso, BuildId(), addr); - return status == ElfStatus::NO_ERROR; + if (status != ElfStatus::NO_ERROR) { + return true; + } + + { + ::art::MemMap::Init(); + + using VdexFile = ::art::VdexFile; + std::string error_msg; + std::unique_ptr vdex = VdexFile::Open(dso, + /* writable= */ false, + /* low_4gb= */ false, + /* unquicken= */ false, + &error_msg); + if (vdex != nullptr) { + *addr = 0u; + return true; + } + } + + return false; } std::unordered_map dsos; -- cgit v1.2.3