|
1 #include "common/linux/synth_elf.h" |
|
2 |
|
3 #include <assert.h> |
|
4 #include <elf.h> |
|
5 #include <stdio.h> |
|
6 #include <string.h> |
|
7 |
|
8 #include "common/using_std_string.h" |
|
9 |
|
10 namespace google_breakpad { |
|
11 namespace synth_elf { |
|
12 |
|
13 #ifndef NT_GNU_BUILD_ID |
|
14 #define NT_GNU_BUILD_ID 3 |
|
15 #endif |
|
16 |
|
17 ELF::ELF(uint16_t machine, |
|
18 uint8_t file_class, |
|
19 Endianness endianness) |
|
20 : Section(endianness), |
|
21 addr_size_(file_class == ELFCLASS64 ? 8 : 4), |
|
22 program_count_(0), |
|
23 program_header_table_(endianness), |
|
24 section_count_(0), |
|
25 section_header_table_(endianness), |
|
26 section_header_strings_(endianness) { |
|
27 // Could add support for more machine types here if needed. |
|
28 assert(machine == EM_386 || |
|
29 machine == EM_X86_64 || |
|
30 machine == EM_ARM); |
|
31 assert(file_class == ELFCLASS32 || file_class == ELFCLASS64); |
|
32 |
|
33 start() = 0; |
|
34 // Add ELF header |
|
35 // e_ident |
|
36 // EI_MAG0...EI_MAG3 |
|
37 D8(ELFMAG0); |
|
38 D8(ELFMAG1); |
|
39 D8(ELFMAG2); |
|
40 D8(ELFMAG3); |
|
41 // EI_CLASS |
|
42 D8(file_class); |
|
43 // EI_DATA |
|
44 D8(endianness == kLittleEndian ? ELFDATA2LSB : ELFDATA2MSB); |
|
45 // EI_VERSION |
|
46 D8(EV_CURRENT); |
|
47 // EI_OSABI |
|
48 D8(ELFOSABI_SYSV); |
|
49 // EI_ABIVERSION |
|
50 D8(0); |
|
51 // EI_PAD |
|
52 Append(7, 0); |
|
53 assert(Size() == EI_NIDENT); |
|
54 |
|
55 // e_type |
|
56 D16(ET_EXEC); //TODO: allow passing ET_DYN? |
|
57 // e_machine |
|
58 D16(machine); |
|
59 // e_version |
|
60 D32(EV_CURRENT); |
|
61 // e_entry |
|
62 Append(endianness, addr_size_, 0); |
|
63 // e_phoff |
|
64 Append(endianness, addr_size_, program_header_label_); |
|
65 // e_shoff |
|
66 Append(endianness, addr_size_, section_header_label_); |
|
67 // e_flags |
|
68 D32(0); |
|
69 // e_ehsize |
|
70 D16(addr_size_ == 8 ? sizeof(Elf64_Ehdr) : sizeof(Elf32_Ehdr)); |
|
71 // e_phentsize |
|
72 D16(addr_size_ == 8 ? sizeof(Elf64_Phdr) : sizeof(Elf32_Phdr)); |
|
73 // e_phnum |
|
74 D16(program_count_label_); |
|
75 // e_shentsize |
|
76 D16(addr_size_ == 8 ? sizeof(Elf64_Shdr) : sizeof(Elf32_Shdr)); |
|
77 // e_shnum |
|
78 D16(section_count_label_); |
|
79 // e_shstrndx |
|
80 D16(section_header_string_index_); |
|
81 |
|
82 // Add an empty section for SHN_UNDEF. |
|
83 Section shn_undef; |
|
84 AddSection("", shn_undef, SHT_NULL); |
|
85 } |
|
86 |
|
87 int ELF::AddSection(const string& name, const Section& section, |
|
88 uint32_t type, uint32_t flags, uint64_t addr, |
|
89 uint32_t link, uint64_t entsize, uint64_t offset) { |
|
90 Label offset_label; |
|
91 Label string_label(section_header_strings_.Add(name)); |
|
92 size_t size = section.Size(); |
|
93 |
|
94 int index = section_count_; |
|
95 ++section_count_; |
|
96 |
|
97 section_header_table_ |
|
98 // sh_name |
|
99 .D32(string_label) |
|
100 // sh_type |
|
101 .D32(type) |
|
102 // sh_flags |
|
103 .Append(endianness(), addr_size_, flags) |
|
104 // sh_addr |
|
105 .Append(endianness(), addr_size_, addr) |
|
106 // sh_offset |
|
107 .Append(endianness(), addr_size_, offset_label) |
|
108 // sh_size |
|
109 .Append(endianness(), addr_size_, size) |
|
110 // sh_link |
|
111 .D32(link) |
|
112 // sh_info |
|
113 .D32(0) |
|
114 // sh_addralign |
|
115 .Append(endianness(), addr_size_, 0) |
|
116 // sh_entsize |
|
117 .Append(endianness(), addr_size_, entsize); |
|
118 |
|
119 sections_.push_back(ElfSection(section, type, addr, offset, offset_label, |
|
120 size)); |
|
121 return index; |
|
122 } |
|
123 |
|
124 void ELF::AppendSection(ElfSection §ion) { |
|
125 // NULL and NOBITS sections have no content, so they |
|
126 // don't need to be written to the file. |
|
127 if (section.type_ == SHT_NULL) { |
|
128 section.offset_label_ = 0; |
|
129 } else if (section.type_ == SHT_NOBITS) { |
|
130 section.offset_label_ = section.offset_; |
|
131 } else { |
|
132 Mark(§ion.offset_label_); |
|
133 Append(section); |
|
134 Align(4); |
|
135 } |
|
136 } |
|
137 |
|
138 void ELF::AddSegment(int start, int end, uint32_t type, uint32_t flags) { |
|
139 assert(start > 0); |
|
140 assert(size_t(start) < sections_.size()); |
|
141 assert(end > 0); |
|
142 assert(size_t(end) < sections_.size()); |
|
143 ++program_count_; |
|
144 |
|
145 // p_type |
|
146 program_header_table_.D32(type); |
|
147 |
|
148 if (addr_size_ == 8) { |
|
149 // p_flags |
|
150 program_header_table_.D32(flags); |
|
151 } |
|
152 |
|
153 size_t filesz = 0; |
|
154 size_t memsz = 0; |
|
155 bool prev_was_nobits = false; |
|
156 for (int i = start; i <= end; ++i) { |
|
157 size_t size = sections_[i].size_; |
|
158 if (sections_[i].type_ != SHT_NOBITS) { |
|
159 assert(!prev_was_nobits); |
|
160 // non SHT_NOBITS sections are 4-byte aligned (see AddSection) |
|
161 size = (size + 3) & ~3; |
|
162 filesz += size; |
|
163 } else { |
|
164 prev_was_nobits = true; |
|
165 } |
|
166 memsz += size; |
|
167 } |
|
168 |
|
169 program_header_table_ |
|
170 // p_offset |
|
171 .Append(endianness(), addr_size_, sections_[start].offset_label_) |
|
172 // p_vaddr |
|
173 .Append(endianness(), addr_size_, sections_[start].addr_) |
|
174 // p_paddr |
|
175 .Append(endianness(), addr_size_, sections_[start].addr_) |
|
176 // p_filesz |
|
177 .Append(endianness(), addr_size_, filesz) |
|
178 // p_memsz |
|
179 .Append(endianness(), addr_size_, memsz); |
|
180 |
|
181 if (addr_size_ == 4) { |
|
182 // p_flags |
|
183 program_header_table_.D32(flags); |
|
184 } |
|
185 |
|
186 // p_align |
|
187 program_header_table_.Append(endianness(), addr_size_, 0); |
|
188 } |
|
189 |
|
190 void ELF::Finish() { |
|
191 // Add the section header string table at the end. |
|
192 section_header_string_index_ = section_count_; |
|
193 //printf(".shstrtab size: %ld\n", section_header_strings_.Size()); |
|
194 AddSection(".shstrtab", section_header_strings_, SHT_STRTAB); |
|
195 //printf("section_count_: %ld, sections_.size(): %ld\n", |
|
196 // section_count_, sections_.size()); |
|
197 if (program_count_) { |
|
198 Mark(&program_header_label_); |
|
199 Append(program_header_table_); |
|
200 } else { |
|
201 program_header_label_ = 0; |
|
202 } |
|
203 |
|
204 for (vector<ElfSection>::iterator it = sections_.begin(); |
|
205 it < sections_.end(); ++it) { |
|
206 AppendSection(*it); |
|
207 } |
|
208 section_count_label_ = section_count_; |
|
209 program_count_label_ = program_count_; |
|
210 |
|
211 // Section header table starts here. |
|
212 Mark(§ion_header_label_); |
|
213 Append(section_header_table_); |
|
214 } |
|
215 |
|
216 SymbolTable::SymbolTable(Endianness endianness, |
|
217 size_t addr_size, |
|
218 StringTable& table) : Section(endianness), |
|
219 addr_size_(addr_size), |
|
220 table_(table) { |
|
221 assert(addr_size_ == 4 || addr_size_ == 8); |
|
222 } |
|
223 |
|
224 void SymbolTable::AddSymbol(const string& name, uint32_t value, |
|
225 uint32_t size, unsigned info, uint16_t shndx) { |
|
226 assert(addr_size_ == 4); |
|
227 D32(table_.Add(name)); |
|
228 D32(value); |
|
229 D32(size); |
|
230 D8(info); |
|
231 D8(0); // other |
|
232 D16(shndx); |
|
233 } |
|
234 |
|
235 void SymbolTable::AddSymbol(const string& name, uint64_t value, |
|
236 uint64_t size, unsigned info, uint16_t shndx) { |
|
237 assert(addr_size_ == 8); |
|
238 D32(table_.Add(name)); |
|
239 D8(info); |
|
240 D8(0); // other |
|
241 D16(shndx); |
|
242 D64(value); |
|
243 D64(size); |
|
244 } |
|
245 |
|
246 void Notes::AddNote(int type, const string &name, const uint8_t* desc_bytes, |
|
247 size_t desc_size) { |
|
248 // Elf32_Nhdr and Elf64_Nhdr are exactly the same. |
|
249 Elf32_Nhdr note_header; |
|
250 memset(¬e_header, 0, sizeof(note_header)); |
|
251 note_header.n_namesz = name.length() + 1; |
|
252 note_header.n_descsz = desc_size; |
|
253 note_header.n_type = type; |
|
254 |
|
255 Append(reinterpret_cast<const uint8_t*>(¬e_header), |
|
256 sizeof(note_header)); |
|
257 AppendCString(name); |
|
258 Align(4); |
|
259 Append(desc_bytes, desc_size); |
|
260 Align(4); |
|
261 } |
|
262 |
|
263 } // namespace synth_elf |
|
264 } // namespace google_breakpad |