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