Serenity Operating System
at master 718 lines 26 kB view raw
1/* 2 * Copyright (c) 2020-2022, the SerenityOS developers. 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <AK/DeprecatedString.h> 8#include <AK/LexicalPath.h> 9#include <AK/StringBuilder.h> 10#include <AK/StringView.h> 11#include <LibCore/ArgsParser.h> 12#include <LibCore/MappedFile.h> 13#include <LibCore/System.h> 14#include <LibELF/DynamicLoader.h> 15#include <LibELF/DynamicObject.h> 16#include <LibELF/Image.h> 17#include <LibELF/Validation.h> 18#include <LibMain/Main.h> 19#include <ctype.h> 20#include <fcntl.h> 21#include <stdio.h> 22#include <unistd.h> 23 24static char const* object_program_header_type_to_string(ElfW(Word) type) 25{ 26 switch (type) { 27 case PT_NULL: 28 return "NULL"; 29 case PT_LOAD: 30 return "LOAD"; 31 case PT_DYNAMIC: 32 return "DYNAMIC"; 33 case PT_INTERP: 34 return "INTERP"; 35 case PT_NOTE: 36 return "NOTE"; 37 case PT_SHLIB: 38 return "SHLIB"; 39 case PT_PHDR: 40 return "PHDR"; 41 case PT_TLS: 42 return "TLS"; 43 case PT_LOOS: 44 return "LOOS"; 45 case PT_HIOS: 46 return "HIOS"; 47 case PT_LOPROC: 48 return "LOPROC"; 49 case PT_HIPROC: 50 return "HIPROC"; 51 case PT_GNU_EH_FRAME: 52 return "GNU_EH_FRAME"; 53 case PT_GNU_RELRO: 54 return "GNU_RELRO"; 55 case PT_GNU_STACK: 56 return "GNU_STACK"; 57 case PT_OPENBSD_RANDOMIZE: 58 return "OPENBSD_RANDOMIZE"; 59 case PT_OPENBSD_WXNEEDED: 60 return "OPENBSD_WXNEEDED"; 61 case PT_OPENBSD_BOOTDATA: 62 return "OPENBSD_BOOTDATA"; 63 default: 64 return "(?)"; 65 } 66} 67 68static char const* object_section_header_type_to_string(ElfW(Word) type) 69{ 70 switch (type) { 71 case SHT_NULL: 72 return "NULL"; 73 case SHT_PROGBITS: 74 return "PROGBITS"; 75 case SHT_SYMTAB: 76 return "SYMTAB"; 77 case SHT_STRTAB: 78 return "STRTAB"; 79 case SHT_RELA: 80 return "RELA"; 81 case SHT_HASH: 82 return "HASH"; 83 case SHT_DYNAMIC: 84 return "DYNAMIC"; 85 case SHT_NOTE: 86 return "NOTE"; 87 case SHT_NOBITS: 88 return "NOBITS"; 89 case SHT_REL: 90 return "REL"; 91 case SHT_SHLIB: 92 return "SHLIB"; 93 case SHT_DYNSYM: 94 return "DYNSYM"; 95 case SHT_NUM: 96 return "NUM"; 97 case SHT_INIT_ARRAY: 98 return "INIT_ARRAY"; 99 case SHT_FINI_ARRAY: 100 return "FINI_ARRAY"; 101 case SHT_PREINIT_ARRAY: 102 return "PREINIT_ARRAY"; 103 case SHT_GROUP: 104 return "GROUP"; 105 case SHT_SYMTAB_SHNDX: 106 return "SYMTAB_SHNDX"; 107 case SHT_RELR: 108 return "RELR"; 109 case SHT_LOOS: 110 return "SOOS"; 111 case SHT_SUNW_dof: 112 return "SUNW_dof"; 113 case SHT_GNU_LIBLIST: 114 return "GNU_LIBLIST"; 115 case SHT_SUNW_move: 116 return "SUNW_move"; 117 case SHT_SUNW_syminfo: 118 return "SUNW_syminfo"; 119 case SHT_SUNW_verdef: 120 return "SUNW_verdef"; 121 case SHT_SUNW_verneed: 122 return "SUNW_verneed"; 123 case SHT_SUNW_versym: // or SHT_HIOS 124 return "SUNW_versym"; 125 case SHT_LOPROC: 126 return "LOPROC"; 127 case SHT_HIPROC: 128 return "HIPROC"; 129 case SHT_LOUSER: 130 return "LOUSER"; 131 case SHT_HIUSER: 132 return "HIUSER"; 133 case SHT_GNU_HASH: 134 return "GNU_HASH"; 135 default: 136 return "(?)"; 137 } 138} 139 140static char const* object_symbol_type_to_string(ElfW(Word) type) 141{ 142 switch (type) { 143 case STT_NOTYPE: 144 return "NOTYPE"; 145 case STT_OBJECT: 146 return "OBJECT"; 147 case STT_FUNC: 148 return "FUNC"; 149 case STT_SECTION: 150 return "SECTION"; 151 case STT_FILE: 152 return "FILE"; 153 case STT_TLS: 154 return "TLS"; 155 case STT_GNU_IFUNC: 156 return "IFUNC"; 157 case STT_LOPROC: 158 return "LOPROC"; 159 case STT_HIPROC: 160 return "HIPROC"; 161 default: 162 return "(?)"; 163 } 164} 165 166static char const* object_symbol_binding_to_string(ElfW(Word) type) 167{ 168 switch (type) { 169 case STB_LOCAL: 170 return "LOCAL"; 171 case STB_GLOBAL: 172 return "GLOBAL"; 173 case STB_WEAK: 174 return "WEAK"; 175 case STB_NUM: 176 return "NUM"; 177 case STB_LOPROC: 178 return "LOPROC"; 179 case STB_HIPROC: 180 return "HIPROC"; 181 default: 182 return "(?)"; 183 } 184} 185 186static char const* object_relocation_type_to_string(ElfW(Word) type) 187{ 188 switch (type) { 189#if ARCH(X86_64) 190 case R_X86_64_NONE: 191 return "R_X86_64_NONE"; 192 case R_X86_64_64: 193 return "R_X86_64"; 194 case R_X86_64_GLOB_DAT: 195 return "R_x86_64_GLOB_DAT"; 196 case R_X86_64_JUMP_SLOT: 197 return "R_X86_64_JUMP_SLOT"; 198 case R_X86_64_RELATIVE: 199 return "R_X86_64_RELATIVE"; 200 case R_X86_64_TPOFF64: 201 return "R_X86_64_TPOFF64"; 202#endif 203 default: 204 return "(?)"; 205 } 206} 207 208ErrorOr<int> serenity_main(Main::Arguments arguments) 209{ 210 TRY(Core::System::pledge("stdio rpath")); 211 212 DeprecatedString path {}; 213 static bool display_all = false; 214 static bool display_elf_header = false; 215 static bool display_program_headers = false; 216 static bool display_section_headers = false; 217 static bool display_headers = false; 218 static bool display_symbol_table = false; 219 static bool display_dynamic_symbol_table = false; 220 static bool display_core_notes = false; 221 static bool display_relocations = false; 222 static bool display_unwind_info = false; 223 static bool display_dynamic_section = false; 224 static bool display_hardening = false; 225 StringView string_dump_section {}; 226 227 Core::ArgsParser args_parser; 228 args_parser.add_option(display_all, "Display all", "all", 'a'); 229 args_parser.add_option(display_elf_header, "Display ELF header", "file-header", 'h'); 230 args_parser.add_option(display_program_headers, "Display program headers", "program-headers", 'l'); 231 args_parser.add_option(display_section_headers, "Display section headers", "section-headers", 'S'); 232 args_parser.add_option(display_headers, "Equivalent to: -h -l -S -s -r -d -n -u -c", "headers", 'e'); 233 args_parser.add_option(display_symbol_table, "Display the symbol table", "syms", 's'); 234 args_parser.add_option(display_dynamic_symbol_table, "Display the dynamic symbol table", "dyn-syms", '\0'); 235 args_parser.add_option(display_dynamic_section, "Display the dynamic section", "dynamic", 'd'); 236 args_parser.add_option(display_core_notes, "Display core notes", "notes", 'n'); 237 args_parser.add_option(display_relocations, "Display relocations", "relocs", 'r'); 238 args_parser.add_option(display_unwind_info, "Display unwind info", "unwind", 'u'); 239 args_parser.add_option(display_hardening, "Display security hardening info", "checksec", 'c'); 240 args_parser.add_option(string_dump_section, "Display the contents of a section as strings", "string-dump", 'p', "section-name"); 241 args_parser.add_positional_argument(path, "ELF path", "path"); 242 args_parser.parse(arguments); 243 244 if (arguments.argc < 3) { 245 args_parser.print_usage(stderr, arguments.strings[0]); 246 return Error::from_errno(EINVAL); 247 } 248 249 if (display_headers) { 250 display_elf_header = true; 251 display_program_headers = true; 252 display_section_headers = true; 253 } 254 255 if (display_all) { 256 display_elf_header = true; 257 display_program_headers = true; 258 display_section_headers = true; 259 display_dynamic_symbol_table = true; 260 display_dynamic_section = true; 261 display_core_notes = true; 262 display_relocations = true; 263 display_unwind_info = true; 264 display_symbol_table = true; 265 display_hardening = true; 266 } 267 268 path = LexicalPath::absolute_path(TRY(Core::System::getcwd()), path); 269 270 auto file_or_error = Core::MappedFile::map(path); 271 272 if (file_or_error.is_error()) { 273 warnln("Unable to map file {}: {}", path, file_or_error.error()); 274 return -1; 275 } 276 277 auto elf_image_data = file_or_error.value()->bytes(); 278 ELF::Image elf_image(elf_image_data); 279 280 if (!elf_image.is_valid()) { 281 warnln("File is not a valid ELF object"); 282 return -1; 283 } 284 285 StringBuilder interpreter_path_builder; 286 auto result_or_error = ELF::validate_program_headers(*(const ElfW(Ehdr)*)elf_image_data.data(), elf_image_data.size(), elf_image_data, &interpreter_path_builder); 287 if (result_or_error.is_error() || !result_or_error.value()) { 288 warnln("Invalid ELF headers"); 289 return -1; 290 } 291 auto interpreter_path = interpreter_path_builder.string_view(); 292 293 auto& header = *reinterpret_cast<const ElfW(Ehdr)*>(elf_image_data.data()); 294 295 RefPtr<ELF::DynamicObject> object = nullptr; 296 297 if (elf_image.is_dynamic()) { 298 if (interpreter_path.is_empty()) { 299 interpreter_path = "/usr/lib/Loader.so"sv; 300 warnln("Warning: Dynamic ELF object has no interpreter path. Using: {}", interpreter_path); 301 } 302 303 auto interpreter_file_or_error = Core::MappedFile::map(interpreter_path); 304 305 if (interpreter_file_or_error.is_error()) { 306 warnln("Unable to map interpreter file {}: {}", interpreter_path, interpreter_file_or_error.error()); 307 } else { 308 auto interpreter_image_data = interpreter_file_or_error.value()->bytes(); 309 310 ELF::Image interpreter_image(interpreter_image_data); 311 312 if (!interpreter_image.is_valid()) { 313 warnln("ELF interpreter image is invalid"); 314 } 315 } 316 317 int fd = TRY(Core::System::open(path, O_RDONLY)); 318 auto result = ELF::DynamicLoader::try_create(fd, path); 319 if (result.is_error()) { 320 outln("{}", result.error().text); 321 return 1; 322 } 323 auto& loader = result.value(); 324 if (!loader->is_valid()) { 325 outln("{} is not a valid ELF dynamic shared object!", path); 326 return 1; 327 } 328 329 object = loader->map(); 330 if (!object) { 331 outln("Failed to map dynamic ELF object {}", path); 332 return 1; 333 } 334 } 335 336 if (display_elf_header) { 337 outln("ELF header:"); 338 339 out(" Magic: "); 340 for (char i : StringView { header.e_ident, sizeof(header.e_ident) }) { 341 if (isprint(i)) { 342 out("{:c} ", i); 343 } else { 344 out("{:02x} ", i); 345 } 346 } 347 outln(); 348 349 outln(" Type: {} ({})", header.e_type, ELF::Image::object_file_type_to_string(header.e_type).value_or("(?)"sv)); 350 outln(" Machine: {} ({})", header.e_machine, ELF::Image::object_machine_type_to_string(header.e_machine).value_or("(?)"sv)); 351 outln(" Version: {:#x}", header.e_version); 352 outln(" Entry point address: {:#x}", header.e_entry); 353 outln(" Start of program headers: {} (bytes into file)", header.e_phoff); 354 outln(" Start of section headers: {} (bytes into file)", header.e_shoff); 355 outln(" Flags: {:#x}", header.e_flags); 356 outln(" Size of this header: {} (bytes)", header.e_ehsize); 357 outln(" Size of program headers: {} (bytes)", header.e_phentsize); 358 outln(" Number of program headers: {}", header.e_phnum); 359 outln(" Size of section headers: {} (bytes)", header.e_shentsize); 360 outln(" Number of section headers: {}", header.e_shnum); 361 outln(" Section header string table index: {}", header.e_shstrndx); 362 outln(); 363 } 364 365 auto addr_padding = " "; 366 367 if (display_section_headers) { 368 if (!display_all) { 369 outln("There are {} section headers, starting at offset {:#x}:", header.e_shnum, header.e_shoff); 370 outln(); 371 } 372 373 if (!elf_image.section_count()) { 374 outln("There are no sections in this file."); 375 } else { 376 outln("Section Headers:"); 377 outln(" Name Type Address{} Offset{} Size{} Flags", addr_padding, addr_padding, addr_padding); 378 379 elf_image.for_each_section([](const ELF::Image::Section& section) { 380 out(" {:19} ", section.name()); 381 out("{:15} ", object_section_header_type_to_string(section.type())); 382 out("{:p} ", section.address()); 383 out("{:p} ", section.offset()); 384 out("{:p} ", section.size()); 385 out("{}", section.flags()); 386 outln(); 387 }); 388 } 389 outln(); 390 } 391 392 if (display_program_headers) { 393 if (!display_all) { 394 outln("ELF file type is {} ({})", header.e_type, ELF::Image::object_file_type_to_string(header.e_type).value_or("(?)"sv)); 395 outln("Entry point {:#x}\n", header.e_entry); 396 outln("There are {} program headers, starting at offset {}", header.e_phnum, header.e_phoff); 397 outln(); 398 } 399 400 if (!elf_image.program_header_count()) { 401 outln("There are no program headers in this file."); 402 } else { 403 outln("Program Headers:"); 404 outln(" Type Offset{} VirtAddr{} PhysAddr{} FileSiz{} MemSiz{} Flg Align", 405 addr_padding, addr_padding, addr_padding, addr_padding, addr_padding); 406 407 elf_image.for_each_program_header([](const ELF::Image::ProgramHeader& program_header) { 408 out(" "); 409 out("{:14} ", object_program_header_type_to_string(program_header.type())); 410 out("{:p} ", program_header.offset()); 411 out("{:p} ", program_header.vaddr().as_ptr()); 412 out("{:p} ", program_header.vaddr().as_ptr()); // FIXME: assumes PhysAddr = VirtAddr 413 out("{:p} ", program_header.size_in_image()); 414 out("{:p} ", program_header.size_in_memory()); 415 out("{:04x} ", program_header.flags()); 416 out("{:p}", program_header.alignment()); 417 outln(); 418 419 if (program_header.type() == PT_INTERP) 420 outln(" [Interpreter: {}]", program_header.raw_data()); 421 }); 422 } 423 424 // TODO: Display section to segment mapping 425 outln(); 426 } 427 428 if (display_dynamic_section) { 429 auto found_dynamic_section = false; 430 if (elf_image.is_dynamic()) { 431 elf_image.for_each_section([&found_dynamic_section](const ELF::Image::Section& section) { 432 if (section.name() != ELF_DYNAMIC) 433 return IterationDecision::Continue; 434 435 found_dynamic_section = true; 436 437 if (section.entry_count()) { 438 outln("Dynamic section '{}' at offset {:#08x} contains {} entries.", section.name().to_deprecated_string(), section.offset(), section.entry_count()); 439 } else { 440 outln("Dynamic section '{}' at offset {:#08x} contains zero entries.", section.name().to_deprecated_string(), section.offset()); 441 } 442 443 return IterationDecision::Break; 444 }); 445 446 Vector<DeprecatedString> libraries; 447 object->for_each_needed_library([&libraries](StringView entry) { 448 libraries.append(DeprecatedString::formatted("{}", entry)); 449 }); 450 451 auto library_index = 0; 452 outln(" Tag Type Name / Value"); 453 object->for_each_dynamic_entry([&library_index, &libraries, &object](const ELF::DynamicObject::DynamicEntry& entry) { 454 out(" {:#08x} ", entry.tag()); 455 out("{:17} ", ELF::DynamicObject::name_for_dtag(entry.tag())); 456 457 if (entry.tag() == DT_NEEDED) { 458 outln("Shared library: {}", libraries[library_index]); 459 library_index++; 460 } else if (entry.tag() == DT_RPATH) { 461 outln("Library rpath: {}", object->rpath()); 462 } else if (entry.tag() == DT_RUNPATH) { 463 outln("Library runpath: {}", object->runpath()); 464 } else if (entry.tag() == DT_SONAME) { 465 outln("Library soname: {}", object->soname()); 466 } else { 467 outln("{:#08x}", entry.val()); 468 } 469 }); 470 } 471 472 if (!found_dynamic_section) 473 outln("No dynamic section in this file."); 474 475 outln(); 476 } 477 478 if (display_relocations) { 479 if (elf_image.is_dynamic()) { 480 if (!object->relocation_section().entry_count()) { 481 outln("Relocation section '{}' at offset {:#08x} contains zero entries:", object->relocation_section().name(), object->relocation_section().offset()); 482 } else { 483 outln("Relocation section '{}' at offset {:#08x} contains {} entries:", object->relocation_section().name(), object->relocation_section().offset(), object->relocation_section().entry_count()); 484 outln(" Offset{} Type Sym Value{} Sym Name", addr_padding, addr_padding); 485 object->relocation_section().for_each_relocation([](const ELF::DynamicObject::Relocation& reloc) { 486 out(" {:p} ", reloc.offset()); 487 out(" {:18} ", object_relocation_type_to_string(reloc.type())); 488 out(" {:p} ", reloc.symbol().value()); 489 out(" {}", reloc.symbol().name()); 490 outln(); 491 }); 492 } 493 outln(); 494 495 if (!object->plt_relocation_section().entry_count()) { 496 outln("Relocation section '{}' at offset {:#08x} contains zero entries:", object->plt_relocation_section().name(), object->plt_relocation_section().offset()); 497 } else { 498 outln("Relocation section '{}' at offset {:#08x} contains {} entries:", object->plt_relocation_section().name(), object->plt_relocation_section().offset(), object->plt_relocation_section().entry_count()); 499 outln(" Offset{} Type Sym Value{} Sym Name", addr_padding, addr_padding); 500 object->plt_relocation_section().for_each_relocation([](const ELF::DynamicObject::Relocation& reloc) { 501 out(" {:p} ", reloc.offset()); 502 out(" {:18} ", object_relocation_type_to_string(reloc.type())); 503 out(" {:p} ", reloc.symbol().value()); 504 out(" {}", reloc.symbol().name()); 505 outln(); 506 }); 507 } 508 509 outln(); 510 511 size_t relr_count = 0; 512 object->for_each_relr_relocation([&relr_count](auto) { ++relr_count; }); 513 if (relr_count != 0) { 514 outln("Relocation section '.relr.dyn' at offset {:#08x} contains {} entries:", object->relr_relocation_section().offset(), object->relr_relocation_section().entry_count()); 515 outln("{:>8x} offsets", relr_count); 516 object->for_each_relr_relocation([](auto offset) { outln("{:p}", offset); }); 517 } 518 } else { 519 outln("No relocations in this file."); 520 } 521 522 outln(); 523 } 524 525 if (display_unwind_info) { 526 // TODO: Unwind info 527 outln("Decoding of unwind sections for machine type {} is not supported.", ELF::Image::object_machine_type_to_string(header.e_machine).value_or("?"sv)); 528 outln(); 529 } 530 531 if (display_core_notes) { 532 auto found_notes = false; 533 elf_image.for_each_program_header([&found_notes](const ELF::Image::ProgramHeader& program_header) { 534 if (program_header.type() != PT_NOTE) 535 return; 536 537 found_notes = true; 538 539 outln("Displaying notes section '{}' at offset {:#08x} of length {:#08x}:", object_program_header_type_to_string(program_header.type()), program_header.offset(), program_header.size_in_image()); 540 541 // FIXME: Parse CORE notes. Notes are in JSON format on SerenityOS, but vary between systems. 542 outln("{}", program_header.raw_data()); 543 }); 544 545 if (!found_notes) 546 outln("No core notes in this file."); 547 548 outln(); 549 } 550 551 if (display_dynamic_symbol_table || display_symbol_table) { 552 auto found_dynamic_symbol_table = false; 553 554 if (elf_image.is_dynamic()) { 555 elf_image.for_each_section([&found_dynamic_symbol_table](const ELF::Image::Section& section) { 556 if (section.name() != ELF_DYNSYM) 557 return IterationDecision::Continue; 558 559 found_dynamic_symbol_table = true; 560 561 if (!section.entry_count()) { 562 outln("Symbol table '{}' contains zero entries.", ELF_DYNSYM); 563 } else { 564 outln("Symbol table '{}' contains {} entries.", ELF_DYNSYM, section.entry_count()); 565 } 566 567 return IterationDecision::Break; 568 }); 569 570 if (object->symbol_count()) { 571 // FIXME: Add support for init/fini/start/main sections 572 outln(" Num: Value{} Size{} Type Bind Name", addr_padding, addr_padding); 573 object->for_each_symbol([](const ELF::DynamicObject::Symbol& sym) { 574 out(" {:>4}: ", sym.index()); 575 out("{:p} ", sym.value()); 576 out("{:p} ", sym.size()); 577 out("{:8} ", object_symbol_type_to_string(sym.type())); 578 out("{:8} ", object_symbol_binding_to_string(sym.bind())); 579 out("{}", sym.name()); 580 outln(); 581 }); 582 } 583 } 584 585 if (!found_dynamic_symbol_table) 586 outln("No dynamic symbol information for this file."); 587 588 outln(); 589 } 590 591 if (display_symbol_table) { 592 if (elf_image.symbol_count()) { 593 outln("Symbol table '{}' contains {} entries:", ELF_SYMTAB, elf_image.symbol_count()); 594 outln(" Num: Value{} Size{} Type Bind Name", addr_padding, addr_padding); 595 596 elf_image.for_each_symbol([](const ELF::Image::Symbol& sym) { 597 out(" {:>4}: ", sym.index()); 598 out("{:p} ", sym.value()); 599 out("{:p} ", sym.size()); 600 out("{:8} ", object_symbol_type_to_string(sym.type())); 601 out("{:8} ", object_symbol_binding_to_string(sym.bind())); 602 out("{}", sym.name()); 603 outln(); 604 }); 605 } else { 606 outln("Symbol table '{}' contains zero entries.", ELF_SYMTAB); 607 } 608 outln(); 609 } 610 611 if (display_hardening) { 612 outln("Security Hardening:"); 613 outln("RELRO Stack Canary NX PIE RPATH RUNPATH Symbols "); 614 615 bool relro = false; 616 elf_image.for_each_program_header([&relro](const ELF::Image::ProgramHeader& program_header) { 617 if (program_header.type() == PT_GNU_RELRO) { 618 relro = true; 619 return IterationDecision::Break; 620 } 621 return IterationDecision::Continue; 622 }); 623 624 bool full_relro = false; 625 if (relro) { 626 object->for_each_dynamic_entry([&full_relro](const ELF::DynamicObject::DynamicEntry& entry) { 627 if (entry.tag() == DT_BIND_NOW) { 628 full_relro = true; 629 return IterationDecision::Break; 630 } 631 return IterationDecision::Continue; 632 }); 633 if (full_relro) 634 out("\033[0;32m{:13}\033[0m ", "Full RELRO"); 635 else 636 out("\033[0;33m{:13}\033[0m ", "Partial RELRO"); 637 } else { 638 out("\033[0;31m{:13}\033[0m ", "No RELRO"); 639 } 640 641 bool canary = false; 642 elf_image.for_each_symbol([&canary](const ELF::Image::Symbol& sym) { 643 if (sym.name() == "__stack_chk_fail" || sym.name() == "__intel_security_cookie") { 644 canary = true; 645 return IterationDecision::Break; 646 } 647 return IterationDecision::Continue; 648 }); 649 650 if (canary) 651 out("\033[0;32m{:12}\033[0m ", "Canary found"); 652 else 653 out("\033[0;31m{:12}\033[0m ", "No canary"); 654 655 bool nx = false; 656 elf_image.for_each_program_header([&nx](const ELF::Image::ProgramHeader& program_header) { 657 if (program_header.type() == PT_GNU_STACK) { 658 if (program_header.flags() & PF_X) 659 nx = false; 660 else 661 nx = true; 662 return IterationDecision::Break; 663 } 664 return IterationDecision::Continue; 665 }); 666 667 if (nx) 668 out("\033[0;32m{:12}\033[0m ", "NX enabled"); 669 else 670 out("\033[0;31m{:12}\033[0m ", "NX disabled"); 671 672 bool pie = false; 673 if (header.e_type == ET_REL || header.e_type == ET_DYN) 674 pie = true; 675 676 if (pie) 677 out("\033[0;32m{:12}\033[0m ", "PIE enabled"); 678 else 679 out("\033[0;31m{:12}\033[0m ", "No PIE"); 680 681 StringView rpath; 682 if (elf_image.is_dynamic()) 683 rpath = object->rpath(); 684 685 if (rpath.is_empty()) 686 out("\033[0;32m{:12}\033[0m ", "No RPATH"); 687 else 688 out("\033[0;31m{:12}\033[0m ", rpath); 689 690 StringView runpath; 691 if (elf_image.is_dynamic()) 692 runpath = object->runpath(); 693 694 if (runpath.is_empty()) 695 out("\033[0;32m{:12}\033[0m ", "No RUNPATH"); 696 else 697 out("\033[0;31m{:12}\033[0m ", runpath); 698 699 out("{} symbols", elf_image.symbol_count()); 700 outln(); 701 } 702 703 if (!string_dump_section.is_null()) { 704 auto maybe_section = elf_image.lookup_section(string_dump_section); 705 if (maybe_section.has_value()) { 706 outln("String dump of section \'{}\':", string_dump_section); 707 StringView data(maybe_section->raw_data(), maybe_section->size()); 708 data.for_each_split_view('\0', SplitBehavior::Nothing, [&data](auto string) { 709 auto offset = string.characters_without_null_termination() - data.characters_without_null_termination(); 710 outln("[{:6x}] {}", offset, string); 711 }); 712 } else { 713 warnln("Could not find section \'{}\'", string_dump_section); 714 return 1; 715 } 716 } 717 return 0; 718}