elfinspect

ELF and DWARF Binary Inspector
git clone anongit@rnpnr.xyz:elfinspect.git
Log | Files | Refs | Feed | README | LICENSE

elfinspect.c (29024B)


      1 /* See LICENSE for license details. */
      2 #define local_persist static
      3 #define global        static
      4 #define function      static
      5 
      6 /* TODO(rnp) platform specific */
      7 #define ASSERT(c) do { if (!(c)) asm("int3; nop"); } while (0)
      8 #define TODO(c) ASSERT(c)
      9 
     10 #define countof(a) (sizeof(a) / sizeof(*a))
     11 
     12 #define static_assert(c, msg) _Static_assert(c, msg)
     13 
     14 #define KB(a) ((u64)a << 10ULL)
     15 #define MB(a) ((u64)a << 20ULL)
     16 
     17 typedef struct {u8 *beg, *end;} Arena;
     18 
     19 #define str8(s) (str8){.len = countof(s) - 1, .data = (u8 *)s}
     20 typedef struct { iz len; u8 *data;} str8;
     21 
     22 typedef struct {
     23 	u8  *data;
     24 	iz   index;
     25 	iz   count;
     26 	b32  errors;
     27 } str8_reader;
     28 
     29 /* NOTE: platform api; defined here so that other platform symbols are not visible to this TU */
     30 function str8 os_map_file(u8 *);
     31 
     32 /* X(name, value, pretty) */
     33 #define ELF_FORMATS \
     34 	X(EF_NONE, 0, "Unknown") \
     35 	X(EF_32,   1, "ELF32")   \
     36 	X(EF_64,   2, "ELF64")
     37 
     38 #define ELF_ENDIANNESS \
     39 	X(EEK_NONE,   0, "Unknown")       \
     40 	X(EEK_LITTLE, 1, "Little-Endian") \
     41 	X(EEK_BIG,    2, "Big-Endian")
     42 
     43 #define ELF_OS_ABI \
     44 	X(ELF_ABI_SYSV,       0x00, "System-V")       \
     45 	X(ELF_ABI_HPUX,       0x01, "HP-UX")          \
     46 	X(ELF_ABI_NETBSD,     0x02, "NetBSD")         \
     47 	X(ELF_ABI_GNU,        0x03, "GNU Hurd")       \
     48 	X(ELF_ABI_SOLARIS,    0x06, "Solaris")        \
     49 	X(ELF_ABI_AIX,        0x07, "AIX")            \
     50 	X(ELF_ABI_IRIX,       0x08, "IRIX")           \
     51 	X(ELF_ABI_FREEBSD,    0x09, "FreeBSD")        \
     52 	X(ELF_ABI_TRU64,      0x0a, "Tru64")          \
     53 	X(ELF_ABI_MODESTO,    0x0b, "Novel Modesto")  \
     54 	X(ELF_ABI_OPENBSD,    0x0c, "OpenBSD")        \
     55 	X(ELF_ABI_OPENVMS,    0x0d, "OpenVMS")        \
     56 	X(ELF_ABI_NONSTOP,    0x0e, "NonStop Kernel") \
     57 	X(ELF_ABI_AROS,       0x0f, "AROS")           \
     58 	X(ELF_ABI_FENIX,      0x10, "Fenix")          \
     59 	X(ELF_ABI_ARM,        0x61, "ARM")            \
     60 	X(ELF_ABI_STANDALONE, 0xff, "Free Standing")
     61 
     62 #define ELF_KINDS \
     63 	X(ELF_KIND_NONE,   0x0000, "Unknown")       \
     64 	X(ELF_KIND_REL,    0x0001, "Relocatable")   \
     65 	X(ELF_KIND_EXEC,   0x0002, "Executable")    \
     66 	X(ELF_KIND_DYN,    0x0003, "Shared Object") \
     67 	X(ELF_KIND_CORE,   0x0004, "Core Dump")
     68 
     69 #define X(name, value, pretty) name = value,
     70 typedef enum { ELF_FORMATS }    ELFFormat;
     71 typedef enum { ELF_ENDIANNESS } ELFEndianKind;
     72 typedef enum { ELF_OS_ABI }     ELFABIKind;
     73 typedef enum { ELF_KINDS }      ELFKind;
     74 #undef X
     75 
     76 /* X(ctype, name) */
     77 #define ELF_HEADER_MEMBERS \
     78 	X(ELFFormat,     format)                          \
     79 	X(ELFEndianKind, endianness)                      \
     80 	X(ELFABIKind,    abi)                             \
     81 	X(ELFKind,       kind)                            \
     82 	X(u16,           abi_version)                     \
     83 	X(u16,           machine)                         \
     84 	X(u32,           version)                         \
     85 	X(u64,           entry_point_offset)              \
     86 	X(u64,           program_header_offset)           \
     87 	X(u64,           section_header_offset)           \
     88 	X(u32,           flags)                           \
     89 	X(u16,           elf_header_size)                 \
     90 	X(u16,           program_header_entry_size)       \
     91 	X(u16,           program_header_count)            \
     92 	X(u16,           section_header_entry_size)       \
     93 	X(u16,           section_header_count)            \
     94 	X(u16,           section_header_name_table_index)
     95 
     96 #define X(ctype, name) ctype name;
     97 typedef struct {ELF_HEADER_MEMBERS} ELFHeader;
     98 #undef X
     99 
    100 typedef enum {
    101 	ESK_NULL         = 0,
    102 	ESK_PROGBITS     = 1,
    103 	ESK_SYMBOL_TABLE = 2,
    104 	ESK_STR_TABLE    = 3,
    105 	ESK_RELA         = 4,
    106 	ESK_HASH         = 5,
    107 	ESK_DYNAMIC      = 6,
    108 	ESK_NOTE         = 7,
    109 	ESK_NOBITS       = 8,
    110 	ESK_REL          = 9,
    111 	ESK_SHLIB        = 10,
    112 	ESK_DYNSYM       = 11,
    113 	ESK_INIT_ARRAY   = 14,
    114 	ESK_FINI_ARRAY   = 15,
    115 	ESK_PREINIT_ARR  = 16,
    116 	ESK_GROUP        = 17,
    117 	ESK_SYMTAB_SHND  = 18,
    118 	ESK_RELR         = 19,
    119 	ESK_NUM          = 20,
    120 	ESK_LOPROC       = 0x70000000,
    121 	ESK_HIPROC       = 0x7fffffff,
    122 	ESK_LOUSER       = 0x80000000,
    123 	ESK_HIUSER       = 0x8fffffff,
    124 } ELFSectionKind;
    125 static_assert(sizeof(ELFSectionKind) == 4, "sizeof(ELFSectionKind) must be 4 bytes");
    126 
    127 /* X(ctype, name) */
    128 #define ELF_SECTION_HEADER_MEMBERS(ptrsize) \
    129 	X(u32,            name_table_offset) \
    130 	X(ELFSectionKind, kind)              \
    131 	X(ptrsize,        flags)             \
    132 	X(ptrsize,        addr)              \
    133 	X(ptrsize,        offset)            \
    134 	X(ptrsize,        size)              \
    135 	X(u32,            link)              \
    136 	X(u32,            info)              \
    137 	X(ptrsize,        addralign)         \
    138 	X(ptrsize,        entsize)
    139 
    140 #define X(ctype, name) ctype name;
    141 typedef struct {ELF_SECTION_HEADER_MEMBERS(u32)} ELFSectionHeader32;
    142 typedef struct {ELF_SECTION_HEADER_MEMBERS(u64)} ELFSectionHeader64;
    143 #undef X
    144 
    145 typedef struct {
    146 	str8 name;
    147 	union {
    148 		ELFSectionHeader64 sh64;
    149 		ELFSectionHeader32 sh32;
    150 	};
    151 } ELFSectionHeader;
    152 
    153 typedef struct {
    154 	ELFSectionHeader *header;
    155 	str8 store;
    156 } ELFSection;
    157 
    158 typedef enum {
    159 	DUT_UNKNOWN       = 0x00,
    160 	DUT_COMPILE       = 0x01,
    161 	DUT_TYPE          = 0x02,
    162 	DUT_PARTIAL       = 0x03,
    163 	DUT_SKELETON      = 0x04,
    164 	DUT_SPLIT_COMPILE = 0x05,
    165 	DUT_SPLIT_TYPE    = 0x06,
    166 	DUT_LO_USER       = 0x80,
    167 	DUT_HI_USER       = 0xff
    168 } DWARFUnitKind;
    169 
    170 typedef struct {
    171 	u64 length;
    172 	u64 abbreviation_offset;
    173 	DWARFUnitKind kind;
    174 	u16 version;
    175 	u8  address_size;
    176 	u8  dwarf_64;
    177 } DWARFUnitHeader;
    178 
    179 typedef enum {
    180 	DATK_SIBLING                 = 0x01,
    181 	DATK_LOCATION                = 0x02,
    182 	DATK_NAME                    = 0x03,
    183 	DATK_ORDERING                = 0x09,
    184 	DATK_BYTE_SIZE               = 0x0b,
    185 	DATK_BIT_OFFSET              = 0x0c,
    186 	DATK_BIT_SIZE                = 0x0d,
    187 	DATK_STMT_LIST               = 0x10,
    188 	DATK_LOW_PC                  = 0x11,
    189 	DATK_HIGH_PC                 = 0x12,
    190 	DATK_LANGUAGE                = 0x13,
    191 	DATK_DISCR                   = 0x15,
    192 	DATK_DISCR_VALUE             = 0x16,
    193 	DATK_VISIBILITY              = 0x17,
    194 	DATK_IMPORT                  = 0x18,
    195 	DATK_STRING_LENGTH           = 0x19,
    196 	DATK_COMMON_REFERENCE        = 0x1a,
    197 	DATK_COMP_DIR                = 0x1b,
    198 	DATK_CONST_VALUE             = 0x1c,
    199 	DATK_CONTAINING_TYPE         = 0x1d,
    200 	DATK_DEFAULT_VALUE           = 0x1e,
    201 	DATK_INLINE                  = 0x20,
    202 	DATK_IS_OPTIONAL             = 0x21,
    203 	DATK_LOWER_BOUND             = 0x22,
    204 	DATK_PRODUCER                = 0x25,
    205 	DATK_PROTOTYPED              = 0x27,
    206 	DATK_RETURN_ADDR             = 0x2a,
    207 	DATK_START_SCOPE             = 0x2c,
    208 	DATK_BIT_STRIDE              = 0x2e,
    209 	DATK_UPPER_BOUND             = 0x2f,
    210 	DATK_ABSTRACT_ORIGIN         = 0x31,
    211 	DATK_ACCESSIBILITY           = 0x32,
    212 	DATK_ADDRESS_CLASS           = 0x33,
    213 	DATK_ARTIFICIAL              = 0x34,
    214 	DATK_BASE_TYPES              = 0x35,
    215 	DATK_CALLING_CONVENTION      = 0x36,
    216 	DATK_COUNT                   = 0x37,
    217 	DATK_DATA_MEMBER_LOCATION    = 0x38,
    218 	DATK_DECL_COLUMN             = 0x39,
    219 	DATK_DECL_FILE               = 0x3a,
    220 	DATK_DECL_LINE               = 0x3b,
    221 	DATK_DECLARATION             = 0x3c,
    222 	DATK_DISCR_LIST              = 0x3d,
    223 	DATK_ENCODING                = 0x3e,
    224 	DATK_EXTERNAL                = 0x3f,
    225 	DATK_FRAME_BASE              = 0x40,
    226 	DATK_FRIEND                  = 0x41,
    227 	DATK_IDENTIFIER_CASE         = 0x42,
    228 	DATK_MACRO_INFO              = 0x43,
    229 	DATK_NAMELIST_ITEM           = 0x44,
    230 	DATK_PRIORITY                = 0x45,
    231 	DATK_SEGMENT                 = 0x46,
    232 	DATK_SPECIFICATION           = 0x47,
    233 	DATK_STATIC_LINK             = 0x48,
    234 	DATK_TYPE                    = 0x49,
    235 	DATK_USE_LOCATION            = 0x4a,
    236 	DATK_VARIABLE_PARAMETER      = 0x4b,
    237 	DATK_VIRTUALITY              = 0x4c,
    238 	DATK_VTABLE_ELEM_LOCATION    = 0x4d,
    239 	DATK_ALLOCATED               = 0x4e,
    240 	DATK_ASSOCIATED              = 0x4f,
    241 	DATK_DATA_LOCATION           = 0x50,
    242 	DATK_BYTE_STRIDE             = 0x51,
    243 	DATK_ENTRY_PC                = 0x52,
    244 	DATK_USE_UTF8                = 0x53,
    245 	DATK_EXTENSION               = 0x54,
    246 	DATK_RANGES                  = 0x55,
    247 	DATK_TRAMPOLINE              = 0x56,
    248 	DATK_CALL_COLUMN             = 0x57,
    249 	DATK_CALL_FILE               = 0x58,
    250 	DATK_CALL_LINE               = 0x59,
    251 	DATK_DESCRIPTION             = 0x5a,
    252 	DATK_BINARY_SCALE            = 0x5b,
    253 	DATK_DECIMAL_SCALE           = 0x5c,
    254 	DATK_SMALL                   = 0x5d,
    255 	DATK_DECIMAL_SIGN            = 0x5e,
    256 	DATK_DIGIT_COUNT             = 0x5f,
    257 	DATK_PICTURE_STRING          = 0x60,
    258 	DATK_MUTABLE                 = 0x61,
    259 	DATK_THREADS_SCALED          = 0x62,
    260 	DATK_EXPLICIT                = 0x63,
    261 	DATK_OBJECT_POINTER          = 0x64,
    262 	DATK_ENDIANITY               = 0x65,
    263 	DATK_ELEMENTAL               = 0x66,
    264 	DATK_PURE                    = 0x67,
    265 	DATK_RECURSIVE               = 0x68,
    266 	DATK_SIGNATURE               = 0x69,
    267 	DATK_MAIN_SUBPROGRAM         = 0x6a,
    268 	DATK_DATA_BIT_OFFSET         = 0x6b,
    269 	DATK_CONST_EXPR              = 0x6c,
    270 	DATK_ENUM_CLASS              = 0x6d,
    271 	DATK_LINKAGE_NAME            = 0x6e,
    272 	DATK_STRING_LENGTH_BIT_SIZE  = 0x6f,
    273 	DATK_STRING_LENGTH_BYTE_SIZE = 0x70,
    274 	DATK_RANK                    = 0x71,
    275 	DATK_STR_OFFSETS_BASE        = 0x72,
    276 	DATK_ADDR_BASE               = 0x73,
    277 	DATK_RNGLISTS_BASE           = 0x74,
    278 	DATK_DWO_NAME                = 0x76,
    279 	DATK_REFERENCE               = 0x77,
    280 	DATK_RVALUE_REFERENCE        = 0x78,
    281 	DATK_MACROS                  = 0x79,
    282 	DATK_CALL_ALL_CALLS          = 0x7a,
    283 	DATK_CALL_ALL_SOURCE_CALLS   = 0x7b,
    284 	DATK_CALL_ALL_TAIL_CALLS     = 0x7c,
    285 	DATK_CALL_RETURN_PC          = 0x7d,
    286 	DATK_CALL_VALUE              = 0x7e,
    287 	DATK_CALL_ORIGIN             = 0x7f,
    288 	DATK_CALL_PARAMETER          = 0x80,
    289 	DATK_CALL_PC                 = 0x81,
    290 	DATK_CALL_TAIL_CALL          = 0x82,
    291 	DATK_CALL_TARGET             = 0x83,
    292 	DATK_CALL_TARGET_CLOBBERED   = 0x84,
    293 	DATK_CALL_DATA_LOCATION      = 0x85,
    294 	DATK_CALL_DATA_VALUE         = 0x86,
    295 	DATK_NORETURN                = 0x87,
    296 	DATK_ALIGNMENT               = 0x88,
    297 	DATK_EXPORT_SYMBOLS          = 0x89,
    298 	DATK_DELETED                 = 0x8a,
    299 	DATK_DEFAULTED               = 0x8b,
    300 	DATK_LOCLISTS_BASE           = 0x8c,
    301 	DATK_LO_USER                 = 0x2000,
    302 	DATK_HI_USER                 = 0x3fff,
    303 } DWARFAttributeKind;
    304 
    305 typedef enum {
    306 	DFK_ADDR           = 0x01,
    307 	DFK_BLOCK2         = 0x03,
    308 	DFK_BLOCK4         = 0x04,
    309 	DFK_DATA2          = 0x05,
    310 	DFK_DATA4          = 0x06,
    311 	DFK_DATA8          = 0x07,
    312 	DFK_STRING         = 0x08,
    313 	DFK_BLOCK          = 0x09,
    314 	DFK_BLOCK1         = 0x0a,
    315 	DFK_DATA1          = 0x0b,
    316 	DFK_FLAG           = 0x0c,
    317 	DFK_SDATA          = 0x0d,
    318 	DFK_STRP           = 0x0e,
    319 	DFK_UDATA          = 0x0f,
    320 	DFK_REF_ADDR       = 0x10,
    321 	DFK_REF1           = 0x11,
    322 	DFK_REF2           = 0x12,
    323 	DFK_REF4           = 0x13,
    324 	DFK_REF8           = 0x14,
    325 	DFK_REF_UDATA      = 0x15,
    326 	DFK_INDIRECT       = 0x16,
    327 	DFK_SEC_OFFSET     = 0x17,
    328 	DFK_EXPRLOC        = 0x18,
    329 	DFK_FLAG_PRESENT   = 0x19,
    330 	DFK_STRX           = 0x1a,
    331 	DFK_ADDRX          = 0x1b,
    332 	DFK_REF_SUP4       = 0x1c,
    333 	DFK_STRP_SUP       = 0x1d,
    334 	DFK_DATA16         = 0x1e,
    335 	DFK_LINE_STRP      = 0x1f,
    336 	DFK_REF_SIG8       = 0x20,
    337 	DFK_IMPLICIT_CONST = 0x21,
    338 	DFK_LOCLISTX       = 0x22,
    339 	DFK_RNGLISTX       = 0x23,
    340 	DFK_REF_SUP8       = 0x24,
    341 	DFK_STRX1          = 0x25,
    342 	DFK_STRX2          = 0x26,
    343 	DFK_STRX3          = 0x27,
    344 	DFK_STRX4          = 0x28,
    345 	DFK_ADDRX1         = 0x29,
    346 	DFK_ADDRX2         = 0x2a,
    347 	DFK_ADDRX3         = 0x2b,
    348 	DFK_ADDRX4         = 0x2c,
    349 } DWARFFormKind;
    350 
    351 typedef struct {
    352 	DWARFAttributeKind kind;
    353 	DWARFFormKind      form_kind;
    354 } DWARFAttribute;
    355 
    356 typedef enum {
    357 	DAK_ARRAY_TYPE               = 0x01,
    358 	DAK_CLASS_TYPE               = 0x02,
    359 	DAK_ENTRY_POINT              = 0x03,
    360 	DAK_ENUMERATION_TYPE         = 0x04,
    361 	DAK_FORMAL_PARAMETER         = 0x05,
    362 	DAK_IMPORTED_DECLARATION     = 0x08,
    363 	DAK_LABEL                    = 0x0a,
    364 	DAK_LEXICAL_BLOCK            = 0x0b,
    365 	DAK_MEMBER                   = 0x0d,
    366 	DAK_POINTER_TYPE             = 0x0f,
    367 	DAK_REFERENCE_TYPE           = 0x10,
    368 	DAK_COMPILE_UNIT             = 0x11,
    369 	DAK_STRING_TYPE              = 0x12,
    370 	DAK_STRUCTURE_TYPE           = 0x13,
    371 	DAK_SUBROUTINE_TYPE          = 0x15,
    372 	DAK_TYPEDEF                  = 0x16,
    373 	DAK_UNION_TYPE               = 0x17,
    374 	DAK_UNSPECIFIED_PARAMETERS   = 0x18,
    375 	DAK_VARIANT                  = 0x19,
    376 	DAK_COMMON_BLOCK             = 0x1a,
    377 	DAK_COMMON_INCLUSION         = 0x1b,
    378 	DAK_INHERITANCE              = 0x1c,
    379 	DAK_INLINED_SUBROUTINE       = 0x1d,
    380 	DAK_MODULE                   = 0x1e,
    381 	DAK_PTR_TO_MEMBER_TYPE       = 0x1f,
    382 	DAK_SET_TYPE                 = 0x20,
    383 	DAK_SUBRANGE_TYPE            = 0x21,
    384 	DAK_WITH_STMT                = 0x22,
    385 	DAK_ACCESS_DECLARATION       = 0x23,
    386 	DAK_BASE_TYPE                = 0x24,
    387 	DAK_CATCH_BLOCK              = 0x25,
    388 	DAK_CONST_TYPE               = 0x26,
    389 	DAK_CONSTANT                 = 0x27,
    390 	DAK_ENUMERATOR               = 0x28,
    391 	DAK_FILE_TYPE                = 0x29,
    392 	DAK_FRIEND                   = 0x2a,
    393 	DAK_NAMELIST                 = 0x2b,
    394 	DAK_NAMELIST_ITEM            = 0x2c,
    395 	DAK_PACKED_TYPE              = 0x2d,
    396 	DAK_SUBPROGRAM               = 0x2e,
    397 	DAK_TEMPLATE_TYPE_PARAMETER  = 0x2f,
    398 	DAK_TEMPLATE_VALUE_PARAMETER = 0x30,
    399 	DAK_THROWN_TYPE              = 0x31,
    400 	DAK_TRY_BLOCK                = 0x32,
    401 	DAK_VARIANT_PART             = 0x33,
    402 	DAK_VARIABLE                 = 0x34,
    403 	DAK_VOLATILE_TYPE            = 0x35,
    404 	DAK_DWARF_PROCEDURE          = 0x36,
    405 	DAK_RESTRICT_TYPE            = 0x37,
    406 	DAK_INTERFACE_TYPE           = 0x38,
    407 	DAK_NAMESPACE                = 0x39,
    408 	DAK_IMPORTED_MODULE          = 0x3a,
    409 	DAK_UNSPECIFIED_TYPE         = 0x3b,
    410 	DAK_PARTIAL_UNIT             = 0x3c,
    411 	DAK_IMPORTED_UNIT            = 0x3d,
    412 	DAK_CONDITION                = 0x3f,
    413 	DAK_SHARED_TYPE              = 0x40,
    414 	DAK_TYPE_UNIT                = 0x41,
    415 	DAK_RVALUE_REFERENCE_TYPE    = 0x42,
    416 	DAK_TEMPLATE_ALIAS           = 0x43,
    417 	DAK_COARRAY_TYPE             = 0x44,
    418 	DAK_GENERIC_SUBRANGE         = 0x45,
    419 	DAK_DYNAMIC_TYPE             = 0x46,
    420 	DAK_ATOMIC_TYPE              = 0x47,
    421 	DAK_CALL_SITE                = 0x48,
    422 	DAK_CALL_SITE_PARAMETER      = 0x49,
    423 	DAK_SKELETON_UNIT            = 0x4a,
    424 	DAK_IMMUTABLE_TYPE           = 0x4b,
    425 	DAK_LO_USER                  = 0x4080,
    426 	DAK_HI_USER                  = 0xffff
    427 } DWARFAbbreviationKind;
    428 
    429 typedef struct DWARFAbbreviation {
    430 	DWARFAbbreviationKind kind;
    431 	b32    has_children;
    432 	u64    abbreviation_code;
    433 
    434 	DWARFAttribute *data;
    435 	s16             count;
    436 	s16             capacity;
    437 
    438 	struct DWARFAbbreviation *next;
    439 } DWARFAbbreviation;
    440 
    441 #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
    442 #error "reader functions not yet implemented for big endian hosts!"
    443 #else
    444 function u16
    445 u16_host_from_be(u8 *s)
    446 {
    447 	u16 result = 0;
    448 	result |= s[0]; result <<= 8;
    449 	result |= s[1];
    450 	return result;
    451 }
    452 
    453 function u16
    454 u16_host_from_le(u8 *s)
    455 {
    456 	u16 result = 0;
    457 	result |= s[1]; result <<= 8;
    458 	result |= s[0];
    459 	return result;
    460 }
    461 
    462 function u32
    463 u32_host_from_be(u8 *s)
    464 {
    465 	u32 result = 0;
    466 	result |= s[0]; result <<= 8;
    467 	result |= s[1]; result <<= 8;
    468 	result |= s[2]; result <<= 8;
    469 	result |= s[3];
    470 	return result;
    471 }
    472 
    473 function u32
    474 u32_host_from_le(u8 *s)
    475 {
    476 	u32 result = 0;
    477 	result |= s[3]; result <<= 8;
    478 	result |= s[2]; result <<= 8;
    479 	result |= s[1]; result <<= 8;
    480 	result |= s[0];
    481 	return result;
    482 }
    483 
    484 function u64
    485 u64_host_from_be(u8 *s)
    486 {
    487 	u64 result = 0;
    488 	result |= s[0]; result <<= 8;
    489 	result |= s[1]; result <<= 8;
    490 	result |= s[2]; result <<= 8;
    491 	result |= s[3]; result <<= 8;
    492 	result |= s[4]; result <<= 8;
    493 	result |= s[5]; result <<= 8;
    494 	result |= s[6]; result <<= 8;
    495 	result |= s[7];
    496 	return result;
    497 }
    498 
    499 function u64
    500 u64_host_from_le(u8 *s)
    501 {
    502 	u64 result = 0;
    503 	result |= s[7]; result <<= 8;
    504 	result |= s[6]; result <<= 8;
    505 	result |= s[5]; result <<= 8;
    506 	result |= s[4]; result <<= 8;
    507 	result |= s[3]; result <<= 8;
    508 	result |= s[2]; result <<= 8;
    509 	result |= s[1]; result <<= 8;
    510 	result |= s[0];
    511 	return result;
    512 }
    513 #endif
    514 
    515 #define zero_struct(s) mem_clear(s, 0, sizeof(*s));
    516 function void *
    517 mem_clear(void *restrict _s, u8 byte, iz size)
    518 {
    519 	u8 *s = _s;
    520 	for (iz i = 0; i < size; i++)
    521 		s[i] = byte;
    522 	return s;
    523 }
    524 
    525 function void *
    526 mem_copy(void *restrict dest, void *restrict src, iz size)
    527 {
    528 	u8 *s = src, *d = dest;
    529 	for (iz i = 0; i < size; i++)
    530 		d[i] = s[i];
    531 	return dest;
    532 }
    533 
    534 #define alloc(a, t, c) (t *)alloc_(a, _Alignof(t), sizeof(t), c)
    535 function void *
    536 alloc_(Arena *a, iz alignment, iz size, iz count)
    537 {
    538 	iz capacity = a->end - a->beg;
    539 	iz padding  = -(uintptr_t)a->beg & alignment;
    540 	if ((capacity - padding) / size  < count) {
    541 		ASSERT(0 && "OOM: buy more ram lol");
    542 	}
    543 	u8 *result = a->beg + padding;
    544 	a->beg += padding + size * count;
    545 	return mem_clear(result, 0, size * count);
    546 }
    547 
    548 enum { DA_INITIAL_CAP = 4 };
    549 #define da_reserve(a, s, n) \
    550   (s)->data = da_reserve_((a), (s)->data, &(s)->capacity, (s)->count + n, \
    551                           _Alignof(typeof(*(s)->data)), sizeof(*(s)->data))
    552 
    553 #define da_push(a, s) \
    554   ((s)->count == (s)->capacity  \
    555     ? da_reserve(a, s, 1),      \
    556       (s)->data + (s)->count++  \
    557     : (s)->data + (s)->count++)
    558 
    559 function void *
    560 da_reserve_(Arena *a, void *data, s16 *capacity, iz needed, iz align, iz size)
    561 {
    562 	iz cap = *capacity;
    563 
    564 	/* NOTE(rnp): handle both 0 initialized DAs and DAs that need to be moved (they started
    565 	 * on the stack or someone allocated something in the middle of the arena during usage) */
    566 	if (!data || a->beg != (u8 *)data + cap * size) {
    567 		void *copy = alloc_(a, size, align, cap);
    568 		if (data) mem_copy(copy, data, cap * size);
    569 		data = copy;
    570 	}
    571 
    572 	if (!cap) cap = DA_INITIAL_CAP;
    573 	while (cap < needed) cap *= 2;
    574 	alloc_(a, size, align, cap - *capacity);
    575 	*capacity = cap;
    576 	return data;
    577 }
    578 
    579 function str8
    580 c_str_to_str8(u8 *c_str)
    581 {
    582 	str8 result = {.data = c_str};
    583 	if (c_str) while (*c_str) c_str++;
    584 	result.len = c_str - result.data;
    585 	return result;
    586 }
    587 
    588 function b32
    589 str8_equal(str8 a, str8 b)
    590 {
    591 	b32 result = a.len == b.len;
    592 	for (iz i = 0; result && i < a.len; i++)
    593 		result &= a.data[i] == b.data[i];
    594 	return result;
    595 }
    596 
    597 function str8
    598 str8_chop(str8 a, iz length)
    599 {
    600 	str8 result = {0};
    601 	if (length < a.len) {
    602 		result.data = a.data + length;
    603 		result.len  = a.len  - length;
    604 	}
    605 	return result;
    606 }
    607 
    608 function iz
    609 str8_read_uleb128(str8 a, u64 *uleb128)
    610 {
    611 	/* TODO(rnp): check for overflow ... */
    612 	iz result = 0;
    613 	iz shift  = 0;
    614 	u64 n     = 0;
    615 	while (result < a.len) {
    616 		u8 byte = a.data[result++];
    617 		n |= (u64)(byte & 0x7F) << shift;
    618 		if ((byte & 0x80) == 0)
    619 			break;
    620 		shift += 7;
    621 	}
    622 	*uleb128 = n;
    623 	return result;
    624 }
    625 
    626 function str8_reader
    627 str8_reader_from_str8(str8 s)
    628 {
    629 	str8_reader result = {0};
    630 	result.data  = s.data;
    631 	result.count = s.len;
    632 	return result;
    633 }
    634 
    635 function u16
    636 str8_read_u16(str8_reader *r, b32 big_endian)
    637 {
    638 	u16 result = 0;
    639 	r->errors |= r->index + 2 > r->count;
    640 	if (!r->errors) {
    641 		if (big_endian) result = u16_host_from_be(r->data + r->index);
    642 		else            result = u16_host_from_le(r->data + r->index);
    643 		r->index += 2;
    644 	}
    645 	return result;
    646 }
    647 
    648 function u32
    649 str8_read_u32(str8_reader *r, b32 big_endian)
    650 {
    651 	u32 result = 0;
    652 	r->errors |= r->index + 4 > r->count;
    653 	if (!r->errors) {
    654 		if (big_endian) result = u32_host_from_be(r->data + r->index);
    655 		else            result = u32_host_from_le(r->data + r->index);
    656 		r->index += 4;
    657 	}
    658 	return result;
    659 }
    660 
    661 function u64
    662 str8_read_u64(str8_reader *r, b32 big_endian)
    663 {
    664 	u64 result = 0;
    665 	r->errors |= r->index + 8 > r->count;
    666 	if (!r->errors) {
    667 		if (big_endian) result = u32_host_from_be(r->data + r->index);
    668 		else            result = u32_host_from_le(r->data + r->index);
    669 		r->index += 8;
    670 	}
    671 	return result;
    672 }
    673 
    674 function void
    675 print_u64(u64 v)
    676 {
    677 	printf("%zu", v);
    678 }
    679 
    680 function void print_u16(u16 v) { print_u64(v); }
    681 function void print_u32(u32 v) { print_u64(v); }
    682 
    683 function void
    684 print_ELFFormat(ELFFormat format)
    685 {
    686 	#define X(name, value, pretty) [name] = str8(pretty),
    687 	local_persist str8 format_pretty[] = {ELF_FORMATS};
    688 	#undef X
    689 	if (format < countof(format_pretty) && format_pretty[format].len) {
    690 		printf("%.*s", (s32)format_pretty[format].len, format_pretty[format].data);
    691 	} else {
    692 		printf("Invalid");
    693 	}
    694 }
    695 
    696 function void
    697 print_ELFEndianKind(ELFEndianKind kind)
    698 {
    699 	#define X(name, value, pretty) [name] = str8(pretty),
    700 	local_persist str8 kind_pretty[] = {ELF_ENDIANNESS};
    701 	#undef X
    702 	if (kind < countof(kind_pretty) && kind_pretty[kind].len) {
    703 		printf("%.*s", (s32)kind_pretty[kind].len, kind_pretty[kind].data);
    704 	} else {
    705 		printf("Invalid");
    706 	}
    707 }
    708 
    709 function void
    710 print_ELFABIKind(ELFABIKind kind)
    711 {
    712 	#define X(name, value, pretty) [name] = str8(pretty),
    713 	local_persist str8 kind_pretty[] = {ELF_OS_ABI};
    714 	#undef X
    715 	if (kind < countof(kind_pretty) && kind_pretty[kind].len) {
    716 		printf("%.*s", (s32)kind_pretty[kind].len, kind_pretty[kind].data);
    717 	} else {
    718 		printf("Invalid");
    719 	}
    720 }
    721 
    722 function void
    723 print_ELFKind(ELFKind kind)
    724 {
    725 	#define X(name, value, pretty) [name] = str8(pretty),
    726 	local_persist str8 kind_pretty[] = {ELF_KINDS};
    727 	#undef X
    728 	if (kind < countof(kind_pretty) && kind_pretty[kind].len) {
    729 		printf("%.*s", (s32)kind_pretty[kind].len, kind_pretty[kind].data);
    730 	} else {
    731 		printf("Invalid");
    732 	}
    733 }
    734 
    735 function void
    736 print_elf_header(ELFHeader *eh)
    737 {
    738 	printf("ELF Header:\n");
    739 	s32 max_name_len = 0;
    740 	#define X(ctype, name) if (max_name_len < sizeof(#name) - 1) max_name_len = sizeof(#name) - 1;
    741 	ELF_HEADER_MEMBERS
    742 	#undef X
    743 
    744 	#define X(ctype, name) printf(#name ": %*s", (s32)(max_name_len - sizeof(#name) + 1), ""); \
    745 	                       print_##ctype(eh->name); printf("\n");
    746 	ELF_HEADER_MEMBERS
    747 	#undef X
    748 }
    749 
    750 function b32
    751 is_elf(str8 file)
    752 {
    753 	b32 result = file.len >= 16;
    754 	result &= file.data[0] == 0x7F;
    755 	result &= file.data[1] == 'E';
    756 	result &= file.data[2] == 'L';
    757 	result &= file.data[3] == 'F';
    758 	return result;
    759 }
    760 
    761 function b32
    762 elf_header_from_file(ELFHeader *eh, str8 file)
    763 {
    764 	b32 result = 0;
    765 	if (is_elf(file)) {
    766 		eh->format      = file.data[4];
    767 		eh->endianness  = file.data[5];
    768 		eh->abi         = file.data[7];
    769 		eh->abi_version = file.data[8];
    770 
    771 		str8_reader reader = str8_reader_from_str8(str8_chop(file, 16));
    772 		b32 big_endian     = eh->endianness == EEK_BIG;
    773 		eh->kind                            = str8_read_u16(&reader, big_endian);
    774 		eh->machine                         = str8_read_u16(&reader, big_endian);
    775 		eh->version                         = str8_read_u32(&reader, big_endian);
    776 		if (eh->format == EF_64) {
    777 			eh->entry_point_offset      = str8_read_u64(&reader, big_endian);
    778 			eh->program_header_offset   = str8_read_u64(&reader, big_endian);
    779 			eh->section_header_offset   = str8_read_u64(&reader, big_endian);
    780 		} else {
    781 			eh->entry_point_offset      = str8_read_u32(&reader, big_endian);
    782 			eh->program_header_offset   = str8_read_u32(&reader, big_endian);
    783 			eh->section_header_offset   = str8_read_u32(&reader, big_endian);
    784 		}
    785 		eh->flags                           = str8_read_u32(&reader, big_endian);
    786 		eh->elf_header_size                 = str8_read_u16(&reader, big_endian);
    787 		eh->program_header_entry_size       = str8_read_u16(&reader, big_endian);
    788 		eh->program_header_count            = str8_read_u16(&reader, big_endian);
    789 		eh->section_header_entry_size       = str8_read_u16(&reader, big_endian);
    790 		eh->section_header_count            = str8_read_u16(&reader, big_endian);
    791 		eh->section_header_name_table_index = str8_read_u16(&reader, big_endian);
    792 		result = !reader.errors && file.data[6] == eh->version;
    793 	}
    794 	return result;
    795 }
    796 
    797 function ELFSectionHeader *
    798 elf_extract_section_headers(Arena *a, str8 file, ELFHeader *eh)
    799 {
    800 	TODO(eh->format == EF_64);
    801 	TODO(eh->endianness == EEK_LITTLE);
    802 	TODO(file.len >= eh->section_header_offset + eh->section_header_entry_size * eh->section_header_count);
    803 	u32 sections = eh->section_header_count;
    804 	ELFSectionHeader *result = alloc(a, ELFSectionHeader, sections);
    805 	for (u32 i = 0; i < sections; i++) {
    806 		iz offset = eh->section_header_offset + eh->section_header_entry_size * i;
    807 		result[i].sh64 = *(ELFSectionHeader64 *)(file.data + offset);
    808 	}
    809 
    810 	u8 *str_tab = file.data + result[eh->section_header_name_table_index].sh64.offset;
    811 	for (u32 i = 0; i < sections; i++)
    812 		result[i].name = c_str_to_str8(str_tab + result[i].sh64.name_table_offset);
    813 
    814 	return result;
    815 }
    816 
    817 function ELFSection
    818 elf_lookup_section(str8 name, str8 file, ELFSectionHeader *shs, u32 sections_count)
    819 {
    820 	ELFSection result = {0};
    821 	for (u32 i = 0; i < sections_count; i++) {
    822 		if (str8_equal(shs[i].name, name)) {
    823 			result.header     = shs + i;
    824 			result.store.data = file.data + shs[i].sh64.offset;
    825 			result.store.len  = shs[i].sh64.size;
    826 			break;
    827 		}
    828 	}
    829 	return result;
    830 }
    831 
    832 function iz
    833 dwarf_read_unit_header(DWARFUnitHeader *duh, str8 store)
    834 {
    835 	iz result = 0;
    836 	/* TODO(rnp): context containing endianess, dwarf size */
    837 	duh->dwarf_64 = *(u32 *)store.data == 0xffffffff;
    838 	if (duh->dwarf_64) { result += 12; duh->length = *(u64 *)(store.data + 4); }
    839 	else               { result +=  4; duh->length = *(u32 *)(store.data);     }
    840 	duh->version = *(u16 *)(store.data + result);
    841 	result += 2;
    842 	if (duh->version == 5) duh->kind = store.data[result++];
    843 	duh->address_size = store.data[result++];
    844 	if (duh->dwarf_64) { duh->abbreviation_offset = *(u64 *)(store.data + result); result += 8; }
    845 	else               { duh->abbreviation_offset = *(u32 *)(store.data + result); result += 4; }
    846 	return result;
    847 }
    848 
    849 function iz
    850 dwarf_parse_abbrevation(Arena *a, DWARFAbbreviation *abbrv, str8 table)
    851 {
    852 	iz table_start_size = table.len;
    853 	iz result = 0;
    854 	table = str8_chop(table, str8_read_uleb128(table, &abbrv->abbreviation_code));
    855 	u64 abbrv_kind = 0;
    856 	table = str8_chop(table, str8_read_uleb128(table, &abbrv_kind));
    857 	abbrv->kind = abbrv_kind;
    858 	if (table.len < 1) return table_start_size;
    859 	abbrv->has_children = *table.data;
    860 	table = str8_chop(table, 1);
    861 	for (;;) {
    862 		u64 attr_kind = 0, form_kind = 0;
    863 		table = str8_chop(table, str8_read_uleb128(table, &attr_kind));
    864 		table = str8_chop(table, str8_read_uleb128(table, &form_kind));
    865 		TODO(form_kind != DFK_INDIRECT);
    866 		TODO(form_kind != DFK_IMPLICIT_CONST);
    867 		if (attr_kind) {
    868 			*da_push(a, abbrv) = (DWARFAttribute){attr_kind, form_kind};
    869 		} else {
    870 			ASSERT(form_kind == 0);
    871 			break;
    872 		}
    873 	}
    874 	result = table_start_size - table.len;
    875 	return result;
    876 }
    877 
    878 function DWARFAbbreviation
    879 dwarf_lookup_abbreviation(Arena *a, str8 table, u64 key)
    880 {
    881 	DWARFAbbreviation result = {0};
    882 	while (key != result.abbreviation_code && table.len > 1) {
    883 		result.count = 0;
    884 		table = str8_chop(table, dwarf_parse_abbrevation(a, &result, table));
    885 	}
    886 	return result;
    887 }
    888 
    889 function b32
    890 elfinspect(Arena arena, str8 file)
    891 {
    892 	b32 result = is_elf(file);
    893 
    894 	if (result) {
    895 		ELFHeader header = {0};
    896 		if (!elf_header_from_file(&header, file)) {
    897 			return 1;
    898 		}
    899 		ELFSectionHeader *sections = elf_extract_section_headers(&arena, file, &header);
    900 		print_elf_header(&header);
    901 		printf("\nSections:\n");
    902 		for (u32 i = 0; i < header.section_header_count; i++) {
    903 			printf("[%2u]:", i);
    904 			str8 name = sections[i].name;
    905 			if (name.len) printf(" %.*s", (s32)name.len, name.data);
    906 			printf("\n");
    907 		}
    908 
    909 		ELFSection debug_info  = elf_lookup_section(str8(".debug_info"), file,
    910 		                                            sections, header.section_header_count);
    911 		ELFSection debug_abbrv = elf_lookup_section(str8(".debug_abbrev"), file,
    912 		                                            sections, header.section_header_count);
    913 		ELFSection debug_str_offsets = elf_lookup_section(str8(".debug_str_offsets"), file,
    914 		                                                  sections, header.section_header_count);
    915 		ELFSection debug_str = elf_lookup_section(str8(".debug_str"), file,
    916 		                                          sections, header.section_header_count);
    917 
    918 		str8 d_info_reader = debug_info.store;
    919 		DWARFUnitHeader d_info_header = {0};
    920 		d_info_reader = str8_chop(d_info_reader, dwarf_read_unit_header(&d_info_header, d_info_reader));
    921 		u64 abbreviation_code = 0;
    922 		str8 abbreviation_table = str8_chop(debug_abbrv.store, d_info_header.abbreviation_offset);
    923 		d_info_reader = str8_chop(d_info_reader, str8_read_uleb128(d_info_reader, &abbreviation_code));
    924 		DWARFAbbreviation abbrv = dwarf_lookup_abbreviation(&arena, abbreviation_table, abbreviation_code);
    925 
    926 		printf("\nFirst DWARF DIE:\n");
    927 		for (s16 i = 0; i < abbrv.count; i++) {
    928 			DWARFAttribute attr = abbrv.data[i];
    929 			if (attr.kind == 0)
    930 				continue;
    931 
    932 			switch (attr.kind) {
    933 			case DATK_PRODUCER:      printf("producer:      "); break;
    934 			case DATK_LANGUAGE:      printf("language:      "); break;
    935 			case DATK_ADDR_BASE:     printf("addr base:     "); break;
    936 			case DATK_LOCLISTS_BASE: printf("loc list base: "); break;
    937 			default: ASSERT(0); break;
    938 			}
    939 
    940 			switch (attr.form_kind) {
    941 			case DFK_STRX1: {
    942 				u32 str_offset_offset = *d_info_reader.data;
    943 				d_info_reader = str8_chop(d_info_reader, 1);
    944 				u32 str_offset = *(u32 *)(debug_str_offsets.store.data + str_offset_offset);
    945 				printf("%s", (char *)debug_str.store.data + str_offset);
    946 			} break;
    947 			case DFK_DATA2: {
    948 				u32 data = *(u16 *)d_info_reader.data;
    949 				d_info_reader = str8_chop(d_info_reader, 2);
    950 				printf("%u", data);
    951 			} break;
    952 			case DFK_SEC_OFFSET: {
    953 				u32 data = *(u32 *)d_info_reader.data;
    954 				d_info_reader = str8_chop(d_info_reader, 4);
    955 				printf("%u", data);
    956 			} break;
    957 			default: ASSERT(0); break;
    958 			}
    959 			printf("\n");
    960 		}
    961 
    962 		result = 1;
    963 	}
    964 
    965 	return result;
    966 }