summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYabin Cui <yabinc@google.com>2016-07-06 18:29:00 -0700
committerYabin Cui <yabinc@google.com>2016-07-07 11:13:34 -0700
commit5783fa0c4ac6a3faaa9191c8f8e3f2b9dc2ae2f0 (patch)
treeef3558c7a7e54d6a1c0bba9140d94c867f480d8e
parent11615de8326ebec451e3011bf2875e811fddfcb2 (diff)
downloadextras-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.cpp34
-rw-r--r--simpleperf/read_elf_test.cpp7
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());
+}