Unit test for LocalBinaryIndexer
A future commit is going to slightly change the implementation of
LocalBinaryIndexer. This commit adds a simple unit test to make sure
that the behavior will not change.
Bug: 200136875
Change-Id: I5a8b6670248a5db376158855b56292b21fae1db1
diff --git a/src/profiling/symbolizer/elf.h b/src/profiling/symbolizer/elf.h
index e323d46..6b89076 100644
--- a/src/profiling/symbolizer/elf.h
+++ b/src/profiling/symbolizer/elf.h
@@ -38,11 +38,15 @@
constexpr auto ELFMAG1 = 'E';
constexpr auto ELFMAG2 = 'L';
constexpr auto ELFMAG3 = 'F';
+constexpr auto ELFDATA2LSB = 1;
+constexpr auto EV_CURRENT = 1;
constexpr auto EI_MAG0 = 0;
constexpr auto EI_MAG1 = 1;
constexpr auto EI_MAG2 = 2;
constexpr auto EI_MAG3 = 3;
constexpr auto EI_CLASS = 4;
+constexpr auto EI_DATA = 5;
+constexpr auto EI_VERSION = 6;
struct Elf32 {
using Addr = uint32_t;
diff --git a/src/profiling/symbolizer/local_symbolizer_unittest.cc b/src/profiling/symbolizer/local_symbolizer_unittest.cc
index b96d318..d52ed69 100644
--- a/src/profiling/symbolizer/local_symbolizer_unittest.cc
+++ b/src/profiling/symbolizer/local_symbolizer_unittest.cc
@@ -20,7 +20,11 @@
// This translation unit is built only on Linux and MacOS. See //gn/BUILD.gn.
#if PERFETTO_BUILDFLAG(PERFETTO_LOCAL_SYMBOLIZER)
+#include <cstddef>
+
+#include "src/base/test/tmp_dir_tree.h"
#include "src/base/test/utils.h"
+#include "src/profiling/symbolizer/elf.h"
#include "src/profiling/symbolizer/local_symbolizer.h"
#include "src/profiling/symbolizer/subprocess.h"
@@ -95,6 +99,75 @@
}
}
+// Creates a very simple ELF file content with the first 20 bytes of `build_id`
+// as build id (if build id is shorter the remainin bytes are zero).
+std::string CreateElfWithBuildId(const std::string& build_id) {
+ struct SimpleElf {
+ Elf64::Ehdr ehdr;
+ Elf64::Shdr shdr;
+ Elf64::Nhdr nhdr;
+ char note_name[4];
+ char note_desc[20];
+ } e;
+ memset(&e, 0, sizeof e);
+
+ e.ehdr.e_ident[EI_MAG0] = ELFMAG0;
+ e.ehdr.e_ident[EI_MAG1] = ELFMAG1;
+ e.ehdr.e_ident[EI_MAG2] = ELFMAG2;
+ e.ehdr.e_ident[EI_MAG3] = ELFMAG3;
+ e.ehdr.e_ident[EI_CLASS] = ELFCLASS64;
+ e.ehdr.e_ident[EI_DATA] = ELFDATA2LSB;
+ e.ehdr.e_ident[EI_VERSION] = EV_CURRENT;
+ e.ehdr.e_version = EV_CURRENT;
+ e.ehdr.e_shentsize = sizeof(Elf64::Shdr);
+ e.ehdr.e_shnum = 1;
+ e.ehdr.e_ehsize = sizeof e.ehdr;
+ e.ehdr.e_shoff = offsetof(SimpleElf, shdr);
+
+ e.shdr.sh_type = SHT_NOTE;
+ e.shdr.sh_offset = offsetof(SimpleElf, nhdr);
+
+ e.nhdr.n_type = NT_GNU_BUILD_ID;
+ e.nhdr.n_namesz = sizeof e.note_name;
+ e.nhdr.n_descsz = sizeof e.note_desc;
+ strcpy(e.note_name, "GNU");
+ memcpy(e.note_desc, build_id.c_str(),
+ std::min(build_id.size(), sizeof(e.note_desc)));
+
+ e.shdr.sh_size = offsetof(SimpleElf, note_desc) + sizeof(e.note_desc) -
+ offsetof(SimpleElf, nhdr);
+
+ return std::string(reinterpret_cast<const char*>(&e), sizeof e);
+}
+
+#if defined(MEMORY_SANITIZER)
+// fts_read() causes some error under msan.
+#define NOMSAN_SimpleTree DISABLED_SimpleTree
+#else
+#define NOMSAN_SimpleTree SimpleTree
+#endif
+TEST(LocalBinaryIndexerTest, NOMSAN_SimpleTree) {
+ base::TmpDirTree tmp;
+ tmp.AddDir("dir1");
+ tmp.AddFile("dir1/elf1", CreateElfWithBuildId("AAAAAAAAAAAAAAAAAAAA"));
+ tmp.AddFile("dir1/nonelf1", "OTHERDATA");
+ tmp.AddDir("dir2");
+ tmp.AddFile("dir2/elf1", CreateElfWithBuildId("BBBBBBBBBBBBBBBBBBBB"));
+ tmp.AddFile("dir2/nonelf1", "other text");
+
+ LocalBinaryIndexer indexer({tmp.path() + "/dir1", tmp.path() + "/dir2"});
+
+ base::Optional<FoundBinary> bin1 =
+ indexer.FindBinary("", "AAAAAAAAAAAAAAAAAAAA");
+ ASSERT_TRUE(bin1.has_value());
+ EXPECT_EQ(bin1.value().file_name, tmp.path() + "/dir1/elf1");
+
+ base::Optional<FoundBinary> bin2 =
+ indexer.FindBinary("", "BBBBBBBBBBBBBBBBBBBB");
+ ASSERT_TRUE(bin2.has_value());
+ EXPECT_EQ(bin2.value().file_name, tmp.path() + "/dir2/elf1");
+}
+
} // namespace
} // namespace profiling
} // namespace perfetto