elf_reader_unittest.cc 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. // Copyright 2018 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "base/debug/elf_reader.h"
  5. #include <dlfcn.h>
  6. #include <cstdint>
  7. #include "base/debug/test_elf_image_builder.h"
  8. #include "base/files/memory_mapped_file.h"
  9. #include "base/native_library.h"
  10. #include "base/strings/string_util.h"
  11. #include "build/build_config.h"
  12. #include "testing/gtest/include/gtest/gtest.h"
  13. #include "third_party/abseil-cpp/absl/types/optional.h"
  14. extern char __executable_start;
  15. namespace base {
  16. namespace debug {
  17. namespace {
  18. constexpr uint8_t kBuildIdBytes[] = {0xab, 0xcd, 0x12, 0x34};
  19. constexpr const char kBuildIdHexString[] = "ABCD1234";
  20. constexpr const char kBuildIdHexStringLower[] = "ABCD1234";
  21. std::string ParamInfoToString(
  22. const ::testing::TestParamInfo<base::TestElfImageBuilder::MappingType>&
  23. param_info) {
  24. switch (param_info.param) {
  25. case TestElfImageBuilder::RELOCATABLE:
  26. return "Relocatable";
  27. case TestElfImageBuilder::RELOCATABLE_WITH_BIAS:
  28. return "RelocatableWithBias";
  29. case TestElfImageBuilder::NON_RELOCATABLE:
  30. return "NonRelocatable";
  31. }
  32. }
  33. } // namespace
  34. using ElfReaderTest =
  35. ::testing::TestWithParam<TestElfImageBuilder::MappingType>;
  36. TEST_P(ElfReaderTest, ReadElfBuildIdUppercase) {
  37. TestElfImage image =
  38. TestElfImageBuilder(GetParam())
  39. .AddLoadSegment(PF_R | PF_X, /* size = */ 2000)
  40. .AddNoteSegment(NT_GNU_BUILD_ID, "GNU", kBuildIdBytes)
  41. .Build();
  42. ElfBuildIdBuffer build_id;
  43. size_t build_id_size = ReadElfBuildId(image.elf_start(), true, build_id);
  44. EXPECT_EQ(8u, build_id_size);
  45. EXPECT_EQ(kBuildIdHexString, StringPiece(&build_id[0], build_id_size));
  46. }
  47. TEST_P(ElfReaderTest, ReadElfBuildIdLowercase) {
  48. TestElfImage image =
  49. TestElfImageBuilder(GetParam())
  50. .AddLoadSegment(PF_R | PF_X, /* size = */ 2000)
  51. .AddNoteSegment(NT_GNU_BUILD_ID, "GNU", kBuildIdBytes)
  52. .Build();
  53. ElfBuildIdBuffer build_id;
  54. size_t build_id_size = ReadElfBuildId(image.elf_start(), false, build_id);
  55. EXPECT_EQ(8u, build_id_size);
  56. EXPECT_EQ(ToLowerASCII(kBuildIdHexStringLower),
  57. StringPiece(&build_id[0], build_id_size));
  58. }
  59. TEST_P(ElfReaderTest, ReadElfBuildIdMultipleNotes) {
  60. constexpr uint8_t kOtherNoteBytes[] = {0xef, 0x56};
  61. TestElfImage image =
  62. TestElfImageBuilder(GetParam())
  63. .AddLoadSegment(PF_R | PF_X, /* size = */ 2000)
  64. .AddNoteSegment(NT_GNU_BUILD_ID + 1, "ABC", kOtherNoteBytes)
  65. .AddNoteSegment(NT_GNU_BUILD_ID, "GNU", kBuildIdBytes)
  66. .Build();
  67. ElfBuildIdBuffer build_id;
  68. size_t build_id_size = ReadElfBuildId(image.elf_start(), true, build_id);
  69. EXPECT_EQ(8u, build_id_size);
  70. EXPECT_EQ(kBuildIdHexString, StringPiece(&build_id[0], build_id_size));
  71. }
  72. TEST_P(ElfReaderTest, ReadElfBuildIdWrongName) {
  73. TestElfImage image =
  74. TestElfImageBuilder(GetParam())
  75. .AddLoadSegment(PF_R | PF_X, /* size = */ 2000)
  76. .AddNoteSegment(NT_GNU_BUILD_ID, "ABC", kBuildIdBytes)
  77. .Build();
  78. ElfBuildIdBuffer build_id;
  79. size_t build_id_size = ReadElfBuildId(image.elf_start(), true, build_id);
  80. EXPECT_EQ(0u, build_id_size);
  81. }
  82. TEST_P(ElfReaderTest, ReadElfBuildIdWrongType) {
  83. TestElfImage image =
  84. TestElfImageBuilder(GetParam())
  85. .AddLoadSegment(PF_R | PF_X, /* size = */ 2000)
  86. .AddNoteSegment(NT_GNU_BUILD_ID + 1, "GNU", kBuildIdBytes)
  87. .Build();
  88. ElfBuildIdBuffer build_id;
  89. size_t build_id_size = ReadElfBuildId(image.elf_start(), true, build_id);
  90. EXPECT_EQ(0u, build_id_size);
  91. }
  92. TEST_P(ElfReaderTest, ReadElfBuildIdNoBuildId) {
  93. TestElfImage image = TestElfImageBuilder(GetParam())
  94. .AddLoadSegment(PF_R | PF_X, /* size = */ 2000)
  95. .Build();
  96. ElfBuildIdBuffer build_id;
  97. size_t build_id_size = ReadElfBuildId(image.elf_start(), true, build_id);
  98. EXPECT_EQ(0u, build_id_size);
  99. }
  100. TEST_P(ElfReaderTest, ReadElfLibraryName) {
  101. TestElfImage image = TestElfImageBuilder(GetParam())
  102. .AddLoadSegment(PF_R | PF_X, /* size = */ 2000)
  103. .AddSoName("mysoname")
  104. .Build();
  105. absl::optional<StringPiece> library_name =
  106. ReadElfLibraryName(image.elf_start());
  107. ASSERT_NE(absl::nullopt, library_name);
  108. EXPECT_EQ("mysoname", *library_name);
  109. }
  110. TEST_P(ElfReaderTest, ReadElfLibraryNameNoSoName) {
  111. TestElfImage image = TestElfImageBuilder(GetParam())
  112. .AddLoadSegment(PF_R | PF_X, /* size = */ 2000)
  113. .Build();
  114. absl::optional<StringPiece> library_name =
  115. ReadElfLibraryName(image.elf_start());
  116. EXPECT_EQ(absl::nullopt, library_name);
  117. }
  118. TEST_P(ElfReaderTest, GetRelocationOffset) {
  119. TestElfImage image = TestElfImageBuilder(GetParam())
  120. .AddLoadSegment(PF_R | PF_X, /* size = */ 2000)
  121. .Build();
  122. switch (GetParam()) {
  123. case TestElfImageBuilder::RELOCATABLE:
  124. EXPECT_EQ(reinterpret_cast<size_t>(image.elf_start()),
  125. GetRelocationOffset(image.elf_start()));
  126. break;
  127. case TestElfImageBuilder::RELOCATABLE_WITH_BIAS:
  128. EXPECT_EQ(reinterpret_cast<size_t>(image.elf_start()) -
  129. TestElfImageBuilder::kLoadBias,
  130. GetRelocationOffset(image.elf_start()));
  131. break;
  132. case TestElfImageBuilder::NON_RELOCATABLE:
  133. EXPECT_EQ(0u, GetRelocationOffset(image.elf_start()));
  134. break;
  135. }
  136. }
  137. INSTANTIATE_TEST_SUITE_P(
  138. MappingTypes,
  139. ElfReaderTest,
  140. ::testing::Values(TestElfImageBuilder::RELOCATABLE,
  141. TestElfImageBuilder::RELOCATABLE_WITH_BIAS,
  142. TestElfImageBuilder::NON_RELOCATABLE),
  143. &ParamInfoToString);
  144. TEST(ElfReaderTestWithCurrentElfImage, ReadElfBuildId) {
  145. ElfBuildIdBuffer build_id;
  146. size_t build_id_size = ReadElfBuildId(&__executable_start, true, build_id);
  147. ASSERT_NE(build_id_size, 0u);
  148. #if defined(OFFICIAL_BUILD)
  149. constexpr size_t kExpectedBuildIdStringLength = 40; // SHA1 hash in hex.
  150. #else
  151. constexpr size_t kExpectedBuildIdStringLength = 16; // 64-bit int in hex.
  152. #endif
  153. EXPECT_EQ(kExpectedBuildIdStringLength, build_id_size);
  154. for (size_t i = 0; i < build_id_size; ++i) {
  155. char c = build_id[i];
  156. EXPECT_TRUE(IsHexDigit(c));
  157. EXPECT_FALSE(IsAsciiLower(c));
  158. }
  159. }
  160. TEST(ElfReaderTestWithCurrentImage, ReadElfBuildId) {
  161. #if BUILDFLAG(IS_ANDROID)
  162. // On Android the library loader memory maps the full so file.
  163. const char kLibraryName[] = "libbase_unittests__library";
  164. const void* addr = &__executable_start;
  165. #else
  166. const char kLibraryName[] = MALLOC_WRAPPER_LIB;
  167. // On Linux the executable does not contain soname and is not mapped till
  168. // dynamic segment. So, use malloc wrapper so file on which the test already
  169. // depends on.
  170. // Find any symbol in the loaded file.
  171. //
  172. NativeLibraryLoadError error;
  173. NativeLibrary library =
  174. LoadNativeLibrary(base::FilePath(kLibraryName), &error);
  175. void* init_addr =
  176. GetFunctionPointerFromNativeLibrary(library, "MallocWrapper");
  177. // Use this symbol to get full path to the loaded library.
  178. Dl_info info;
  179. int res = dladdr(init_addr, &info);
  180. ASSERT_NE(0, res);
  181. const void* addr = info.dli_fbase;
  182. #endif
  183. auto name = ReadElfLibraryName(addr);
  184. ASSERT_TRUE(name);
  185. EXPECT_NE(std::string::npos, name->find(kLibraryName))
  186. << "Library name " << *name << " doesn't contain expected "
  187. << kLibraryName;
  188. #if !BUILDFLAG(IS_ANDROID)
  189. UnloadNativeLibrary(library);
  190. #endif
  191. }
  192. } // namespace debug
  193. } // namespace base