Serenity Operating System
at master 460 lines 13 kB view raw
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