readelf.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  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 <LibELF/Image.h>
  32. #include <LibELF/Validation.h>
  33. #include <ctype.h>
  34. #include <stdio.h>
  35. static const char* object_file_type_to_string(Elf32_Half type)
  36. {
  37. switch (type) {
  38. case ET_NONE:
  39. return "None";
  40. case ET_REL:
  41. return "Relocatable";
  42. case ET_EXEC:
  43. return "Executable";
  44. case ET_DYN:
  45. return "Shared object";
  46. case ET_CORE:
  47. return "Core";
  48. default:
  49. return "(?)";
  50. }
  51. }
  52. static const char* object_machine_type_to_string(Elf32_Half type)
  53. {
  54. switch (type) {
  55. case ET_NONE:
  56. return "None";
  57. case EM_M32:
  58. return "AT&T WE 32100";
  59. case EM_SPARC:
  60. return "SPARC";
  61. case EM_386:
  62. return "Intel 80386";
  63. case EM_68K:
  64. return "Motorola 68000";
  65. case EM_88K:
  66. return "Motorola 88000";
  67. case EM_486:
  68. return "Intel 80486";
  69. case EM_860:
  70. return "Intel 80860";
  71. case EM_MIPS:
  72. return "MIPS R3000 Big-Endian only";
  73. default:
  74. return "(?)";
  75. }
  76. }
  77. static const char* object_program_header_type_to_string(Elf32_Word type)
  78. {
  79. switch (type) {
  80. case PT_NULL:
  81. return "NULL";
  82. case PT_LOAD:
  83. return "LOAD";
  84. case PT_DYNAMIC:
  85. return "DYNAMIC";
  86. case PT_INTERP:
  87. return "INTERP";
  88. case PT_NOTE:
  89. return "NOTE";
  90. case PT_SHLIB:
  91. return "SHLIB";
  92. case PT_PHDR:
  93. return "PHDR";
  94. case PT_TLS:
  95. return "TLS";
  96. case PT_LOOS:
  97. return "LOOS";
  98. case PT_HIOS:
  99. return "HIOS";
  100. case PT_LOPROC:
  101. return "LOPROC";
  102. case PT_HIPROC:
  103. return "HIPROC";
  104. case PT_GNU_EH_FRAME:
  105. return "GNU_EH_FRAME";
  106. case PT_GNU_RELRO:
  107. return "GNU_RELRO";
  108. case PT_GNU_STACK:
  109. return "GNU_STACK";
  110. case PT_OPENBSD_RANDOMIZE:
  111. return "OPENBSD_RANDOMIZE";
  112. case PT_OPENBSD_WXNEEDED:
  113. return "OPENBSD_WXNEEDED";
  114. case PT_OPENBSD_BOOTDATA:
  115. return "OPENBSD_BOOTDATA";
  116. default:
  117. return "(?)";
  118. }
  119. }
  120. static const char* object_section_header_type_to_string(Elf32_Word type)
  121. {
  122. switch (type) {
  123. case SHT_NULL:
  124. return "NULL";
  125. case SHT_PROGBITS:
  126. return "PROGBITS";
  127. case SHT_SYMTAB:
  128. return "SYMTAB";
  129. case SHT_STRTAB:
  130. return "STRTAB";
  131. case SHT_RELA:
  132. return "RELA";
  133. case SHT_HASH:
  134. return "HASH";
  135. case SHT_DYNAMIC:
  136. return "DYNAMIC";
  137. case SHT_NOTE:
  138. return "NOTE";
  139. case SHT_NOBITS:
  140. return "NOBITS";
  141. case SHT_REL:
  142. return "REL";
  143. case SHT_SHLIB:
  144. return "SHLIB";
  145. case SHT_DYNSYM:
  146. return "DYNSYM";
  147. case SHT_NUM:
  148. return "NUM";
  149. case SHT_INIT_ARRAY:
  150. return "INIT_ARRAY";
  151. case SHT_FINI_ARRAY:
  152. return "FINI_ARRAY";
  153. case SHT_PREINIT_ARRAY:
  154. return "PREINIT_ARRAY";
  155. case SHT_GROUP:
  156. return "GROUP";
  157. case SHT_SYMTAB_SHNDX:
  158. return "SYMTAB_SHNDX";
  159. case SHT_LOOS:
  160. return "SOOS";
  161. case SHT_SUNW_dof:
  162. return "SUNW_dof";
  163. case SHT_GNU_LIBLIST:
  164. return "GNU_LIBLIST";
  165. case SHT_SUNW_move:
  166. return "SUNW_move";
  167. case SHT_SUNW_syminfo:
  168. return "SUNW_syminfo";
  169. case SHT_SUNW_verdef:
  170. return "SUNW_verdef";
  171. case SHT_SUNW_verneed:
  172. return "SUNW_verneed";
  173. case SHT_SUNW_versym: // or SHT_HIOS
  174. return "SUNW_versym";
  175. case SHT_LOPROC:
  176. return "LOPROC";
  177. case SHT_HIPROC:
  178. return "HIPROC";
  179. case SHT_LOUSER:
  180. return "LOUSER";
  181. case SHT_HIUSER:
  182. return "HIUSER";
  183. case SHT_GNU_HASH:
  184. return "GNU_HASH";
  185. default:
  186. return "(?)";
  187. }
  188. }
  189. static const char* object_symbol_type_to_string(Elf32_Word type)
  190. {
  191. switch (type) {
  192. case STT_NOTYPE:
  193. return "NOTYPE";
  194. case STT_OBJECT:
  195. return "OBJECT";
  196. case STT_FUNC:
  197. return "FUNC";
  198. case STT_SECTION:
  199. return "SECTION";
  200. case STT_FILE:
  201. return "FILE";
  202. case STT_TLS:
  203. return "TLS";
  204. case STT_LOPROC:
  205. return "LOPROC";
  206. case STT_HIPROC:
  207. return "HIPROC";
  208. default:
  209. return "(?)";
  210. }
  211. }
  212. static const char* object_symbol_binding_to_string(Elf32_Word type)
  213. {
  214. switch (type) {
  215. case STB_LOCAL:
  216. return "LOCAL";
  217. case STB_GLOBAL:
  218. return "GLOBAL";
  219. case STB_WEAK:
  220. return "WEAK";
  221. case STB_NUM:
  222. return "NUM";
  223. case STB_LOPROC:
  224. return "LOPROC";
  225. case STB_HIPROC:
  226. return "HIPROC";
  227. default:
  228. return "(?)";
  229. }
  230. }
  231. int main(int argc, char** argv)
  232. {
  233. if (pledge("stdio rpath", nullptr) < 0) {
  234. perror("pledge");
  235. return 1;
  236. }
  237. const char* path;
  238. static bool display_all = false;
  239. static bool display_elf_header = false;
  240. static bool display_program_headers = false;
  241. static bool display_section_headers = false;
  242. static bool display_headers = false;
  243. static bool display_symbol_table = false;
  244. static bool display_dynamic_symbol_table = false;
  245. static bool display_core_notes = false;
  246. static bool display_relocations = false;
  247. static bool display_unwind_info = false;
  248. static bool display_dynamic_section = false;
  249. Core::ArgsParser args_parser;
  250. args_parser.add_option(display_all, "Display all", "all", 'a');
  251. args_parser.add_option(display_elf_header, "Display ELF header", "file-header", 'h');
  252. args_parser.add_option(display_program_headers, "Display program headers", "program-headers", 'l');
  253. args_parser.add_option(display_section_headers, "Display section headers", "section-headers", 'S');
  254. args_parser.add_option(display_headers, "Equivalent to: -h -l -S", "headers", 'e');
  255. args_parser.add_option(display_symbol_table, "Display the symbol table", "syms", 's');
  256. args_parser.add_positional_argument(path, "ELF path", "path");
  257. args_parser.parse(argc, argv);
  258. if (argc < 3) {
  259. args_parser.print_usage(stderr, argv[0]);
  260. return -1;
  261. }
  262. if (display_headers) {
  263. display_elf_header = true;
  264. display_program_headers = true;
  265. display_section_headers = true;
  266. }
  267. if (display_all) {
  268. display_elf_header = true;
  269. display_program_headers = true;
  270. display_section_headers = true;
  271. display_symbol_table = true;
  272. }
  273. auto file_or_error = MappedFile::map(path);
  274. if (file_or_error.is_error()) {
  275. warnln("Unable to map file {}: {}", path, file_or_error.error());
  276. return -1;
  277. }
  278. auto elf_image_data = file_or_error.value()->bytes();
  279. ELF::Image executable_elf(elf_image_data);
  280. if (!executable_elf.is_valid()) {
  281. fprintf(stderr, "File is not a valid ELF object\n");
  282. return -1;
  283. }
  284. String interpreter_path;
  285. 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)) {
  286. fprintf(stderr, "Invalid ELF headers\n");
  287. return -1;
  288. }
  289. if (executable_elf.is_dynamic() && interpreter_path.is_null()) {
  290. fprintf(stderr, "Warning: Dynamic ELF object has no interpreter path\n");
  291. }
  292. ELF::Image interpreter_image(elf_image_data);
  293. if (!interpreter_image.is_valid()) {
  294. fprintf(stderr, "ELF image is invalid\n");
  295. return -1;
  296. }
  297. auto& header = *reinterpret_cast<const Elf32_Ehdr*>(elf_image_data.data());
  298. if (display_elf_header) {
  299. printf("ELF header:\n");
  300. String magic = String::format("%s", header.e_ident);
  301. printf(" Magic: ");
  302. for (size_t i = 0; i < magic.length(); i++) {
  303. if (isprint(magic[i])) {
  304. printf("%c ", magic[i]);
  305. } else {
  306. printf("%02x ", magic[i]);
  307. }
  308. }
  309. printf("\n");
  310. printf(" Type: %d (%s)\n", header.e_type, object_file_type_to_string(header.e_type));
  311. printf(" Machine: %u (%s)\n", header.e_machine, object_machine_type_to_string(header.e_machine));
  312. printf(" Version: 0x%x\n", header.e_version);
  313. printf(" Entry point address: 0x%x\n", header.e_entry);
  314. printf(" Start of program headers: %u (bytes into file)\n", header.e_phoff);
  315. printf(" Start of section headers: %u (bytes into file)\n", header.e_shoff);
  316. printf(" Flags: 0x%x\n", header.e_flags);
  317. printf(" Size of this header: %u (bytes)\n", header.e_ehsize);
  318. printf(" Size of program headers: %u (bytes)\n", header.e_phentsize);
  319. printf(" Number of program headers: %u\n", header.e_phnum);
  320. printf(" Size of section headers: %u (bytes)\n", header.e_shentsize);
  321. printf(" Number of section headers: %u\n", header.e_shnum);
  322. printf(" Section header string table index: %u\n", header.e_shstrndx);
  323. printf("\n");
  324. }
  325. if (display_section_headers) {
  326. if (!display_all) {
  327. printf("There are %u section headers, starting at offset 0x%x:\n", header.e_shnum, header.e_shoff);
  328. printf("\n");
  329. }
  330. if (!interpreter_image.section_count()) {
  331. printf("There are no sections in this file.\n");
  332. } else {
  333. printf("Section Headers:\n");
  334. printf(" Name Type Address Offset Size Flags\n");
  335. interpreter_image.for_each_section([](const ELF::Image::Section& section) {
  336. printf(" %-15s ", section.name().characters_without_null_termination());
  337. printf("%-15s ", object_section_header_type_to_string(section.type()));
  338. printf("%08x ", section.address());
  339. printf("%08x ", section.offset());
  340. printf("%08x ", section.size());
  341. printf("%u", section.flags());
  342. printf("\n");
  343. return IterationDecision::Continue;
  344. });
  345. }
  346. printf("\n");
  347. }
  348. if (display_program_headers) {
  349. if (!display_all) {
  350. printf("Elf file type is %d (%s)\n", header.e_type, object_file_type_to_string(header.e_type));
  351. printf("Entry point 0x%x\n", header.e_entry);
  352. printf("There are %u program headers, starting at offset %u\n", header.e_phnum, header.e_phoff);
  353. printf("\n");
  354. }
  355. printf("Program Headers:\n");
  356. printf(" Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align\n");
  357. interpreter_image.for_each_program_header([](const ELF::Image::ProgramHeader& program_header) {
  358. printf(" %-14s ", object_program_header_type_to_string(program_header.type()));
  359. printf("0x%08x ", program_header.offset());
  360. printf("%p ", program_header.vaddr().as_ptr());
  361. printf("%p ", program_header.vaddr().as_ptr()); // FIXME: assumes PhysAddr = VirtAddr
  362. printf("0x%08x ", program_header.size_in_image());
  363. printf("0x%08x ", program_header.size_in_memory());
  364. printf("%04x ", program_header.flags());
  365. printf("0x%08x", program_header.alignment());
  366. printf("\n");
  367. if (program_header.type() == PT_INTERP)
  368. printf(" [Interpreter: %s]\n", program_header.raw_data());
  369. return IterationDecision::Continue;
  370. });
  371. printf("\n");
  372. }
  373. if (display_dynamic_section) {
  374. // TODO: Dynamic section
  375. }
  376. if (display_relocations) {
  377. // TODO: Relocations section
  378. }
  379. if (display_unwind_info) {
  380. // TODO: Unwind info
  381. }
  382. if (display_core_notes) {
  383. // TODO: Core notes
  384. }
  385. if (display_dynamic_symbol_table || display_symbol_table) {
  386. // TODO: dynamic symbol table
  387. if (!interpreter_image.symbol_count()) {
  388. printf("Dynamic symbol information is not available for displaying symbols.\n");
  389. printf("\n");
  390. }
  391. }
  392. if (display_symbol_table) {
  393. if (interpreter_image.symbol_count()) {
  394. printf("Symbol table '.symtab' contains %u entries:\n", interpreter_image.symbol_count());
  395. printf(" Num: Value Size Type Bind Name\n");
  396. interpreter_image.for_each_symbol([](const ELF::Image::Symbol& sym) {
  397. printf(" %4u: ", sym.index());
  398. printf("%08x ", sym.value());
  399. printf("%08x ", sym.size());
  400. printf("%-8s ", object_symbol_type_to_string(sym.type()));
  401. printf("%-8s ", object_symbol_binding_to_string(sym.bind()));
  402. printf("%s", sym.name().characters_without_null_termination());
  403. printf("\n");
  404. return IterationDecision::Continue;
  405. });
  406. }
  407. printf("\n");
  408. }
  409. return 0;
  410. }