• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
TEST(DsoTest,ReadsBuildId)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 
TEST(DsoTest,ReadsBuildId_MissingBuildid)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 
TEST(DsoTest,ReadsBuildId_WrongSection)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 
TEST(DsoTest,ReadsBuildId_PrefersGnuBuildid)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 
TEST(DsoTest,ReadsSysfsModuleBuildidNote)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*>(&note_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