1 | //===-- ELFHeader.cpp -----------------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include <cstring> |
10 | |
11 | #include "lldb/Core/Section.h" |
12 | #include "lldb/Utility/DataExtractor.h" |
13 | #include "lldb/Utility/Stream.h" |
14 | |
15 | #include "ELFHeader.h" |
16 | |
17 | using namespace elf; |
18 | using namespace lldb; |
19 | using namespace llvm::ELF; |
20 | |
21 | // Static utility functions. |
22 | // |
23 | // GetMaxU64 and GetMaxS64 wrap the similarly named methods from DataExtractor |
24 | // with error handling code and provide for parsing a sequence of values. |
25 | static bool (const lldb_private::DataExtractor &data, |
26 | lldb::offset_t *offset, uint64_t *value, |
27 | uint32_t byte_size) { |
28 | const lldb::offset_t saved_offset = *offset; |
29 | *value = data.GetMaxU64(offset_ptr: offset, byte_size); |
30 | return *offset != saved_offset; |
31 | } |
32 | |
33 | static bool (const lldb_private::DataExtractor &data, |
34 | lldb::offset_t *offset, uint64_t *value, |
35 | uint32_t byte_size, uint32_t count) { |
36 | lldb::offset_t saved_offset = *offset; |
37 | |
38 | for (uint32_t i = 0; i < count; ++i, ++value) { |
39 | if (!GetMaxU64(data, offset, value, byte_size)) { |
40 | *offset = saved_offset; |
41 | return false; |
42 | } |
43 | } |
44 | return true; |
45 | } |
46 | |
47 | static bool (const lldb_private::DataExtractor &data, |
48 | lldb::offset_t *offset, int64_t *value, |
49 | uint32_t byte_size) { |
50 | const lldb::offset_t saved_offset = *offset; |
51 | *value = data.GetMaxS64(offset_ptr: offset, byte_size); |
52 | return *offset != saved_offset; |
53 | } |
54 | |
55 | static bool (const lldb_private::DataExtractor &data, |
56 | lldb::offset_t *offset, int64_t *value, |
57 | uint32_t byte_size, uint32_t count) { |
58 | lldb::offset_t saved_offset = *offset; |
59 | |
60 | for (uint32_t i = 0; i < count; ++i, ++value) { |
61 | if (!GetMaxS64(data, offset, value, byte_size)) { |
62 | *offset = saved_offset; |
63 | return false; |
64 | } |
65 | } |
66 | return true; |
67 | } |
68 | |
69 | // ELFHeader |
70 | |
71 | ELFHeader::() { memset(s: this, c: 0, n: sizeof(ELFHeader)); } |
72 | |
73 | ByteOrder ELFHeader::() const { |
74 | if (e_ident[EI_DATA] == ELFDATA2MSB) |
75 | return eByteOrderBig; |
76 | if (e_ident[EI_DATA] == ELFDATA2LSB) |
77 | return eByteOrderLittle; |
78 | return eByteOrderInvalid; |
79 | } |
80 | |
81 | bool ELFHeader::() const { |
82 | bool result = false; |
83 | |
84 | // Check if any of these values looks like sentinel. |
85 | result |= e_phnum_hdr == 0xFFFF; // PN_XNUM |
86 | result |= e_shnum_hdr == SHN_UNDEF; |
87 | result |= e_shstrndx_hdr == SHN_XINDEX; |
88 | |
89 | // If header extension is present, the section offset cannot be null. |
90 | result &= e_shoff != 0; |
91 | |
92 | // Done. |
93 | return result; |
94 | } |
95 | |
96 | void ELFHeader::(lldb_private::DataExtractor &data) { |
97 | // Extract section #0 header. |
98 | ELFSectionHeader section_zero; |
99 | lldb::offset_t offset = 0; |
100 | lldb_private::DataExtractor sh_data(data, e_shoff, e_shentsize); |
101 | bool ok = section_zero.Parse(data: sh_data, offset: &offset); |
102 | |
103 | // If we succeeded, fix the header. |
104 | if (ok) { |
105 | if (e_phnum_hdr == 0xFFFF) // PN_XNUM |
106 | e_phnum = section_zero.sh_info; |
107 | if (e_shnum_hdr == SHN_UNDEF) |
108 | e_shnum = section_zero.sh_size; |
109 | if (e_shstrndx_hdr == SHN_XINDEX) |
110 | e_shstrndx = section_zero.sh_link; |
111 | } |
112 | } |
113 | |
114 | bool ELFHeader::(lldb_private::DataExtractor &data, |
115 | lldb::offset_t *offset) { |
116 | // Read e_ident. This provides byte order and address size info. |
117 | if (data.GetU8(offset_ptr: offset, dst: &e_ident, count: EI_NIDENT) == nullptr) |
118 | return false; |
119 | |
120 | const unsigned byte_size = Is32Bit() ? 4 : 8; |
121 | data.SetByteOrder(GetByteOrder()); |
122 | data.SetAddressByteSize(byte_size); |
123 | |
124 | // Read e_type and e_machine. |
125 | if (data.GetU16(offset_ptr: offset, dst: &e_type, count: 2) == nullptr) |
126 | return false; |
127 | |
128 | // Read e_version. |
129 | if (data.GetU32(offset_ptr: offset, dst: &e_version, count: 1) == nullptr) |
130 | return false; |
131 | |
132 | // Read e_entry, e_phoff and e_shoff. |
133 | if (!GetMaxU64(data, offset, value: &e_entry, byte_size, count: 3)) |
134 | return false; |
135 | |
136 | // Read e_flags. |
137 | if (data.GetU32(offset_ptr: offset, dst: &e_flags, count: 1) == nullptr) |
138 | return false; |
139 | |
140 | // Read e_ehsize, e_phentsize, e_phnum, e_shentsize, e_shnum and e_shstrndx. |
141 | if (data.GetU16(offset_ptr: offset, dst: &e_ehsize, count: 6) == nullptr) |
142 | return false; |
143 | |
144 | // Initialize e_phnum, e_shnum, and e_shstrndx with the values read from the |
145 | // header. |
146 | e_phnum = e_phnum_hdr; |
147 | e_shnum = e_shnum_hdr; |
148 | e_shstrndx = e_shstrndx_hdr; |
149 | |
150 | // See if we have extended header in section #0. |
151 | if (HasHeaderExtension()) |
152 | ParseHeaderExtension(data); |
153 | |
154 | return true; |
155 | } |
156 | |
157 | bool ELFHeader::(const uint8_t *magic) { |
158 | return memcmp(s1: magic, s2: ElfMagic, n: strlen(s: ElfMagic)) == 0; |
159 | } |
160 | |
161 | unsigned ELFHeader::(const uint8_t *magic) { |
162 | unsigned address_size = 0; |
163 | |
164 | switch (magic[EI_CLASS]) { |
165 | case ELFCLASS32: |
166 | address_size = 4; |
167 | break; |
168 | |
169 | case ELFCLASS64: |
170 | address_size = 8; |
171 | break; |
172 | } |
173 | return address_size; |
174 | } |
175 | |
176 | unsigned ELFHeader::() const { |
177 | unsigned slot = 0; |
178 | |
179 | switch (e_machine) { |
180 | default: |
181 | assert(false && "architecture not supported" ); |
182 | break; |
183 | case EM_PPC: |
184 | slot = R_PPC_JMP_SLOT; |
185 | break; |
186 | case EM_PPC64: |
187 | slot = R_PPC64_JMP_SLOT; |
188 | break; |
189 | case EM_386: |
190 | case EM_IAMCU: // FIXME: is this correct? |
191 | slot = R_386_JUMP_SLOT; |
192 | break; |
193 | case EM_X86_64: |
194 | slot = R_X86_64_JUMP_SLOT; |
195 | break; |
196 | case EM_ARM: |
197 | slot = R_ARM_JUMP_SLOT; |
198 | break; |
199 | case EM_HEXAGON: |
200 | slot = R_HEX_JMP_SLOT; |
201 | break; |
202 | case EM_AARCH64: |
203 | slot = R_AARCH64_JUMP_SLOT; |
204 | break; |
205 | case EM_MIPS: |
206 | slot = R_MIPS_JUMP_SLOT; |
207 | break; |
208 | case EM_S390: |
209 | slot = R_390_JMP_SLOT; |
210 | break; |
211 | case EM_RISCV: |
212 | slot = R_RISCV_JUMP_SLOT; |
213 | break; |
214 | case EM_LOONGARCH: |
215 | slot = R_LARCH_JUMP_SLOT; |
216 | break; |
217 | } |
218 | |
219 | return slot; |
220 | } |
221 | |
222 | // ELFSectionHeader |
223 | |
224 | ELFSectionHeader::() { |
225 | memset(s: this, c: 0, n: sizeof(ELFSectionHeader)); |
226 | } |
227 | |
228 | bool ELFSectionHeader::(const lldb_private::DataExtractor &data, |
229 | lldb::offset_t *offset) { |
230 | const unsigned byte_size = data.GetAddressByteSize(); |
231 | |
232 | // Read sh_name and sh_type. |
233 | if (data.GetU32(offset_ptr: offset, dst: &sh_name, count: 2) == nullptr) |
234 | return false; |
235 | |
236 | // Read sh_flags. |
237 | if (!GetMaxU64(data, offset, value: &sh_flags, byte_size)) |
238 | return false; |
239 | |
240 | // Read sh_addr, sh_off and sh_size. |
241 | if (!GetMaxU64(data, offset, value: &sh_addr, byte_size, count: 3)) |
242 | return false; |
243 | |
244 | // Read sh_link and sh_info. |
245 | if (data.GetU32(offset_ptr: offset, dst: &sh_link, count: 2) == nullptr) |
246 | return false; |
247 | |
248 | // Read sh_addralign and sh_entsize. |
249 | if (!GetMaxU64(data, offset, value: &sh_addralign, byte_size, count: 2)) |
250 | return false; |
251 | |
252 | return true; |
253 | } |
254 | |
255 | // ELFSymbol |
256 | |
257 | ELFSymbol::ELFSymbol() { memset(s: this, c: 0, n: sizeof(ELFSymbol)); } |
258 | |
259 | #define ENUM_TO_CSTR(e) \ |
260 | case e: \ |
261 | return #e |
262 | |
263 | const char *ELFSymbol::bindingToCString(unsigned char binding) { |
264 | switch (binding) { |
265 | ENUM_TO_CSTR(STB_LOCAL); |
266 | ENUM_TO_CSTR(STB_GLOBAL); |
267 | ENUM_TO_CSTR(STB_WEAK); |
268 | ENUM_TO_CSTR(STB_LOOS); |
269 | ENUM_TO_CSTR(STB_HIOS); |
270 | ENUM_TO_CSTR(STB_LOPROC); |
271 | ENUM_TO_CSTR(STB_HIPROC); |
272 | } |
273 | return "" ; |
274 | } |
275 | |
276 | const char *ELFSymbol::typeToCString(unsigned char type) { |
277 | switch (type) { |
278 | ENUM_TO_CSTR(STT_NOTYPE); |
279 | ENUM_TO_CSTR(STT_OBJECT); |
280 | ENUM_TO_CSTR(STT_FUNC); |
281 | ENUM_TO_CSTR(STT_SECTION); |
282 | ENUM_TO_CSTR(STT_FILE); |
283 | ENUM_TO_CSTR(STT_COMMON); |
284 | ENUM_TO_CSTR(STT_TLS); |
285 | ENUM_TO_CSTR(STT_GNU_IFUNC); |
286 | ENUM_TO_CSTR(STT_HIOS); |
287 | ENUM_TO_CSTR(STT_LOPROC); |
288 | ENUM_TO_CSTR(STT_HIPROC); |
289 | } |
290 | return "" ; |
291 | } |
292 | |
293 | const char *ELFSymbol::sectionIndexToCString( |
294 | elf_half shndx, const lldb_private::SectionList *section_list) { |
295 | switch (shndx) { |
296 | ENUM_TO_CSTR(SHN_UNDEF); |
297 | ENUM_TO_CSTR(SHN_LOPROC); |
298 | ENUM_TO_CSTR(SHN_HIPROC); |
299 | ENUM_TO_CSTR(SHN_LOOS); |
300 | ENUM_TO_CSTR(SHN_HIOS); |
301 | ENUM_TO_CSTR(SHN_ABS); |
302 | ENUM_TO_CSTR(SHN_COMMON); |
303 | ENUM_TO_CSTR(SHN_XINDEX); |
304 | default: { |
305 | const lldb_private::Section *section = |
306 | section_list->GetSectionAtIndex(idx: shndx).get(); |
307 | if (section) |
308 | return section->GetName().AsCString(value_if_empty: "" ); |
309 | } break; |
310 | } |
311 | return "" ; |
312 | } |
313 | |
314 | void ELFSymbol::(lldb_private::Stream *s, uint32_t idx, |
315 | const lldb_private::DataExtractor *strtab_data, |
316 | const lldb_private::SectionList *section_list) { |
317 | s->Printf(format: "[%3u] 0x%16.16" PRIx64 " 0x%16.16" PRIx64 |
318 | " 0x%8.8x 0x%2.2x (%-10s %-13s) 0x%2.2x 0x%4.4x (%-10s) %s\n" , |
319 | idx, st_value, st_size, st_name, st_info, |
320 | bindingToCString(binding: getBinding()), typeToCString(type: getType()), st_other, |
321 | st_shndx, sectionIndexToCString(shndx: st_shndx, section_list), |
322 | strtab_data ? strtab_data->PeekCStr(offset: st_name) : "" ); |
323 | } |
324 | |
325 | bool ELFSymbol::(const lldb_private::DataExtractor &data, |
326 | lldb::offset_t *offset) { |
327 | const unsigned byte_size = data.GetAddressByteSize(); |
328 | const bool parsing_32 = byte_size == 4; |
329 | |
330 | // Read st_name. |
331 | if (data.GetU32(offset_ptr: offset, dst: &st_name, count: 1) == nullptr) |
332 | return false; |
333 | |
334 | if (parsing_32) { |
335 | // Read st_value and st_size. |
336 | if (!GetMaxU64(data, offset, value: &st_value, byte_size, count: 2)) |
337 | return false; |
338 | |
339 | // Read st_info and st_other. |
340 | if (data.GetU8(offset_ptr: offset, dst: &st_info, count: 2) == nullptr) |
341 | return false; |
342 | |
343 | // Read st_shndx. |
344 | if (data.GetU16(offset_ptr: offset, dst: &st_shndx, count: 1) == nullptr) |
345 | return false; |
346 | } else { |
347 | // Read st_info and st_other. |
348 | if (data.GetU8(offset_ptr: offset, dst: &st_info, count: 2) == nullptr) |
349 | return false; |
350 | |
351 | // Read st_shndx. |
352 | if (data.GetU16(offset_ptr: offset, dst: &st_shndx, count: 1) == nullptr) |
353 | return false; |
354 | |
355 | // Read st_value and st_size. |
356 | if (data.GetU64(offset_ptr: offset, dst: &st_value, count: 2) == nullptr) |
357 | return false; |
358 | } |
359 | return true; |
360 | } |
361 | |
362 | // ELFProgramHeader |
363 | |
364 | ELFProgramHeader::() { |
365 | memset(s: this, c: 0, n: sizeof(ELFProgramHeader)); |
366 | } |
367 | |
368 | bool ELFProgramHeader::(const lldb_private::DataExtractor &data, |
369 | lldb::offset_t *offset) { |
370 | const uint32_t byte_size = data.GetAddressByteSize(); |
371 | const bool parsing_32 = byte_size == 4; |
372 | |
373 | // Read p_type; |
374 | if (data.GetU32(offset_ptr: offset, dst: &p_type, count: 1) == nullptr) |
375 | return false; |
376 | |
377 | if (parsing_32) { |
378 | // Read p_offset, p_vaddr, p_paddr, p_filesz and p_memsz. |
379 | if (!GetMaxU64(data, offset, value: &p_offset, byte_size, count: 5)) |
380 | return false; |
381 | |
382 | // Read p_flags. |
383 | if (data.GetU32(offset_ptr: offset, dst: &p_flags, count: 1) == nullptr) |
384 | return false; |
385 | |
386 | // Read p_align. |
387 | if (!GetMaxU64(data, offset, value: &p_align, byte_size)) |
388 | return false; |
389 | } else { |
390 | // Read p_flags. |
391 | if (data.GetU32(offset_ptr: offset, dst: &p_flags, count: 1) == nullptr) |
392 | return false; |
393 | |
394 | // Read p_offset, p_vaddr, p_paddr, p_filesz, p_memsz and p_align. |
395 | if (!GetMaxU64(data, offset, value: &p_offset, byte_size, count: 6)) |
396 | return false; |
397 | } |
398 | |
399 | return true; |
400 | } |
401 | |
402 | // ELFDynamic |
403 | |
404 | ELFDynamic::ELFDynamic() { memset(s: this, c: 0, n: sizeof(ELFDynamic)); } |
405 | |
406 | bool ELFDynamic::(const lldb_private::DataExtractor &data, |
407 | lldb::offset_t *offset) { |
408 | const unsigned byte_size = data.GetAddressByteSize(); |
409 | return GetMaxS64(data, offset, value: &d_tag, byte_size, count: 2); |
410 | } |
411 | |
412 | // ELFRel |
413 | |
414 | ELFRel::ELFRel() { memset(s: this, c: 0, n: sizeof(ELFRel)); } |
415 | |
416 | bool ELFRel::(const lldb_private::DataExtractor &data, |
417 | lldb::offset_t *offset) { |
418 | const unsigned byte_size = data.GetAddressByteSize(); |
419 | |
420 | // Read r_offset and r_info. |
421 | return GetMaxU64(data, offset, value: &r_offset, byte_size, count: 2) != false; |
422 | } |
423 | |
424 | // ELFRela |
425 | |
426 | ELFRela::ELFRela() { memset(s: this, c: 0, n: sizeof(ELFRela)); } |
427 | |
428 | bool ELFRela::(const lldb_private::DataExtractor &data, |
429 | lldb::offset_t *offset) { |
430 | const unsigned byte_size = data.GetAddressByteSize(); |
431 | |
432 | // Read r_offset and r_info. |
433 | if (!GetMaxU64(data, offset, value: &r_offset, byte_size, count: 2)) |
434 | return false; |
435 | |
436 | // Read r_addend; |
437 | if (!GetMaxS64(data, offset, value: &r_addend, byte_size)) |
438 | return false; |
439 | |
440 | return true; |
441 | } |
442 | |