readelf.cpp 29 KB

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