1 // Copyright 2016 The Chromium OS 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 5 #include "dso.h" 6 7 #include <elf.h> 8 #include <fcntl.h> 9 #include <gelf.h> 10 #include <libelf.h> 11 #include <stdlib.h> 12 #include <sys/stat.h> 13 #include <sys/types.h> 14 #include <unistd.h> 15 16 #include <vector> 17 18 #include "base/logging.h" 19 #include "buffer_reader.h" 20 #include "compat/string.h" 21 #include "compat/test.h" 22 #include "dso_test_utils.h" 23 #include "scoped_temp_path.h" 24 25 namespace quipper { 26 27 TEST(DsoTest, ReadsBuildId) { 28 InitializeLibelf(); 29 ScopedTempFile elf("/tmp/tempelf."); 30 31 const string expected_buildid = "\xde\xad\xf0\x0d"; 32 testing::WriteElfWithBuildid(elf.path(), ".note.gnu.build-id", 33 expected_buildid); 34 35 string buildid; 36 EXPECT_TRUE(ReadElfBuildId(elf.path(), &buildid)); 37 EXPECT_EQ(expected_buildid, buildid); 38 39 // Repeat with other spellings of the section name: 40 41 testing::WriteElfWithBuildid(elf.path(), ".notes", expected_buildid); 42 EXPECT_TRUE(ReadElfBuildId(elf.path(), &buildid)); 43 EXPECT_EQ(expected_buildid, buildid); 44 45 testing::WriteElfWithBuildid(elf.path(), ".note", expected_buildid); 46 EXPECT_TRUE(ReadElfBuildId(elf.path(), &buildid)); 47 EXPECT_EQ(expected_buildid, buildid); 48 } 49 50 TEST(DsoTest, ReadsBuildId_MissingBuildid) { 51 InitializeLibelf(); 52 ScopedTempFile elf("/tmp/tempelf."); 53 54 testing::WriteElfWithMultipleBuildids(elf.path(), {/*empty*/}); 55 56 string buildid; 57 EXPECT_FALSE(ReadElfBuildId(elf.path(), &buildid)); 58 } 59 60 TEST(DsoTest, ReadsBuildId_WrongSection) { 61 InitializeLibelf(); 62 ScopedTempFile elf("/tmp/tempelf."); 63 64 testing::WriteElfWithBuildid(elf.path(), ".unexpected-section", "blah"); 65 66 string buildid; 67 EXPECT_FALSE(ReadElfBuildId(elf.path(), &buildid)); 68 } 69 70 TEST(DsoTest, ReadsBuildId_PrefersGnuBuildid) { 71 InitializeLibelf(); 72 ScopedTempFile elf("/tmp/tempelf."); 73 74 const string buildid_gnu = "\xde\xad\xf0\x0d"; 75 const string buildid_notes = "\xc0\xde\xf0\x0d"; 76 const string buildid_note = "\xfe\xed\xba\xad"; 77 78 std::vector<std::pair<string, string>> section_buildids{ 79 std::make_pair(".notes", buildid_notes), 80 std::make_pair(".note", buildid_note), 81 std::make_pair(".note.gnu.build-id", buildid_gnu), 82 }; 83 testing::WriteElfWithMultipleBuildids(elf.path(), section_buildids); 84 85 string buildid; 86 EXPECT_TRUE(ReadElfBuildId(elf.path(), &buildid)); 87 EXPECT_EQ(buildid_gnu, buildid); 88 89 // Also prefer ".notes" over ".note" 90 section_buildids = { 91 std::make_pair(".note", buildid_note), 92 std::make_pair(".notes", buildid_notes), 93 }; 94 testing::WriteElfWithMultipleBuildids(elf.path(), section_buildids); 95 96 EXPECT_TRUE(ReadElfBuildId(elf.path(), &buildid)); 97 EXPECT_EQ(buildid_notes, buildid); 98 } 99 100 TEST(DsoTest, ReadsSysfsModuleBuildidNote) { 101 // Mimic contents of a /sys/module/<name>/notes/.note.gnu.build-id file. 102 const size_t namesz = 4; 103 const size_t descsz = 0x14; 104 const GElf_Nhdr note_header = { 105 .n_namesz = namesz, 106 .n_descsz = descsz, 107 .n_type = NT_GNU_BUILD_ID, 108 }; 109 110 const char note_name[namesz] = ELF_NOTE_GNU; 111 const char note_desc[descsz]{ 112 // Note \0 here. This is not null-terminated. 113 '\x1c', '\0', '\x69', '\x27', '\x15', '\x26', '\x6b', 114 '\xe7', '\xcc', '\x69', '\x2c', '\x12', '\xe8', '\x09', 115 '\x20', '\x18', '\x03', '\x5b', '\xb6', '\x4f', 116 }; 117 118 string data; 119 data.append(reinterpret_cast<const char*>(¬e_header), sizeof(note_header)); 120 data.append(note_name, sizeof(note_name)); 121 data.append(note_desc, sizeof(note_desc)); 122 123 ASSERT_EQ(0x24, data.size()) << "Sanity"; 124 125 BufferReader data_reader(data.data(), data.size()); 126 string buildid; 127 EXPECT_TRUE(ReadBuildIdNote(&data_reader, &buildid)); 128 EXPECT_EQ(string(note_desc, sizeof(note_desc)), buildid); 129 } 130 131 } // namespace quipper 132