readelf.cpp 26 KB

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