Simpleperf: exclude meaningless labels in aarch64.
Also remove the use of <elf.h> because of its conflicts with llvm.
Bug: 19483574
Change-Id: I2cc6fcb3429aa986101e214dc39fabd920f254dd
diff --git a/simpleperf/read_elf.cpp b/simpleperf/read_elf.cpp
index 5fb94e5..4d41165 100644
--- a/simpleperf/read_elf.cpp
+++ b/simpleperf/read_elf.cpp
@@ -32,10 +32,11 @@
#pragma clang diagnostic pop
-#include <elf.h>
-
#include "utils.h"
+#define ELF_NOTE_GNU "GNU"
+#define NT_GNU_BUILD_ID 3
+
static bool GetBuildIdFromNoteSection(const char* section, size_t section_size, BuildId* build_id) {
const char* p = section;
const char* end = p + section_size;
@@ -77,7 +78,7 @@
bool GetBuildIdFromELFFile(const llvm::object::ELFFile<ELFT>* elf, BuildId* build_id) {
for (auto section_iterator = elf->begin_sections(); section_iterator != elf->end_sections();
++section_iterator) {
- if (section_iterator->sh_type == SHT_NOTE) {
+ if (section_iterator->sh_type == llvm::ELF::SHT_NOTE) {
auto contents = elf->getSectionContents(&*section_iterator);
if (contents.getError()) {
LOG(DEBUG) << "read note section error";
@@ -114,10 +115,19 @@
}
return result;
}
+
+bool IsArmMappingSymbol(const char* name) {
+ // Mapping symbols in arm, which are described in "ELF for ARM Architecture" and
+ // "ELF for ARM 64-bit Architecture". The regular expression to match mapping symbol
+ // is ^\$(a|d|t|x)(\..*)?$
+ return name[0] == '$' && strchr("adtx", name[1]) != nullptr && (name[2] == '\0' || name[2] == '.');
+}
+
template <class ELFT>
bool ParseSymbolsFromELFFile(const llvm::object::ELFFile<ELFT>* elf,
std::function<void(const ElfFileSymbol&)> callback) {
- bool is_arm = (elf->getHeader()->e_machine == EM_ARM);
+ bool is_arm = (elf->getHeader()->e_machine == llvm::ELF::EM_ARM ||
+ elf->getHeader()->e_machine == llvm::ELF::EM_AARCH64);
auto begin = elf->begin_symbols();
auto end = elf->end_symbols();
if (begin == end) {
@@ -158,16 +168,17 @@
}
symbol.len = elf_symbol.st_size;
int type = elf_symbol.getType();
- if (type == STT_FUNC) {
+ if (type == llvm::ELF::STT_FUNC) {
symbol.is_func = true;
- } else if (type == STT_NOTYPE) {
+ } else if (type == llvm::ELF::STT_NOTYPE) {
if (symbol.is_in_text_section) {
symbol.is_label = true;
-
- // Arm has meaningless labels like $t, $d, $x, exclude them.
if (is_arm) {
- size_t test_pos = (symbol.name.find(linker_prefix) == 0) ? linker_prefix.size() : 0;
- if (test_pos + 2 == symbol.name.size() && symbol.name[test_pos] == '$') {
+ // Remove mapping symbols in arm.
+ const char* p = (symbol.name.compare(0, linker_prefix.size(), linker_prefix) == 0)
+ ? symbol.name.c_str() + linker_prefix.size()
+ : symbol.name.c_str();
+ if (IsArmMappingSymbol(p)) {
symbol.is_label = false;
}
}
diff --git a/simpleperf/read_elf.h b/simpleperf/read_elf.h
index 487fc28..96eb2f3 100644
--- a/simpleperf/read_elf.h
+++ b/simpleperf/read_elf.h
@@ -39,4 +39,7 @@
bool ParseSymbolsFromElfFile(const std::string& filename,
std::function<void(const ElfFileSymbol&)> callback);
+// Expose the following functions for unit tests.
+bool IsArmMappingSymbol(const char* name);
+
#endif // SIMPLE_PERF_READ_ELF_H_
diff --git a/simpleperf/read_elf_test.cpp b/simpleperf/read_elf_test.cpp
index bc9ef73..c0ff660 100644
--- a/simpleperf/read_elf_test.cpp
+++ b/simpleperf/read_elf_test.cpp
@@ -36,3 +36,10 @@
ParseSymbolsFromElfFile(elf_file, std::bind(ParseSymbol, std::placeholders::_1, &result)));
ASSERT_TRUE(result);
}
+
+TEST(read_elf, arm_mapping_symbol) {
+ ASSERT_TRUE(IsArmMappingSymbol("$a"));
+ ASSERT_FALSE(IsArmMappingSymbol("$b"));
+ ASSERT_TRUE(IsArmMappingSymbol("$a.anything"));
+ ASSERT_FALSE(IsArmMappingSymbol("$a_no_dot"));
+}