elfinspect.c (38774B)
1 /* See LICENSE for license details. */ 2 3 #define local_persist static 4 #define global static 5 #define function static 6 7 #ifdef __ARM_ARCH_ISA_A64 8 #define debugbreak() asm("brk 0xf000") 9 #elif __x86_64__ 10 #define debugbreak() asm("int3; nop") 11 #else 12 #error Unsupported Architecture 13 #endif 14 #define assert(c) do { if (!(c)) debugbreak(); } while (0) 15 #define TODO(c) assert(c) 16 17 #ifdef __clang__ 18 #define read_only __attribute__((section(".rodata"))) 19 #else 20 /* TODO(rnp): how to do this with gcc */ 21 #define read_only 22 #endif 23 24 #define countof(a) (sizeof(a) / sizeof(*a)) 25 26 #define static_assert(c, msg) _Static_assert(c, msg) 27 28 #define MIN(a, b) ((a) < (b) ? (a) : (b)) 29 #define MAX(a, b) ((a) < (b) ? (b) : (a)) 30 31 #define KB(a) ((u64)a << 10ULL) 32 #define MB(a) ((u64)a << 20ULL) 33 34 typedef struct {u8 *beg, *end;} Arena; 35 36 #define str8(s) (str8){.len = countof(s) - 1, .data = (u8 *)s} 37 typedef struct { sz len; u8 *data;} str8; 38 39 typedef struct { 40 u8 *data; 41 sz index; 42 sz count; 43 b32 errors; 44 } str8_stream; 45 46 typedef struct { 47 sz *max_column_widths; 48 49 str8 *data; 50 s16 capacity; 51 s16 count; 52 53 u16 columns; 54 } Table; 55 56 typedef struct { 57 u8 *argv0; 58 struct { 59 u8 **data; 60 s16 capacity; 61 s16 count; 62 } file_names; 63 64 b32 sections; 65 b32 header; 66 } Options; 67 68 /* NOTE: platform api; defined here so that other platform symbols are not visible to this TU */ 69 function str8 os_map_file(u8 *); 70 71 /* X(name, value, pretty) */ 72 #define ELF_FORMATS \ 73 X(EF_NONE, 0, "Unknown") \ 74 X(EF_32, 1, "ELF32") \ 75 X(EF_64, 2, "ELF64") 76 77 #define ELF_ENDIANNESS \ 78 X(EEK_NONE, 0, "Unknown") \ 79 X(EEK_LITTLE, 1, "Little-Endian") \ 80 X(EEK_BIG, 2, "Big-Endian") 81 82 #define ELF_OS_ABI \ 83 X(ELF_ABI_SYSV, 0x00, "System-V") \ 84 X(ELF_ABI_HPUX, 0x01, "HP-UX") \ 85 X(ELF_ABI_NETBSD, 0x02, "NetBSD") \ 86 X(ELF_ABI_GNU, 0x03, "GNU Hurd") \ 87 X(ELF_ABI_SOLARIS, 0x06, "Solaris") \ 88 X(ELF_ABI_AIX, 0x07, "AIX") \ 89 X(ELF_ABI_IRIX, 0x08, "IRIX") \ 90 X(ELF_ABI_FREEBSD, 0x09, "FreeBSD") \ 91 X(ELF_ABI_TRU64, 0x0a, "Tru64") \ 92 X(ELF_ABI_MODESTO, 0x0b, "Novel Modesto") \ 93 X(ELF_ABI_OPENBSD, 0x0c, "OpenBSD") \ 94 X(ELF_ABI_OPENVMS, 0x0d, "OpenVMS") \ 95 X(ELF_ABI_NONSTOP, 0x0e, "NonStop Kernel") \ 96 X(ELF_ABI_AROS, 0x0f, "AROS") \ 97 X(ELF_ABI_FENIX, 0x10, "Fenix") \ 98 X(ELF_ABI_ARM, 0x61, "ARM") \ 99 X(ELF_ABI_STANDALONE, 0xff, "Free Standing") 100 101 #define ELF_KINDS \ 102 X(ELF_KIND_NONE, 0x0000, "Unknown") \ 103 X(ELF_KIND_REL, 0x0001, "Relocatable") \ 104 X(ELF_KIND_EXEC, 0x0002, "Executable") \ 105 X(ELF_KIND_DYN, 0x0003, "Shared Object") \ 106 X(ELF_KIND_CORE, 0x0004, "Core Dump") 107 108 #define X(name, value, pretty) name = value, 109 typedef enum { ELF_FORMATS } ELFFormat; 110 typedef enum { ELF_ENDIANNESS } ELFEndianKind; 111 typedef enum { ELF_OS_ABI } ELFABIKind; 112 typedef enum { ELF_KINDS } ELFKind; 113 #undef X 114 115 /* X(ctype, name) */ 116 #define ELF_HEADER_MEMBERS \ 117 X(ELFFormat, format) \ 118 X(ELFEndianKind, endianness) \ 119 X(ELFABIKind, abi) \ 120 X(ELFKind, kind) \ 121 X(u16, abi_version) \ 122 X(u16, machine) \ 123 X(u32, version) \ 124 X(u64, entry_point_offset) \ 125 X(u64, program_header_offset) \ 126 X(u64, section_header_offset) \ 127 X(u32, flags) \ 128 X(u16, elf_header_size) \ 129 X(u16, program_header_entry_size) \ 130 X(u16, program_header_count) \ 131 X(u16, section_header_entry_size) \ 132 X(u16, section_header_count) \ 133 X(u16, section_header_name_table_index) 134 135 #define X(ctype, name) ctype name; 136 typedef struct {ELF_HEADER_MEMBERS} ELFHeader; 137 #undef X 138 139 /* X(name, value, pretty) */ 140 /* NOTE: base section kinds; extended kinds handled directly */ 141 #define ELFSectionKinds \ 142 X(NULL, 0x00, "null") \ 143 X(PROGBITS, 0x01, "progdata") \ 144 X(SYMBOL_TABLE, 0x02, "symtab") \ 145 X(STR_TABLE, 0x03, "strtab") \ 146 X(RELA, 0x04, "rela") \ 147 X(HASH, 0x05, "symhashtab") \ 148 X(DYNAMIC, 0x06, "dynamic") \ 149 X(NOTE, 0x07, "notes") \ 150 X(NOBITS, 0x08, "nobits") \ 151 X(REL, 0x09, "rel") \ 152 X(SHLIB, 0x0A, "shlib") \ 153 X(DYNSYM, 0x0B, "dynsym") \ 154 X(INIT_ARRAY, 0x0E, "init_array") \ 155 X(FINI_ARRAY, 0x0F, "fini_array") \ 156 X(PREINIT_ARR, 0x10, "preinit_array") \ 157 X(GROUP, 0x11, "group") \ 158 X(SYMTAB_SHND, 0x12, "extended symtab") \ 159 X(RELR, 0x13, "relr") \ 160 X(NUM, 0x14, "number") 161 162 163 #define X(name, value, pretty) ELFSectionKind_ ## name = value, 164 typedef enum {ELFSectionKinds ELFSectionKind_COUNT} ELFSectionKind; 165 #undef X 166 167 /* X(ctype, read32, read64, name) */ 168 #define ELF_SECTION_HEADER_MEMBERS \ 169 X(u32, u32, u32, name_table_offset) \ 170 X(ELFSectionKind, u32, u32, kind) \ 171 X(u64, u32, u64, flags) \ 172 X(u64, u32, u64, addr) \ 173 X(u64, u32, u64, offset) \ 174 X(u64, u32, u64, size) \ 175 X(u32, u32, u32, link) \ 176 X(u32, u32, u32, info) \ 177 X(u64, u32, u64, addralign) \ 178 X(u64, u32, u64, entsize) 179 180 #define X(ctype, r32, r64, name) ctype name; 181 typedef struct { 182 str8 name; 183 ELF_SECTION_HEADER_MEMBERS 184 } ELFSectionHeader; 185 #undef X 186 187 typedef struct { 188 ELFSectionHeader header; 189 str8 store; 190 } ELFSection; 191 192 typedef enum { 193 DUT_UNKNOWN = 0x00, 194 DUT_COMPILE = 0x01, 195 DUT_TYPE = 0x02, 196 DUT_PARTIAL = 0x03, 197 DUT_SKELETON = 0x04, 198 DUT_SPLIT_COMPILE = 0x05, 199 DUT_SPLIT_TYPE = 0x06, 200 DUT_LO_USER = 0x80, 201 DUT_HI_USER = 0xff 202 } DWARFUnitKind; 203 204 typedef struct { 205 u64 length; 206 u64 abbreviation_offset; 207 DWARFUnitKind kind; 208 u16 version; 209 u8 address_size; 210 u8 dwarf_64; 211 } DWARFUnitHeader; 212 213 typedef enum { 214 DATK_SIBLING = 0x01, 215 DATK_LOCATION = 0x02, 216 DATK_NAME = 0x03, 217 DATK_ORDERING = 0x09, 218 DATK_BYTE_SIZE = 0x0b, 219 DATK_BIT_OFFSET = 0x0c, 220 DATK_BIT_SIZE = 0x0d, 221 DATK_STMT_LIST = 0x10, 222 DATK_LOW_PC = 0x11, 223 DATK_HIGH_PC = 0x12, 224 DATK_LANGUAGE = 0x13, 225 DATK_DISCR = 0x15, 226 DATK_DISCR_VALUE = 0x16, 227 DATK_VISIBILITY = 0x17, 228 DATK_IMPORT = 0x18, 229 DATK_STRING_LENGTH = 0x19, 230 DATK_COMMON_REFERENCE = 0x1a, 231 DATK_COMP_DIR = 0x1b, 232 DATK_CONST_VALUE = 0x1c, 233 DATK_CONTAINING_TYPE = 0x1d, 234 DATK_DEFAULT_VALUE = 0x1e, 235 DATK_INLINE = 0x20, 236 DATK_IS_OPTIONAL = 0x21, 237 DATK_LOWER_BOUND = 0x22, 238 DATK_PRODUCER = 0x25, 239 DATK_PROTOTYPED = 0x27, 240 DATK_RETURN_ADDR = 0x2a, 241 DATK_START_SCOPE = 0x2c, 242 DATK_BIT_STRIDE = 0x2e, 243 DATK_UPPER_BOUND = 0x2f, 244 DATK_ABSTRACT_ORIGIN = 0x31, 245 DATK_ACCESSIBILITY = 0x32, 246 DATK_ADDRESS_CLASS = 0x33, 247 DATK_ARTIFICIAL = 0x34, 248 DATK_BASE_TYPES = 0x35, 249 DATK_CALLING_CONVENTION = 0x36, 250 DATK_COUNT = 0x37, 251 DATK_DATA_MEMBER_LOCATION = 0x38, 252 DATK_DECL_COLUMN = 0x39, 253 DATK_DECL_FILE = 0x3a, 254 DATK_DECL_LINE = 0x3b, 255 DATK_DECLARATION = 0x3c, 256 DATK_DISCR_LIST = 0x3d, 257 DATK_ENCODING = 0x3e, 258 DATK_EXTERNAL = 0x3f, 259 DATK_FRAME_BASE = 0x40, 260 DATK_FRIEND = 0x41, 261 DATK_IDENTIFIER_CASE = 0x42, 262 DATK_MACRO_INFO = 0x43, 263 DATK_NAMELIST_ITEM = 0x44, 264 DATK_PRIORITY = 0x45, 265 DATK_SEGMENT = 0x46, 266 DATK_SPECIFICATION = 0x47, 267 DATK_STATIC_LINK = 0x48, 268 DATK_TYPE = 0x49, 269 DATK_USE_LOCATION = 0x4a, 270 DATK_VARIABLE_PARAMETER = 0x4b, 271 DATK_VIRTUALITY = 0x4c, 272 DATK_VTABLE_ELEM_LOCATION = 0x4d, 273 DATK_ALLOCATED = 0x4e, 274 DATK_ASSOCIATED = 0x4f, 275 DATK_DATA_LOCATION = 0x50, 276 DATK_BYTE_STRIDE = 0x51, 277 DATK_ENTRY_PC = 0x52, 278 DATK_USE_UTF8 = 0x53, 279 DATK_EXTENSION = 0x54, 280 DATK_RANGES = 0x55, 281 DATK_TRAMPOLINE = 0x56, 282 DATK_CALL_COLUMN = 0x57, 283 DATK_CALL_FILE = 0x58, 284 DATK_CALL_LINE = 0x59, 285 DATK_DESCRIPTION = 0x5a, 286 DATK_BINARY_SCALE = 0x5b, 287 DATK_DECIMAL_SCALE = 0x5c, 288 DATK_SMALL = 0x5d, 289 DATK_DECIMAL_SIGN = 0x5e, 290 DATK_DIGIT_COUNT = 0x5f, 291 DATK_PICTURE_STRING = 0x60, 292 DATK_MUTABLE = 0x61, 293 DATK_THREADS_SCALED = 0x62, 294 DATK_EXPLICIT = 0x63, 295 DATK_OBJECT_POINTER = 0x64, 296 DATK_ENDIANITY = 0x65, 297 DATK_ELEMENTAL = 0x66, 298 DATK_PURE = 0x67, 299 DATK_RECURSIVE = 0x68, 300 DATK_SIGNATURE = 0x69, 301 DATK_MAIN_SUBPROGRAM = 0x6a, 302 DATK_DATA_BIT_OFFSET = 0x6b, 303 DATK_CONST_EXPR = 0x6c, 304 DATK_ENUM_CLASS = 0x6d, 305 DATK_LINKAGE_NAME = 0x6e, 306 DATK_STRING_LENGTH_BIT_SIZE = 0x6f, 307 DATK_STRING_LENGTH_BYTE_SIZE = 0x70, 308 DATK_RANK = 0x71, 309 DATK_STR_OFFSETS_BASE = 0x72, 310 DATK_ADDR_BASE = 0x73, 311 DATK_RNGLISTS_BASE = 0x74, 312 DATK_DWO_NAME = 0x76, 313 DATK_REFERENCE = 0x77, 314 DATK_RVALUE_REFERENCE = 0x78, 315 DATK_MACROS = 0x79, 316 DATK_CALL_ALL_CALLS = 0x7a, 317 DATK_CALL_ALL_SOURCE_CALLS = 0x7b, 318 DATK_CALL_ALL_TAIL_CALLS = 0x7c, 319 DATK_CALL_RETURN_PC = 0x7d, 320 DATK_CALL_VALUE = 0x7e, 321 DATK_CALL_ORIGIN = 0x7f, 322 DATK_CALL_PARAMETER = 0x80, 323 DATK_CALL_PC = 0x81, 324 DATK_CALL_TAIL_CALL = 0x82, 325 DATK_CALL_TARGET = 0x83, 326 DATK_CALL_TARGET_CLOBBERED = 0x84, 327 DATK_CALL_DATA_LOCATION = 0x85, 328 DATK_CALL_DATA_VALUE = 0x86, 329 DATK_NORETURN = 0x87, 330 DATK_ALIGNMENT = 0x88, 331 DATK_EXPORT_SYMBOLS = 0x89, 332 DATK_DELETED = 0x8a, 333 DATK_DEFAULTED = 0x8b, 334 DATK_LOCLISTS_BASE = 0x8c, 335 DATK_LO_USER = 0x2000, 336 DATK_HI_USER = 0x3fff, 337 } DWARFAttributeKind; 338 339 typedef enum { 340 DFK_ADDR = 0x01, 341 DFK_BLOCK2 = 0x03, 342 DFK_BLOCK4 = 0x04, 343 DFK_DATA2 = 0x05, 344 DFK_DATA4 = 0x06, 345 DFK_DATA8 = 0x07, 346 DFK_STRING = 0x08, 347 DFK_BLOCK = 0x09, 348 DFK_BLOCK1 = 0x0a, 349 DFK_DATA1 = 0x0b, 350 DFK_FLAG = 0x0c, 351 DFK_SDATA = 0x0d, 352 DFK_STRP = 0x0e, 353 DFK_UDATA = 0x0f, 354 DFK_REF_ADDR = 0x10, 355 DFK_REF1 = 0x11, 356 DFK_REF2 = 0x12, 357 DFK_REF4 = 0x13, 358 DFK_REF8 = 0x14, 359 DFK_REF_UDATA = 0x15, 360 DFK_INDIRECT = 0x16, 361 DFK_SEC_OFFSET = 0x17, 362 DFK_EXPRLOC = 0x18, 363 DFK_FLAG_PRESENT = 0x19, 364 DFK_STRX = 0x1a, 365 DFK_ADDRX = 0x1b, 366 DFK_REF_SUP4 = 0x1c, 367 DFK_STRP_SUP = 0x1d, 368 DFK_DATA16 = 0x1e, 369 DFK_LINE_STRP = 0x1f, 370 DFK_REF_SIG8 = 0x20, 371 DFK_IMPLICIT_CONST = 0x21, 372 DFK_LOCLISTX = 0x22, 373 DFK_RNGLISTX = 0x23, 374 DFK_REF_SUP8 = 0x24, 375 DFK_STRX1 = 0x25, 376 DFK_STRX2 = 0x26, 377 DFK_STRX3 = 0x27, 378 DFK_STRX4 = 0x28, 379 DFK_ADDRX1 = 0x29, 380 DFK_ADDRX2 = 0x2a, 381 DFK_ADDRX3 = 0x2b, 382 DFK_ADDRX4 = 0x2c, 383 } DWARFFormKind; 384 385 typedef struct { 386 DWARFAttributeKind kind; 387 DWARFFormKind form_kind; 388 } DWARFAttribute; 389 390 typedef enum { 391 DAK_ARRAY_TYPE = 0x01, 392 DAK_CLASS_TYPE = 0x02, 393 DAK_ENTRY_POINT = 0x03, 394 DAK_ENUMERATION_TYPE = 0x04, 395 DAK_FORMAL_PARAMETER = 0x05, 396 DAK_IMPORTED_DECLARATION = 0x08, 397 DAK_LABEL = 0x0a, 398 DAK_LEXICAL_BLOCK = 0x0b, 399 DAK_MEMBER = 0x0d, 400 DAK_POINTER_TYPE = 0x0f, 401 DAK_REFERENCE_TYPE = 0x10, 402 DAK_COMPILE_UNIT = 0x11, 403 DAK_STRING_TYPE = 0x12, 404 DAK_STRUCTURE_TYPE = 0x13, 405 DAK_SUBROUTINE_TYPE = 0x15, 406 DAK_TYPEDEF = 0x16, 407 DAK_UNION_TYPE = 0x17, 408 DAK_UNSPECIFIED_PARAMETERS = 0x18, 409 DAK_VARIANT = 0x19, 410 DAK_COMMON_BLOCK = 0x1a, 411 DAK_COMMON_INCLUSION = 0x1b, 412 DAK_INHERITANCE = 0x1c, 413 DAK_INLINED_SUBROUTINE = 0x1d, 414 DAK_MODULE = 0x1e, 415 DAK_PTR_TO_MEMBER_TYPE = 0x1f, 416 DAK_SET_TYPE = 0x20, 417 DAK_SUBRANGE_TYPE = 0x21, 418 DAK_WITH_STMT = 0x22, 419 DAK_ACCESS_DECLARATION = 0x23, 420 DAK_BASE_TYPE = 0x24, 421 DAK_CATCH_BLOCK = 0x25, 422 DAK_CONST_TYPE = 0x26, 423 DAK_CONSTANT = 0x27, 424 DAK_ENUMERATOR = 0x28, 425 DAK_FILE_TYPE = 0x29, 426 DAK_FRIEND = 0x2a, 427 DAK_NAMELIST = 0x2b, 428 DAK_NAMELIST_ITEM = 0x2c, 429 DAK_PACKED_TYPE = 0x2d, 430 DAK_SUBPROGRAM = 0x2e, 431 DAK_TEMPLATE_TYPE_PARAMETER = 0x2f, 432 DAK_TEMPLATE_VALUE_PARAMETER = 0x30, 433 DAK_THROWN_TYPE = 0x31, 434 DAK_TRY_BLOCK = 0x32, 435 DAK_VARIANT_PART = 0x33, 436 DAK_VARIABLE = 0x34, 437 DAK_VOLATILE_TYPE = 0x35, 438 DAK_DWARF_PROCEDURE = 0x36, 439 DAK_RESTRICT_TYPE = 0x37, 440 DAK_INTERFACE_TYPE = 0x38, 441 DAK_NAMESPACE = 0x39, 442 DAK_IMPORTED_MODULE = 0x3a, 443 DAK_UNSPECIFIED_TYPE = 0x3b, 444 DAK_PARTIAL_UNIT = 0x3c, 445 DAK_IMPORTED_UNIT = 0x3d, 446 DAK_CONDITION = 0x3f, 447 DAK_SHARED_TYPE = 0x40, 448 DAK_TYPE_UNIT = 0x41, 449 DAK_RVALUE_REFERENCE_TYPE = 0x42, 450 DAK_TEMPLATE_ALIAS = 0x43, 451 DAK_COARRAY_TYPE = 0x44, 452 DAK_GENERIC_SUBRANGE = 0x45, 453 DAK_DYNAMIC_TYPE = 0x46, 454 DAK_ATOMIC_TYPE = 0x47, 455 DAK_CALL_SITE = 0x48, 456 DAK_CALL_SITE_PARAMETER = 0x49, 457 DAK_SKELETON_UNIT = 0x4a, 458 DAK_IMMUTABLE_TYPE = 0x4b, 459 DAK_LO_USER = 0x4080, 460 DAK_HI_USER = 0xffff 461 } DWARFAbbreviationKind; 462 463 typedef struct DWARFAbbreviation { 464 DWARFAbbreviationKind kind; 465 b32 has_children; 466 u64 abbreviation_code; 467 468 DWARFAttribute *data; 469 s16 count; 470 s16 capacity; 471 472 struct DWARFAbbreviation *next; 473 } DWARFAbbreviation; 474 475 #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ 476 function u16 477 u16_host_from_be(u8 *s) 478 { 479 u16 result = 0; 480 result |= s[1]; result <<= 8; 481 result |= s[0]; 482 return result; 483 } 484 485 function u16 486 u16_host_from_le(u8 *s) 487 { 488 u16 result = 0; 489 result |= s[0]; result <<= 8; 490 result |= s[1]; 491 return result; 492 } 493 494 function u32 495 u32_host_from_be(u8 *s) 496 { 497 u32 result = 0; 498 result |= s[3]; result <<= 8; 499 result |= s[2]; result <<= 8; 500 result |= s[1]; result <<= 8; 501 result |= s[0]; 502 return result; 503 } 504 505 function u32 506 u32_host_from_le(u8 *s) 507 { 508 u32 result = 0; 509 result |= s[0]; result <<= 8; 510 result |= s[1]; result <<= 8; 511 result |= s[2]; result <<= 8; 512 result |= s[3]; 513 return result; 514 } 515 516 function u64 517 u64_host_from_be(u8 *s) 518 { 519 u64 result = 0; 520 result |= s[7]; result <<= 8; 521 result |= s[6]; result <<= 8; 522 result |= s[5]; result <<= 8; 523 result |= s[4]; result <<= 8; 524 result |= s[3]; result <<= 8; 525 result |= s[2]; result <<= 8; 526 result |= s[1]; result <<= 8; 527 result |= s[0]; 528 return result; 529 } 530 531 function u64 532 u64_host_from_le(u8 *s) 533 { 534 u64 result = 0; 535 result |= s[0]; result <<= 8; 536 result |= s[1]; result <<= 8; 537 result |= s[2]; result <<= 8; 538 result |= s[3]; result <<= 8; 539 result |= s[4]; result <<= 8; 540 result |= s[5]; result <<= 8; 541 result |= s[6]; result <<= 8; 542 result |= s[7]; 543 return result; 544 } 545 #else 546 function u16 547 u16_host_from_be(u8 *s) 548 { 549 u16 result = 0; 550 result |= s[0]; result <<= 8; 551 result |= s[1]; 552 return result; 553 } 554 555 function u16 556 u16_host_from_le(u8 *s) 557 { 558 u16 result = 0; 559 result |= s[1]; result <<= 8; 560 result |= s[0]; 561 return result; 562 } 563 564 function u32 565 u32_host_from_be(u8 *s) 566 { 567 u32 result = 0; 568 result |= s[0]; result <<= 8; 569 result |= s[1]; result <<= 8; 570 result |= s[2]; result <<= 8; 571 result |= s[3]; 572 return result; 573 } 574 575 function u32 576 u32_host_from_le(u8 *s) 577 { 578 u32 result = 0; 579 result |= s[3]; result <<= 8; 580 result |= s[2]; result <<= 8; 581 result |= s[1]; result <<= 8; 582 result |= s[0]; 583 return result; 584 } 585 586 function u64 587 u64_host_from_be(u8 *s) 588 { 589 u64 result = 0; 590 result |= s[0]; result <<= 8; 591 result |= s[1]; result <<= 8; 592 result |= s[2]; result <<= 8; 593 result |= s[3]; result <<= 8; 594 result |= s[4]; result <<= 8; 595 result |= s[5]; result <<= 8; 596 result |= s[6]; result <<= 8; 597 result |= s[7]; 598 return result; 599 } 600 601 function u64 602 u64_host_from_le(u8 *s) 603 { 604 u64 result = 0; 605 result |= s[7]; result <<= 8; 606 result |= s[6]; result <<= 8; 607 result |= s[5]; result <<= 8; 608 result |= s[4]; result <<= 8; 609 result |= s[3]; result <<= 8; 610 result |= s[2]; result <<= 8; 611 result |= s[1]; result <<= 8; 612 result |= s[0]; 613 return result; 614 } 615 #endif 616 617 #define zero_struct(s) mem_clear(s, 0, sizeof(*s)); 618 function void * 619 mem_clear(void *restrict _s, u8 byte, sz size) 620 { 621 u8 *s = _s; 622 for (sz i = 0; i < size; i++) 623 s[i] = byte; 624 return s; 625 } 626 627 function void * 628 mem_copy(void *restrict dest, void *restrict src, sz size) 629 { 630 u8 *s = src, *d = dest; 631 for (sz i = 0; i < size; i++) 632 d[i] = s[i]; 633 return dest; 634 } 635 636 #define push_array(a, t, c) (t *)alloc_(a, _Alignof(t), sizeof(t), c) 637 function void * 638 alloc_(Arena *a, sz alignment, sz size, sz count) 639 { 640 sz capacity = a->end - a->beg; 641 sz padding = -(uintptr_t)a->beg & (alignment - 1); 642 if ((capacity - padding) / size < count) { 643 assert(0 && "OOM: buy more ram lol"); 644 } 645 u8 *result = a->beg + padding; 646 a->beg += padding + size * count; 647 return mem_clear(result, 0, size * count); 648 } 649 650 enum { DA_INITIAL_CAP = 4 }; 651 #define da_reserve(a, s, n) \ 652 (s)->data = da_reserve_((a), (s)->data, &(s)->capacity, (s)->count + n, \ 653 _Alignof(typeof(*(s)->data)), sizeof(*(s)->data)) 654 655 #define da_push(a, s) \ 656 ((s)->count == (s)->capacity \ 657 ? da_reserve(a, s, 1), \ 658 (s)->data + (s)->count++ \ 659 : (s)->data + (s)->count++) 660 661 function void * 662 da_reserve_(Arena *a, void *data, s16 *capacity, sz needed, sz align, sz size) 663 { 664 sz cap = *capacity; 665 666 /* NOTE(rnp): handle both 0 initialized DAs and DAs that need to be moved (they started 667 * on the stack or someone allocated something in the middle of the arena during usage) */ 668 if (!data || a->beg != (u8 *)data + cap * size) { 669 void *copy = alloc_(a, align, size, cap); 670 if (data) mem_copy(copy, data, cap * size); 671 data = copy; 672 } 673 674 if (!cap) cap = DA_INITIAL_CAP; 675 while (cap < needed) cap *= 2; 676 alloc_(a, align, size, cap - *capacity); 677 *capacity = cap; 678 return data; 679 } 680 681 function str8 682 arena_commit_str8_stream(Arena *a, str8_stream *s) 683 { 684 assert(s->data == a->beg); 685 str8 result = {.data = s->data, .len = s->index}; 686 a->beg += s->index; 687 s->count -= s->index; 688 s->data = a->beg; 689 s->index = 0; 690 return result; 691 } 692 693 function str8_stream 694 str8_stream_from_arena(Arena arena) 695 { 696 str8_stream result = {0}; 697 result.data = arena.beg; 698 result.count = arena.end - arena.beg; 699 return result; 700 } 701 702 function str8 703 str8_from_c_str(u8 *c_str) 704 { 705 str8 result = {.data = c_str}; 706 if (c_str) while (*c_str) c_str++; 707 result.len = c_str - result.data; 708 return result; 709 } 710 711 function b32 712 str8_equal(str8 a, str8 b) 713 { 714 b32 result = a.len == b.len; 715 for (sz i = 0; result && i < a.len; i++) 716 result &= a.data[i] == b.data[i]; 717 return result; 718 } 719 720 function str8 721 str8_chop_at(str8 a, sz length) 722 { 723 str8 result = {0}; 724 if (length < a.len) { 725 result.data = a.data + length; 726 result.len = a.len - length; 727 } 728 return result; 729 } 730 731 function str8_stream 732 str8_reader_from_str8(str8 s) 733 { 734 str8_stream result = {0}; 735 result.data = s.data; 736 result.count = s.len; 737 return result; 738 } 739 740 function u8 741 str8_read_u8(str8_stream *r) 742 { 743 u8 result = 0; 744 r->errors |= r->index + 1 > r->count; 745 if (!r->errors) result = r->data[r->index++]; 746 return result; 747 } 748 749 function u16 750 str8_read_u16(str8_stream *r, b32 big_endian) 751 { 752 u16 result = 0; 753 r->errors |= r->index + 2 > r->count; 754 if (!r->errors) { 755 if (big_endian) result = u16_host_from_be(r->data + r->index); 756 else result = u16_host_from_le(r->data + r->index); 757 r->index += 2; 758 } 759 return result; 760 } 761 762 function u32 763 str8_read_u32(str8_stream *r, b32 big_endian) 764 { 765 u32 result = 0; 766 r->errors |= r->index + 4 > r->count; 767 if (!r->errors) { 768 if (big_endian) result = u32_host_from_be(r->data + r->index); 769 else result = u32_host_from_le(r->data + r->index); 770 r->index += 4; 771 } 772 return result; 773 } 774 775 function u64 776 str8_read_u64(str8_stream *r, b32 big_endian) 777 { 778 u64 result = 0; 779 r->errors |= r->index + 8 > r->count; 780 if (!r->errors) { 781 if (big_endian) result = u32_host_from_be(r->data + r->index); 782 else result = u32_host_from_le(r->data + r->index); 783 r->index += 8; 784 } 785 return result; 786 } 787 788 function u64 789 str8_read_uleb128(str8_stream *r) 790 { 791 /* TODO(rnp): check for overflow ... */ 792 sz shift = 0; 793 u64 result = 0; 794 while (r->index < r->count) { 795 u8 byte = r->data[r->index++]; 796 result |= (u64)(byte & 0x7F) << shift; 797 if ((byte & 0x80) == 0) 798 break; 799 shift += 7; 800 } 801 return result; 802 } 803 804 function void 805 print_u64(u64 v) 806 { 807 printf("%zu", v); 808 } 809 810 function void print_u16(u16 v) { print_u64(v); } 811 function void print_u32(u32 v) { print_u64(v); } 812 813 function void 814 print_ELFFormat(ELFFormat format) 815 { 816 #define X(name, value, pretty) [name] = str8(pretty), 817 local_persist str8 format_pretty[] = {ELF_FORMATS}; 818 #undef X 819 if (format < countof(format_pretty) && format_pretty[format].len) { 820 printf("%.*s", (s32)format_pretty[format].len, format_pretty[format].data); 821 } else { 822 printf("Invalid"); 823 } 824 } 825 826 function void 827 print_ELFEndianKind(ELFEndianKind kind) 828 { 829 #define X(name, value, pretty) [name] = str8(pretty), 830 local_persist str8 kind_pretty[] = {ELF_ENDIANNESS}; 831 #undef X 832 if (kind < countof(kind_pretty) && kind_pretty[kind].len) { 833 printf("%.*s", (s32)kind_pretty[kind].len, kind_pretty[kind].data); 834 } else { 835 printf("Invalid"); 836 } 837 } 838 839 function void 840 print_ELFABIKind(ELFABIKind kind) 841 { 842 #define X(name, value, pretty) [name] = str8(pretty), 843 local_persist str8 kind_pretty[] = {ELF_OS_ABI}; 844 #undef X 845 if (kind < countof(kind_pretty) && kind_pretty[kind].len) { 846 printf("%.*s", (s32)kind_pretty[kind].len, kind_pretty[kind].data); 847 } else { 848 printf("Invalid"); 849 } 850 } 851 852 function void 853 print_ELFKind(ELFKind kind) 854 { 855 #define X(name, value, pretty) [name] = str8(pretty), 856 local_persist str8 kind_pretty[] = {ELF_KINDS}; 857 #undef X 858 if (kind < countof(kind_pretty) && kind_pretty[kind].len) { 859 printf("%.*s", (s32)kind_pretty[kind].len, kind_pretty[kind].data); 860 } else { 861 printf("Invalid"); 862 } 863 } 864 865 function void 866 print_elf_header(ELFHeader *eh) 867 { 868 printf("ELF Header:\n"); 869 s32 max_name_len = 0; 870 #define X(ctype, name) if (max_name_len < sizeof(#name) - 1) max_name_len = sizeof(#name) - 1; 871 ELF_HEADER_MEMBERS 872 #undef X 873 874 #define X(ctype, name) printf(#name ": %*s", (s32)(max_name_len - sizeof(#name) + 1), ""); \ 875 print_##ctype(eh->name); printf("\n"); 876 ELF_HEADER_MEMBERS 877 #undef X 878 } 879 880 function void 881 str8_stream_append(str8_stream *s, void *restrict data, sz size) 882 { 883 s->errors |= s->count - s->index < size; 884 if (!s->errors) { 885 mem_copy(s->data + s->index, data, size); 886 s->index += size; 887 } 888 } 889 890 function void 891 str8_stream_print_byte(str8_stream *s, u8 byte) 892 { 893 str8_stream_append(s, &byte, 1); 894 } 895 896 function void 897 str8_stream_print_str8(str8_stream *s, str8 str) 898 { 899 str8_stream_append(s, str.data, str.len); 900 } 901 902 function void 903 str8_stream_print_u64(str8_stream *s, u64 n) 904 { 905 u8 buffer[64]; 906 u8 *end = buffer + sizeof(buffer); 907 u8 *beg = end; 908 do { *--beg = '0' + (n % 10); } while (n /= 10); 909 str8_stream_append(s, beg, end - beg); 910 } 911 912 function void 913 str8_stream_print_u64_hex(str8_stream *s, u64 n) 914 { 915 u8 buffer[16]; 916 u8 *end = buffer + sizeof(buffer); 917 u8 *beg = end; 918 while (n) { 919 *--beg = "0123456789abcdef"[n & 0x0Fu]; 920 n >>= 4; 921 } 922 while (end - beg < 2) *--beg = '0'; 923 str8_stream_append(s, beg, end - beg); 924 } 925 926 function void 927 str8_stream_print_elf_section_header_kind(str8_stream *s, ELFSectionKind kind) 928 { 929 #define X(name, value, pretty) [ELFSectionKind_##name] = str8(pretty), 930 read_only local_persist str8 kind_pretty[ELFSectionKind_COUNT] = {ELFSectionKinds}; 931 #undef X 932 if (kind_pretty[MIN(kind, ELFSectionKind_COUNT - 1)].len) { 933 str8_stream_print_str8(s, kind_pretty[MIN(kind, ELFSectionKind_COUNT - 1)]); 934 } else { 935 str8_stream_print_str8(s, str8("0x")); 936 str8_stream_print_u64_hex(s, kind); 937 } 938 } 939 940 function void 941 print_table_line_marker(Table *t, str8_stream *s) 942 { 943 str8_stream_print_byte(s, '+'); 944 for (s16 column = 0; column < t->columns; column++) { 945 for (sz i = 0; i < t->max_column_widths[column] + 2; i++) 946 str8_stream_print_byte(s, '-'); 947 str8_stream_print_byte(s, '+'); 948 } 949 str8_stream_print_byte(s, '\n'); 950 } 951 952 function void 953 print_table_row(Table *t, str8 *cells, str8_stream *s) 954 { 955 str8_stream_print_byte(s, '|'); 956 for (s16 column = 0; column < t->columns; column++) { 957 str8_stream_print_byte(s, ' '); 958 str8_stream_print_str8(s, cells[column]); 959 for (s32 i = cells[column].len; i < t->max_column_widths[column]; i++) 960 str8_stream_print_byte(s, ' '); 961 str8_stream_print_byte(s, ' '); 962 str8_stream_print_byte(s, '|'); 963 } 964 str8_stream_print_byte(s, '\n'); 965 } 966 967 function b32 968 is_elf(str8 file) 969 { 970 b32 result = file.len >= 16; 971 if (result) { 972 result &= file.data[0] == 0x7F; 973 result &= file.data[1] == 'E'; 974 result &= file.data[2] == 'L'; 975 result &= file.data[3] == 'F'; 976 } 977 return result; 978 } 979 980 function b32 981 elf_header_from_file(ELFHeader *eh, str8 file) 982 { 983 b32 result = 0; 984 if (is_elf(file)) { 985 eh->format = file.data[4]; 986 eh->endianness = file.data[5]; 987 eh->abi = file.data[7]; 988 eh->abi_version = file.data[8]; 989 990 str8_stream reader = str8_reader_from_str8(str8_chop_at(file, 16)); 991 b32 big_endian = eh->endianness == EEK_BIG; 992 eh->kind = str8_read_u16(&reader, big_endian); 993 eh->machine = str8_read_u16(&reader, big_endian); 994 eh->version = str8_read_u32(&reader, big_endian); 995 if (eh->format == EF_64) { 996 eh->entry_point_offset = str8_read_u64(&reader, big_endian); 997 eh->program_header_offset = str8_read_u64(&reader, big_endian); 998 eh->section_header_offset = str8_read_u64(&reader, big_endian); 999 } else { 1000 eh->entry_point_offset = str8_read_u32(&reader, big_endian); 1001 eh->program_header_offset = str8_read_u32(&reader, big_endian); 1002 eh->section_header_offset = str8_read_u32(&reader, big_endian); 1003 } 1004 eh->flags = str8_read_u32(&reader, big_endian); 1005 eh->elf_header_size = str8_read_u16(&reader, big_endian); 1006 eh->program_header_entry_size = str8_read_u16(&reader, big_endian); 1007 eh->program_header_count = str8_read_u16(&reader, big_endian); 1008 eh->section_header_entry_size = str8_read_u16(&reader, big_endian); 1009 eh->section_header_count = str8_read_u16(&reader, big_endian); 1010 eh->section_header_name_table_index = str8_read_u16(&reader, big_endian); 1011 result = !reader.errors && file.data[6] == eh->version; 1012 } 1013 return result; 1014 } 1015 1016 function void 1017 elf_section_header32_from_str8(ELFSectionHeader *sh, str8 s, b32 big_endian) 1018 { 1019 assert(s.len >= 0x28); 1020 u8 *data = s.data; 1021 if (big_endian) { 1022 #define X(ctype, r32, r64, name) \ 1023 sh->name = r32 ##_host_from_be(data); data += sizeof(r32); 1024 ELF_SECTION_HEADER_MEMBERS 1025 #undef X 1026 } else { 1027 #define X(ctype, r32, r64, name) \ 1028 sh->name = r32 ##_host_from_le(data); data += sizeof(r32); 1029 ELF_SECTION_HEADER_MEMBERS 1030 #undef X 1031 } 1032 } 1033 1034 function void 1035 elf_section_header64_from_str8(ELFSectionHeader *sh, str8 s, b32 big_endian) 1036 { 1037 assert(s.len >= 0x40); 1038 u8 *data = s.data; 1039 if (big_endian) { 1040 #define X(ctype, r32, r64, name) \ 1041 sh->name = r64 ##_host_from_be(data); data += sizeof(r64); 1042 ELF_SECTION_HEADER_MEMBERS 1043 #undef X 1044 } else { 1045 #define X(ctype, r32, r64, name) \ 1046 sh->name = r64 ##_host_from_le(data); data += sizeof(r64); 1047 ELF_SECTION_HEADER_MEMBERS 1048 #undef X 1049 } 1050 } 1051 1052 function b32 1053 elf_section_header_from_str8(ELFSectionHeader *sh, str8 s, b32 big_endian, b32 is32bit) 1054 { 1055 b32 result = s.len >= 0x40 || (is32bit && s.len >= 0x28); 1056 if (result) { 1057 if (is32bit) elf_section_header32_from_str8(sh, s, big_endian); 1058 else elf_section_header64_from_str8(sh, s, big_endian); 1059 } 1060 return result; 1061 } 1062 1063 function ELFSectionHeader * 1064 elf_extract_section_headers(Arena *a, str8 file, ELFHeader *eh) 1065 { 1066 /* TODO(rnp): */ 1067 assert(file.len >= eh->section_header_offset + eh->section_header_entry_size * eh->section_header_count); 1068 1069 u32 sections = eh->section_header_count; 1070 ELFSectionHeader *result = push_array(a, ELFSectionHeader, sections); 1071 for (u32 i = 0; i < sections; i++) { 1072 sz offset = eh->section_header_offset + eh->section_header_entry_size * i; 1073 elf_section_header_from_str8(result + i, str8_chop_at(file, offset), 1074 eh->endianness == EEK_BIG, eh->format == EF_32); 1075 } 1076 1077 u8 *str_tab = file.data + result[eh->section_header_name_table_index].offset; 1078 for (u32 i = 0; i < sections; i++) 1079 result[i].name = str8_from_c_str(str_tab + result[i].name_table_offset); 1080 1081 return result; 1082 } 1083 1084 function ELFSection 1085 elf_lookup_section(str8 name, str8 file, ELFSectionHeader *shs, u32 sections_count) 1086 { 1087 ELFSection result = {0}; 1088 for (u32 i = 0; i < sections_count; i++) { 1089 if (str8_equal(shs[i].name, name)) { 1090 result.header = shs[i]; 1091 result.store.data = file.data + shs[i].offset; 1092 result.store.len = shs[i].size; 1093 break; 1094 } 1095 } 1096 return result; 1097 } 1098 1099 function void 1100 dwarf_read_unit_header(str8_stream *store, DWARFUnitHeader *duh) 1101 { 1102 /* TODO(rnp): context containing endianess, dwarf size */ 1103 u32 test_length = str8_read_u32(store, 0); 1104 duh->dwarf_64 = test_length == 0xffffffff; 1105 if (duh->dwarf_64) duh->length = str8_read_u64(store, 0); 1106 else duh->length = test_length; 1107 duh->version = str8_read_u16(store, 0); 1108 if (duh->version == 5) duh->kind = str8_read_u8(store); 1109 duh->address_size = str8_read_u8(store); 1110 if (duh->dwarf_64) duh->abbreviation_offset = str8_read_u64(store, 0); 1111 else duh->abbreviation_offset = str8_read_u32(store, 0); 1112 } 1113 1114 function sz 1115 dwarf_parse_abbrevation(Arena *a, DWARFAbbreviation *abbrv, str8 table) 1116 { 1117 str8_stream table_reader = str8_reader_from_str8(table); 1118 sz table_start_size = table.len; 1119 abbrv->abbreviation_code = str8_read_uleb128(&table_reader); 1120 abbrv->kind = str8_read_uleb128(&table_reader); 1121 if (table_reader.count - table_reader.index < 1) 1122 return table_start_size; 1123 abbrv->has_children = str8_read_u8(&table_reader); 1124 for (;;) { 1125 u64 attr_kind = str8_read_uleb128(&table_reader); 1126 u64 form_kind = str8_read_uleb128(&table_reader); 1127 TODO(form_kind != DFK_INDIRECT); 1128 TODO(form_kind != DFK_IMPLICIT_CONST); 1129 if (attr_kind) { 1130 *da_push(a, abbrv) = (DWARFAttribute){attr_kind, form_kind}; 1131 } else { 1132 assert(form_kind == 0); 1133 break; 1134 } 1135 } 1136 return table_reader.index; 1137 } 1138 1139 function DWARFAbbreviation 1140 dwarf_lookup_abbreviation(Arena *a, str8 table, u64 key) 1141 { 1142 DWARFAbbreviation result = {0}; 1143 while (key != result.abbreviation_code && table.len > 1) { 1144 result.count = 0; 1145 table = str8_chop_at(table, dwarf_parse_abbrevation(a, &result, table)); 1146 } 1147 return result; 1148 } 1149 1150 function Table 1151 table_new(Arena *arena, u16 column_count, u16 reserved_rows) 1152 { 1153 Table result = {0}; 1154 result.max_column_widths = push_array(arena, typeof(*result.max_column_widths), column_count); 1155 result.columns = column_count; 1156 assert(reserved_rows < 0xFFFF / column_count); 1157 result.data = da_reserve(arena, &result, reserved_rows * column_count); 1158 return result; 1159 } 1160 1161 #define table_push_row(t, a, ...) \ 1162 table_push_row_(t, a, (str8 []){__VA_ARGS__}, sizeof((str8 []){__VA_ARGS__}) / (sizeof(str8))) 1163 function void 1164 table_push_row_(Table *table, Arena *arena, str8 *cells, sz cells_count) 1165 { 1166 assert(table->columns == cells_count); 1167 for (sz i = 0; i < cells_count; i++) { 1168 table->max_column_widths[i] = MAX(table->max_column_widths[i], cells[i].len); 1169 str8 *out = da_push(arena, table); 1170 str8 cell = cells[i]; 1171 *out = cell; 1172 } 1173 } 1174 1175 function void 1176 print_section_table(Arena arena, ELFSectionHeader *sections, u32 section_count) 1177 { 1178 str8 header_row[] = {str8("name"), str8("kind"), str8("size"), str8("offset"), str8("flags"), str8("align")}; 1179 Table table = table_new(&arena, countof(header_row), section_count); 1180 for (u32 i = 0; i < countof(header_row); i++) 1181 table.max_column_widths[i] = header_row[i].len; 1182 1183 for (u32 i = 0; i < section_count; i++) { 1184 if (sections[i].size) { 1185 str8_stream sb = str8_stream_from_arena(arena); 1186 str8 name = sections[i].name; 1187 1188 str8_stream_print_elf_section_header_kind(&sb, sections[i].kind); 1189 str8 kind = arena_commit_str8_stream(&arena, &sb); 1190 1191 str8_stream_print_u64(&sb, sections[i].size); 1192 str8 size = arena_commit_str8_stream(&arena, &sb); 1193 1194 str8_stream_print_str8(&sb, str8("0x")); 1195 str8_stream_print_u64_hex(&sb, sections[i].offset); 1196 str8 offset = arena_commit_str8_stream(&arena, &sb); 1197 1198 str8_stream_print_str8(&sb, str8("0x")); 1199 str8_stream_print_u64_hex(&sb, sections[i].flags); 1200 str8 flags = arena_commit_str8_stream(&arena, &sb); 1201 1202 str8_stream_print_u64(&sb, sections[i].addralign); 1203 str8 align = arena_commit_str8_stream(&arena, &sb); 1204 1205 table_push_row(&table, &arena, name, kind, size, offset, flags, align); 1206 } 1207 } 1208 1209 str8_stream sb = str8_stream_from_arena(arena); 1210 print_table_line_marker(&table, &sb); 1211 print_table_row(&table, header_row, &sb); 1212 print_table_line_marker(&table, &sb); 1213 for (s16 index = 0; index < table.count; index += table.columns) 1214 print_table_row(&table, table.data + index, &sb); 1215 print_table_line_marker(&table, &sb); 1216 fwrite(sb.data, 1, sb.index, stdout); 1217 fflush(stdout); 1218 } 1219 1220 function b32 1221 elf_inspect_file(Arena arena, str8 file, Options *options) 1222 { 1223 b32 result = is_elf(file); 1224 if (result) { 1225 ELFHeader header = {0}; 1226 if (!elf_header_from_file(&header, file)) { 1227 return 1; 1228 } 1229 1230 if (options->header) 1231 print_elf_header(&header); 1232 1233 ELFSectionHeader *sections = elf_extract_section_headers(&arena, file, &header); 1234 1235 if (options->sections) 1236 print_section_table(arena, sections, header.section_header_count); 1237 1238 #if 0 /* TODO(rnp): fix this. it broke when da_reserve was fixed (i.e. it was always busted)*/ 1239 ELFSection debug_info = elf_lookup_section(str8(".debug_info"), file, 1240 sections, header.section_header_count); 1241 ELFSection debug_abbrv = elf_lookup_section(str8(".debug_abbrev"), file, 1242 sections, header.section_header_count); 1243 ELFSection debug_str_offsets = elf_lookup_section(str8(".debug_str_offsets"), file, 1244 sections, header.section_header_count); 1245 ELFSection debug_str = elf_lookup_section(str8(".debug_str"), file, 1246 sections, header.section_header_count); 1247 1248 /* TODO(rnp): cleanup */ 1249 if (debug_info.store.len == 0) { 1250 printf("No Debug Info!\n"); 1251 return 0; 1252 } 1253 1254 str8_stream d_info_reader = str8_reader_from_str8(debug_info.store); 1255 DWARFUnitHeader d_info_header = {0}; 1256 dwarf_read_unit_header(&d_info_reader, &d_info_header); 1257 str8 abbreviation_table = str8_chop_at(debug_abbrv.store, d_info_header.abbreviation_offset); 1258 u64 abbreviation_code = str8_read_uleb128(&d_info_reader); 1259 DWARFAbbreviation abbrv = dwarf_lookup_abbreviation(&arena, abbreviation_table, abbreviation_code); 1260 1261 printf("\nFirst DWARF DIE:\n"); 1262 for (s16 i = 0; i < abbrv.count; i++) { 1263 DWARFAttribute attr = abbrv.data[i]; 1264 if (attr.kind == 0) 1265 continue; 1266 1267 switch (attr.kind) { 1268 case DATK_PRODUCER: printf("producer: "); break; 1269 case DATK_LANGUAGE: printf("language: "); break; 1270 case DATK_ADDR_BASE: printf("addr base: "); break; 1271 case DATK_LOCLISTS_BASE: printf("loc list base: "); break; 1272 case DATK_RNGLISTS_BASE: printf("range list base: "); break; 1273 case DATK_NAME: printf("name: "); break; 1274 default: assert(0); break; 1275 } 1276 1277 switch (attr.form_kind) { 1278 case DFK_STRX1: { 1279 u32 str_offset_offset = str8_read_u8(&d_info_reader); 1280 u32 str_offset; 1281 if (header.endianness == EEK_BIG) 1282 str_offset = u32_host_from_be(debug_str_offsets.store.data + str_offset_offset); 1283 else 1284 str_offset = u32_host_from_le(debug_str_offsets.store.data + str_offset_offset); 1285 printf("%s", (char *)debug_str.store.data + str_offset); 1286 } break; 1287 case DFK_DATA2: { 1288 u32 data = str8_read_u16(&d_info_reader, header.endianness == EEK_BIG); 1289 printf("%u", data); 1290 } break; 1291 case DFK_SEC_OFFSET: { 1292 u32 data = str8_read_u32(&d_info_reader, header.endianness == EEK_BIG); 1293 printf("%u", data); 1294 } break; 1295 default: assert(0); break; 1296 } 1297 printf("\n"); 1298 } 1299 #endif 1300 1301 result = 1; 1302 } 1303 1304 return result; 1305 } 1306 1307 function Options 1308 parse_command_line(Arena *arena, s32 argc, char *argv[]) 1309 { 1310 Options result = {0}; 1311 1312 #define shift(c, v) ((c)--, *(v)++) 1313 1314 char *c_arg = shift(argc, argv); 1315 result.argv0 = (u8 *)c_arg; 1316 while (argc) { 1317 c_arg = shift(argc, argv); 1318 str8 arg = str8_from_c_str((u8 *)c_arg); 1319 if (str8_equal(arg, str8("--sections"))) { 1320 result.sections = 1; 1321 } else if (str8_equal(arg, str8("--header"))) { 1322 result.header = 1; 1323 } else { 1324 *da_push(arena, &result.file_names) = (u8 *)c_arg; 1325 } 1326 } 1327 1328 #undef shift 1329 1330 return result; 1331 } 1332 1333 function b32 1334 elfinspect(Arena arena, s32 argc, char *argv[]) 1335 { 1336 Options options = parse_command_line(&arena, argc, argv); 1337 1338 b32 result = 1; 1339 for (s32 file_index = 0; file_index < options.file_names.count; file_index++) { 1340 u8 *file_name = options.file_names.data[file_index]; 1341 str8 file = os_map_file(file_name); 1342 if (!file.len) fprintf(stderr, "failed to open file: %s\n", file_name); 1343 result &= elf_inspect_file(arena, file, &options); 1344 } 1345 1346 return result; 1347 }