Serenity Operating System
1/*
2 * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
3 * Copyright (c) 2022, the SerenityOS developers.
4 *
5 * SPDX-License-Identifier: BSD-2-Clause
6 */
7
8#include <AK/BinarySearch.h>
9#include <AK/Debug.h>
10#include <AK/Demangle.h>
11#include <AK/QuickSort.h>
12#include <AK/StringBuilder.h>
13#include <AK/StringView.h>
14#include <Kernel/API/serenity_limits.h>
15#include <LibELF/Image.h>
16#include <LibELF/Validation.h>
17
18#ifdef KERNEL
19# include <Kernel/StdLib.h>
20#else
21# include <string.h>
22#endif
23
24namespace ELF {
25
26Image::Image(ReadonlyBytes bytes, bool verbose_logging)
27 : m_buffer(bytes.data())
28 , m_size(bytes.size())
29 , m_verbose_logging(verbose_logging)
30{
31 parse();
32}
33
34Image::Image(u8 const* buffer, size_t size, bool verbose_logging)
35 : Image(ReadonlyBytes { buffer, size }, verbose_logging)
36{
37}
38
39StringView Image::section_index_to_string(unsigned index) const
40{
41 VERIFY(m_valid);
42 if (index == SHN_UNDEF)
43 return "Undefined"sv;
44 if (index >= SHN_LORESERVE)
45 return "Reserved"sv;
46 return section(index).name();
47}
48
49unsigned Image::symbol_count() const
50{
51 VERIFY(m_valid);
52 if (!section_count())
53 return 0;
54 return section(m_symbol_table_section_index).entry_count();
55}
56
57void Image::dump() const
58{
59#if ELF_IMAGE_DEBUG
60 dbgln("ELF::Image({:p}) {{", this);
61 dbgln(" is_valid: {}", is_valid());
62
63 if (!is_valid()) {
64 dbgln("}}");
65 return;
66 }
67
68 dbgln(" type: {}", ELF::Image::object_file_type_to_string(header().e_type).value_or("(?)"sv));
69 dbgln(" machine: {}", header().e_machine);
70 dbgln(" entry: {:x}", header().e_entry);
71 dbgln(" shoff: {}", header().e_shoff);
72 dbgln(" shnum: {}", header().e_shnum);
73 dbgln(" phoff: {}", header().e_phoff);
74 dbgln(" phnum: {}", header().e_phnum);
75 dbgln(" shstrndx: {}", header().e_shstrndx);
76
77 for_each_program_header([&](ProgramHeader const& program_header) {
78 dbgln(" Program Header {}: {{", program_header.index());
79 dbgln(" type: {:x}", program_header.type());
80 dbgln(" offset: {:x}", program_header.offset());
81 dbgln(" flags: {:x}", program_header.flags());
82 dbgln(" }}");
83 });
84
85 for (unsigned i = 0; i < header().e_shnum; ++i) {
86 auto const& section = this->section(i);
87 dbgln(" Section {}: {{", i);
88 dbgln(" name: {}", section.name());
89 dbgln(" type: {:x}", section.type());
90 dbgln(" offset: {:x}", section.offset());
91 dbgln(" size: {}", section.size());
92 dbgln(" ");
93 dbgln(" }}");
94 }
95
96 dbgln("Symbol count: {} (table is {})", symbol_count(), m_symbol_table_section_index);
97 for (unsigned i = 1; i < symbol_count(); ++i) {
98 auto const& sym = symbol(i);
99 dbgln("Symbol @{}:", i);
100 dbgln(" Name: {}", sym.name());
101 dbgln(" In section: {}", section_index_to_string(sym.section_index()));
102 dbgln(" Value: {}", sym.value());
103 dbgln(" Size: {}", sym.size());
104 }
105
106 dbgln("}}");
107#endif
108}
109
110unsigned Image::section_count() const
111{
112 VERIFY(m_valid);
113 return header().e_shnum;
114}
115
116unsigned Image::program_header_count() const
117{
118 VERIFY(m_valid);
119 return header().e_phnum;
120}
121
122bool Image::parse()
123{
124 if (m_size < sizeof(ElfW(Ehdr)) || !validate_elf_header(header(), m_size, m_verbose_logging)) {
125 if (m_verbose_logging)
126 dbgln("ELF::Image::parse(): ELF Header not valid");
127 m_valid = false;
128 return false;
129 }
130
131 auto result_or_error = validate_program_headers(header(), m_size, { m_buffer, m_size }, nullptr, m_verbose_logging);
132 if (result_or_error.is_error()) {
133 if (m_verbose_logging)
134 dbgln("ELF::Image::parse(): Failed validating ELF Program Headers");
135 m_valid = false;
136 return false;
137 }
138 if (!result_or_error.value()) {
139 if (m_verbose_logging)
140 dbgln("ELF::Image::parse(): ELF Program Headers not valid");
141 m_valid = false;
142 return false;
143 }
144
145 m_valid = true;
146
147 // First locate the string tables.
148 for (unsigned i = 0; i < section_count(); ++i) {
149 auto& sh = section_header(i);
150 if (sh.sh_type == SHT_SYMTAB) {
151 if (m_symbol_table_section_index && m_symbol_table_section_index != i) {
152 m_valid = false;
153 return false;
154 }
155 m_symbol_table_section_index = i;
156 }
157 if (sh.sh_type == SHT_STRTAB && i != header().e_shstrndx) {
158 if (section_header_table_string(sh.sh_name) == ELF_STRTAB)
159 m_string_table_section_index = i;
160 }
161 }
162
163 return m_valid;
164}
165
166StringView Image::table_string(unsigned table_index, unsigned offset) const
167{
168 VERIFY(m_valid);
169 auto& sh = section_header(table_index);
170 if (sh.sh_type != SHT_STRTAB)
171 return {};
172 size_t computed_offset = sh.sh_offset + offset;
173 if (computed_offset >= m_size) {
174 if (m_verbose_logging)
175 dbgln("SHENANIGANS! Image::table_string() computed offset outside image.");
176 return {};
177 }
178 size_t max_length = min(m_size - computed_offset, (size_t)PAGE_SIZE);
179 size_t length = strnlen(raw_data(sh.sh_offset + offset), max_length);
180 return { raw_data(sh.sh_offset + offset), length };
181}
182
183StringView Image::section_header_table_string(unsigned offset) const
184{
185 VERIFY(m_valid);
186 return table_string(header().e_shstrndx, offset);
187}
188
189StringView Image::table_string(unsigned offset) const
190{
191 VERIFY(m_valid);
192 return table_string(m_string_table_section_index, offset);
193}
194
195char const* Image::raw_data(unsigned offset) const
196{
197 VERIFY(offset < m_size); // Callers must check indices into raw_data()'s result are also in bounds.
198 return reinterpret_cast<char const*>(m_buffer) + offset;
199}
200
201const ElfW(Ehdr) & Image::header() const
202{
203 VERIFY(m_size >= sizeof(ElfW(Ehdr)));
204 return *reinterpret_cast<const ElfW(Ehdr)*>(raw_data(0));
205}
206
207const ElfW(Phdr) & Image::program_header_internal(unsigned index) const
208{
209 VERIFY(m_valid);
210 VERIFY(index < header().e_phnum);
211 return *reinterpret_cast<const ElfW(Phdr)*>(raw_data(header().e_phoff + (index * sizeof(ElfW(Phdr)))));
212}
213
214const ElfW(Shdr) & Image::section_header(unsigned index) const
215{
216 VERIFY(m_valid);
217 VERIFY(index < header().e_shnum);
218 return *reinterpret_cast<const ElfW(Shdr)*>(raw_data(header().e_shoff + (index * header().e_shentsize)));
219}
220
221Image::Symbol Image::symbol(unsigned index) const
222{
223 VERIFY(m_valid);
224 VERIFY(index < symbol_count());
225 auto* raw_syms = reinterpret_cast<const ElfW(Sym)*>(raw_data(section(m_symbol_table_section_index).offset()));
226 return Symbol(*this, index, raw_syms[index]);
227}
228
229Image::Section Image::section(unsigned index) const
230{
231 VERIFY(m_valid);
232 VERIFY(index < section_count());
233 return Section(*this, index);
234}
235
236Image::ProgramHeader Image::program_header(unsigned index) const
237{
238 VERIFY(m_valid);
239 VERIFY(index < program_header_count());
240 return ProgramHeader(*this, index);
241}
242
243Image::Relocation Image::RelocationSection::relocation(unsigned index) const
244{
245 VERIFY(index < relocation_count());
246 auto* rels = reinterpret_cast<const ElfW(Rel)*>(m_image.raw_data(offset()));
247 return Relocation(m_image, rels[index]);
248}
249
250Optional<Image::RelocationSection> Image::Section::relocations() const
251{
252 StringBuilder builder;
253 builder.append(".rel"sv);
254 builder.append(name());
255
256 auto relocation_section = m_image.lookup_section(builder.string_view());
257 if (!relocation_section.has_value())
258 return {};
259
260 dbgln_if(ELF_IMAGE_DEBUG, "Found relocations for {} in {}", name(), relocation_section.value().name());
261 return static_cast<RelocationSection>(relocation_section.value());
262}
263
264Optional<Image::Section> Image::lookup_section(StringView name) const
265{
266 VERIFY(m_valid);
267 for (unsigned i = 0; i < section_count(); ++i) {
268 auto section = this->section(i);
269 if (section.name() == name)
270 return section;
271 }
272 return {};
273}
274
275Optional<StringView> Image::object_file_type_to_string(ElfW(Half) type)
276{
277 switch (type) {
278 case ET_NONE:
279 return "None"sv;
280 case ET_REL:
281 return "Relocatable"sv;
282 case ET_EXEC:
283 return "Executable"sv;
284 case ET_DYN:
285 return "Shared object"sv;
286 case ET_CORE:
287 return "Core"sv;
288 default:
289 return {};
290 }
291}
292
293Optional<StringView> Image::object_machine_type_to_string(ElfW(Half) type)
294{
295 switch (type) {
296 case ET_NONE:
297 return "None"sv;
298 case EM_M32:
299 return "AT&T WE 32100"sv;
300 case EM_SPARC:
301 return "SPARC"sv;
302 case EM_386:
303 return "Intel 80386"sv;
304 case EM_68K:
305 return "Motorola 68000"sv;
306 case EM_88K:
307 return "Motorola 88000"sv;
308 case EM_486:
309 return "Intel 80486"sv;
310 case EM_860:
311 return "Intel 80860"sv;
312 case EM_MIPS:
313 return "MIPS R3000 Big-Endian only"sv;
314 case EM_X86_64:
315 return "x86_64"sv;
316 default:
317 return {};
318 }
319}
320
321Optional<StringView> Image::object_abi_type_to_string(Elf_Byte type)
322{
323 switch (type) {
324 case ELFOSABI_SYSV:
325 return "SYSV"sv;
326 case ELFOSABI_HPUX:
327 return "HP-UX"sv;
328 case ELFOSABI_NETBSD:
329 return "NetBSD"sv;
330 case ELFOSABI_LINUX:
331 return "Linux"sv;
332 case ELFOSABI_HURD:
333 return "GNU Hurd"sv;
334 case ELFOSABI_86OPEN:
335 return "86Open"sv;
336 case ELFOSABI_SOLARIS:
337 return "Solaris"sv;
338 case ELFOSABI_MONTEREY:
339 return "AIX"sv;
340 case ELFOSABI_IRIX:
341 return "IRIX"sv;
342 case ELFOSABI_FREEBSD:
343 return "FreeBSD"sv;
344 case ELFOSABI_TRU64:
345 return "Tru64"sv;
346 case ELFOSABI_MODESTO:
347 return "Novell Modesto"sv;
348 case ELFOSABI_OPENBSD:
349 return "OpenBSD"sv;
350 case ELFOSABI_ARM:
351 return "ARM"sv;
352 case ELFOSABI_STANDALONE:
353 return "Standalone"sv;
354 default:
355 return {};
356 }
357}
358
359StringView Image::Symbol::raw_data() const
360{
361 auto section = this->section();
362 return { section.raw_data() + (value() - section.address()), size() };
363}
364
365#ifndef KERNEL
366Optional<Image::Symbol> Image::find_demangled_function(StringView name) const
367{
368 Optional<Image::Symbol> found;
369 for_each_symbol([&](Image::Symbol const& symbol) {
370 if (symbol.type() != STT_FUNC && symbol.type() != STT_GNU_IFUNC)
371 return IterationDecision::Continue;
372 if (symbol.is_undefined())
373 return IterationDecision::Continue;
374 auto demangled = demangle(symbol.name());
375 auto index_of_paren = demangled.find('(');
376 if (index_of_paren.has_value()) {
377 demangled = demangled.substring(0, index_of_paren.value());
378 }
379 if (demangled != name)
380 return IterationDecision::Continue;
381 found = symbol;
382 return IterationDecision::Break;
383 });
384 return found;
385}
386
387Image::SortedSymbol* Image::find_sorted_symbol(FlatPtr address) const
388{
389 if (m_sorted_symbols.is_empty())
390 sort_symbols();
391
392 size_t index = 0;
393 binary_search(m_sorted_symbols, nullptr, &index, [&address](auto, auto& candidate) {
394 if (address < candidate.address)
395 return -1;
396 else if (address > candidate.address)
397 return 1;
398 else
399 return 0;
400 });
401 // FIXME: The error path here feels strange, index == 0 means error but what about symbol #0?
402 if (index == 0)
403 return nullptr;
404 return &m_sorted_symbols[index];
405}
406
407Optional<Image::Symbol> Image::find_symbol(FlatPtr address, u32* out_offset) const
408{
409 auto symbol_count = this->symbol_count();
410 if (!symbol_count)
411 return {};
412
413 auto* symbol = find_sorted_symbol(address);
414 if (!symbol)
415 return {};
416 if (out_offset)
417 *out_offset = address - symbol->address;
418 return symbol->symbol;
419}
420
421NEVER_INLINE void Image::sort_symbols() const
422{
423 m_sorted_symbols.ensure_capacity(symbol_count());
424 for_each_symbol([this](auto const& symbol) {
425 m_sorted_symbols.append({ symbol.value(), symbol.name(), {}, symbol });
426 });
427 quick_sort(m_sorted_symbols, [](auto& a, auto& b) {
428 return a.address < b.address;
429 });
430}
431
432DeprecatedString Image::symbolicate(FlatPtr address, u32* out_offset) const
433{
434 auto symbol_count = this->symbol_count();
435 if (!symbol_count) {
436 if (out_offset)
437 *out_offset = 0;
438 return "??";
439 }
440
441 auto* symbol = find_sorted_symbol(address);
442 if (!symbol) {
443 if (out_offset)
444 *out_offset = 0;
445 return "??";
446 }
447
448 auto& demangled_name = symbol->demangled_name;
449 if (demangled_name.is_null())
450 demangled_name = demangle(symbol->name);
451
452 if (out_offset) {
453 *out_offset = address - symbol->address;
454 return demangled_name;
455 }
456 return DeprecatedString::formatted("{} +{:#x}", demangled_name, address - symbol->address);
457}
458#endif
459
460} // end namespace ELF