Home | History | Annotate | Download | only in quipper
      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*>(&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