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_test_utils.h"
6
7 #include <elf.h>
8 #include <fcntl.h>
9 #include <gelf.h>
10 #include <libelf.h>
11 #include <string.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 "binary_data_utils.h"
20
21 namespace quipper {
22 namespace testing {
23
24 namespace {
25
26 // Example string table:
27 // index 0: "\0"
28 // index 1: "value 1" "\0"
29 // index 9: "value 2" "\0"
30 // index 17: "value 3" "\0"
31 class ElfStringTable {
32 public:
ElfStringTable()33 ElfStringTable() : table_("", 1) {} // index 0 is the empty string.
34 // Returns the index to use in place of the string.
Add(string value)35 GElf_Word Add(string value) {
36 GElf_Word ret = table_.size();
37 table_.append(value.data(), value.size() + 1); // Include the '\0'.
38 return ret;
39 }
40
table()41 const string &table() { return table_; }
42
43 private:
44 string table_;
45 };
46
47 // Helper to control the scope of data in Elf_Data.d_buf added to a Elf_Scn.
48 // Basically, makes sure that the d_buf pointer remains valid, and holds on to a
49 // copy of your buffer so you don't have to.
50 class ElfDataCache {
51 public:
AddDataToSection(Elf_Scn * section,const string & data_str)52 Elf_Data *AddDataToSection(Elf_Scn *section, const string &data_str) {
53 Elf_Data *data = elf_newdata(section);
54 CHECK(data) << elf_errmsg(-1);
55 // avoid zero memory allocation
56 char *data_storage = new char[data_str.size() + 1];
57 cache_.emplace_back(data_storage);
58 memcpy(data_storage, data_str.data(), data_str.size());
59 data->d_buf = data_storage;
60 data->d_size = data_str.size();
61 return data;
62 }
63
~ElfDataCache()64 ~ElfDataCache() {
65 for (auto &s : cache_) {
66 delete[] s;
67 }
68 }
69
70 private:
71 std::vector<char *> cache_;
72 };
73
74 } // namespace
75
WriteElfWithBuildid(string filename,string section_name,string buildid)76 void WriteElfWithBuildid(string filename, string section_name, string buildid) {
77 std::vector<std::pair<string, string>> section_name_to_buildid{
78 std::make_pair(section_name, buildid)};
79 WriteElfWithMultipleBuildids(filename, section_name_to_buildid);
80 }
81
WriteElfWithMultipleBuildids(string filename,const std::vector<std::pair<string,string>> section_buildids)82 void WriteElfWithMultipleBuildids(
83 string filename,
84 const std::vector<std::pair<string, string>> section_buildids) {
85 int fd = open(filename.data(), O_WRONLY | O_CREAT | O_TRUNC, 0660);
86 CHECK_GE(fd, 0) << strerror(errno);
87
88 // ANDROID-CHANGED: Ensure libelf is initialized, as dso_android doesn't.
89 {
90 const unsigned int kElfVersionNone = EV_NONE; // correctly typed.
91 CHECK_NE(kElfVersionNone, elf_version(EV_CURRENT)) << elf_errmsg(-1);
92 }
93
94 Elf *elf = elf_begin(fd, ELF_C_WRITE, nullptr);
95 CHECK(elf) << elf_errmsg(-1);
96 Elf64_Ehdr *elf_header = elf64_newehdr(elf);
97 CHECK(elf_header) << elf_errmsg(-1);
98 elf_header->e_ident[EI_DATA] = ELFDATA2LSB;
99 elf_header->e_machine = EM_X86_64;
100 elf_header->e_version = EV_CURRENT;
101 CHECK(elf_update(elf, ELF_C_NULL) > 0) << elf_errmsg(-1);
102
103 ElfStringTable string_table;
104 ElfDataCache data_cache;
105
106 // Note section(s)
107 for (const auto &entry : section_buildids) {
108 const string §ion_name = entry.first;
109 const string &buildid = entry.second;
110 Elf_Scn *section = elf_newscn(elf);
111 CHECK(section) << elf_errmsg(-1);
112 GElf_Shdr section_header;
113 CHECK(gelf_getshdr(section, §ion_header)) << elf_errmsg(-1);
114 section_header.sh_name = string_table.Add(section_name);
115 section_header.sh_type = SHT_NOTE;
116 CHECK(gelf_update_shdr(section, §ion_header)) << elf_errmsg(-1);
117
118 string note_name = ELF_NOTE_GNU;
119 GElf_Nhdr note_header;
120 note_header.n_namesz = Align<4>(note_name.size());
121 note_header.n_descsz = Align<4>(buildid.size());
122 note_header.n_type = NT_GNU_BUILD_ID;
123 string data_str;
124 data_str.append(reinterpret_cast<char *>(¬e_header),
125 sizeof(note_header));
126 data_str.append(note_name);
127 data_str.append(string(note_header.n_namesz - note_name.size(), '\0'));
128 data_str.append(buildid);
129 data_str.append(string(note_header.n_descsz - buildid.size(), '\0'));
130 Elf_Data *data = data_cache.AddDataToSection(section, data_str);
131 data->d_type = ELF_T_NHDR;
132 }
133
134 // String table section
135 {
136 Elf_Scn *section = elf_newscn(elf);
137 CHECK(section) << elf_errmsg(-1);
138 GElf_Shdr section_header;
139 CHECK(gelf_getshdr(section, §ion_header)) << elf_errmsg(-1);
140 section_header.sh_name = string_table.Add(".shstrtab");
141 section_header.sh_type = SHT_STRTAB;
142 CHECK(gelf_update_shdr(section, §ion_header)) << elf_errmsg(-1);
143 Elf_Data *data = data_cache.AddDataToSection(section, string_table.table());
144 data->d_type = ELF_T_BYTE;
145
146 elf_header->e_shstrndx = elf_ndxscn(section);
147 }
148
149 CHECK(elf_update(elf, ELF_C_WRITE) > 0) << elf_errmsg(-1);
150 elf_end(elf);
151
152 close(fd);
153 }
154
155 } // namespace testing
156 } // namespace quipper
157