readelf.cpp 29 KB

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