diff options
author | Yabin Cui <yabinc@google.com> | 2016-07-06 18:29:00 -0700 |
---|---|---|
committer | Yabin Cui <yabinc@google.com> | 2016-07-07 11:13:34 -0700 |
commit | 5783fa0c4ac6a3faaa9191c8f8e3f2b9dc2ae2f0 (patch) | |
tree | ef3558c7a7e54d6a1c0bba9140d94c867f480d8e | |
parent | 11615de8326ebec451e3011bf2875e811fddfcb2 (diff) | |
download | extras-5783fa0c4ac6a3faaa9191c8f8e3f2b9dc2ae2f0.tar.gz |
simpleperf: add symbol for .plt section.
This avoid reporting unknown symbols when there are samples in .plt section.
Bug: 28911532
Test: run simpleperf_unit_test.
Change-Id: I62cb08776c99951ff845e98f0f601859d25ece5c
-rw-r--r-- | simpleperf/read_elf.cpp | 34 | ||||
-rw-r--r-- | simpleperf/read_elf_test.cpp | 7 |
2 files changed, 41 insertions, 0 deletions
diff --git a/simpleperf/read_elf.cpp b/simpleperf/read_elf.cpp index f59ec37a..51b85b64 100644 --- a/simpleperf/read_elf.cpp +++ b/simpleperf/read_elf.cpp @@ -301,6 +301,39 @@ void ReadSymbolTable(llvm::object::symbol_iterator sym_begin, } template <class ELFT> +void AddSymbolForPltSection(const llvm::object::ELFObjectFile<ELFT>* elf, + std::function<void(const ElfFileSymbol&)> callback) { + // We may sample instructions in .plt section if the program + // calls functions from shared libraries. Different architectures use + // different formats to store .plt section, so it needs a lot of work to match + // instructions in .plt section to symbols. As samples in .plt section rarely + // happen, and .plt section can hardly be a performance bottleneck, we can + // just use a symbol @plt to represent instructions in .plt section. + for (auto it = elf->section_begin(); it != elf->section_end(); ++it) { + const llvm::object::ELFSectionRef& section_ref = *it; + llvm::StringRef section_name; + std::error_code err = section_ref.getName(section_name); + if (err || section_name != ".plt") { + continue; + } + const auto* shdr = elf->getSection(section_ref.getRawDataRefImpl()); + if (shdr == nullptr) { + return; + } + ElfFileSymbol symbol; + symbol.vaddr = shdr->sh_addr; + symbol.len = shdr->sh_size; + symbol.is_func = true; + symbol.is_label = true; + symbol.is_in_text_section = true; + symbol.name = "@plt"; + callback(symbol); + return; + } +} + + +template <class ELFT> void ParseSymbolsFromELFFile(const llvm::object::ELFObjectFile<ELFT>* elf, std::function<void(const ElfFileSymbol&)> callback) { auto machine = elf->getELFFile()->getHeader()->e_machine; @@ -310,6 +343,7 @@ void ParseSymbolsFromELFFile(const llvm::object::ELFObjectFile<ELFT>* elf, } else if (elf->dynamic_symbol_begin()->getRawDataRefImpl() != llvm::object::DataRefImpl()) { ReadSymbolTable(elf->dynamic_symbol_begin(), elf->dynamic_symbol_end(), callback, is_arm); } + AddSymbolForPltSection(elf, callback); std::string debugdata; if (ReadSectionFromELFFile(elf, ".gnu_debugdata", &debugdata, false)) { LOG(VERBOSE) << "Read .gnu_debugdata from " << elf->getFileName().str(); diff --git a/simpleperf/read_elf_test.cpp b/simpleperf/read_elf_test.cpp index f2649e00..5669d279 100644 --- a/simpleperf/read_elf_test.cpp +++ b/simpleperf/read_elf_test.cpp @@ -105,3 +105,10 @@ TEST(read_elf, IsValidElfPath) { ASSERT_FALSE(IsValidElfPath("/sys/devices/system/cpu/online")); ASSERT_TRUE(IsValidElfPath(GetTestData(ELF_FILE))); } + +TEST(read_elf, check_symbol_for_plt_section) { + std::map<std::string, ElfFileSymbol> symbols; + ASSERT_TRUE(ParseSymbolsFromElfFile(GetTestData(ELF_FILE), BuildId(), + std::bind(ParseSymbol, std::placeholders::_1, &symbols))); + ASSERT_NE(symbols.find("@plt"), symbols.end()); +} |