Serenity Operating System
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}