readelf.cpp 31 KB

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