// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) #ifndef DWARF_PARSE_H #define DWARF_PARSE_H typedef struct DW_Section { String8 name; String8 data; B32 is_dwo; } DW_Section; typedef struct DW_Input { DW_Section sec[DW_Section_Count]; DW_Section sup[DW_Section_Count]; } DW_Input; typedef struct DW_ListUnit { DW_Version version; U64 address_size; U64 segment_selector_size; U64 entry_size; String8 entries; } DW_ListUnit; typedef struct DW_ListUnitInput { U64 addr_count; U64 str_offset_count; U64 rnglist_count; U64 loclist_count; Rng1U64Array addr_ranges; Rng1U64Array str_offset_ranges; Rng1U64Array rnglist_ranges; Rng1U64Array loclist_ranges; DW_ListUnit *addrs; DW_ListUnit *str_offsets; DW_ListUnit *rnglists; DW_ListUnit *loclists; } DW_ListUnitInput; typedef struct DW_AbbrevTableEntry { U64 id; U64 off; } DW_AbbrevTableEntry; typedef struct DW_AbbrevTable DW_AbbrevTable; struct DW_AbbrevTable { U64 count; DW_AbbrevTableEntry *entries; }; typedef enum DW_AbbrevKind { DW_Abbrev_Null, DW_Abbrev_Tag, DW_Abbrev_Attrib, DW_Abbrev_AttribSequenceEnd, DW_Abbrev_DIEBegin, DW_Abbrev_DIEEnd, } DW_AbbrevKind; typedef U32 DW_AbbrevFlags; enum { DW_AbbrevFlag_HasImplicitConst = (1 << 0), DW_AbbrevFlag_HasChildren = (1 << 1), }; typedef struct DW_Abbrev { DW_AbbrevKind kind; U64 sub_kind; U64 id; U64 const_value; DW_AbbrevFlags flags; } DW_Abbrev; typedef union DW_Form { String8 addr; String8 block; String8 data; String8 string; String8 exprloc; B8 flag; S64 sdata; U64 udata; U64 sec_offset; U64 ref; U64 strp_sup; U64 xval; U64 addrx; U64 strx; U64 rnglistx; U64 ptr; U64 implicit_const; } DW_Form; typedef struct DW_Attrib { U64 info_off; U64 abbrev_off; U64 abbrev_id; DW_AttribKind attrib_kind; DW_FormKind form_kind; DW_Form form; } DW_Attrib; typedef struct DW_AttribNode { struct DW_AttribNode *next; DW_Attrib v; } DW_AttribNode; typedef struct DW_AttribList { DW_AttribNode *first; DW_AttribNode *last; U64 count; } DW_AttribList; typedef struct DW_Tag { B32 has_children; U64 abbrev_id; DW_TagKind kind; DW_AttribList attribs; U64 info_off; } DW_Tag; typedef struct DW_TagNode { DW_Tag tag; struct DW_TagNode *sibling; struct DW_TagNode *first_child; struct DW_TagNode *last_child; } DW_TagNode; typedef struct DW_Loc { Rng1U64 range; String8 expr; } DW_Loc; typedef struct DW_LocNode { DW_Loc v; struct DW_LocNode *next; } DW_LocNode; typedef struct DW_LocList { U64 count; DW_LocNode *first; DW_LocNode *last; } DW_LocList; typedef struct DW_CompUnit { B32 relaxed; DW_Ext ext; DW_CompUnitKind kind; DW_Version version; DW_Format format; U64 address_size; U64 abbrev_off; Rng1U64 info_range; U64 first_tag_info_off; DW_AbbrevTable abbrev_table; String8 abbrev_data; DW_ListUnit *addr_lu; DW_ListUnit *str_offsets_lu; DW_ListUnit *rnglists_lu; DW_ListUnit *loclists_lu; U64 low_pc; U64 dwo_id; DW_Tag tag; HashTable *tag_ht; } DW_CompUnit; typedef struct DW_TagTree { DW_TagNode *root; U64 tag_count; } DW_TagTree; typedef struct DW_LineFile { String8 file_name; U64 dir_idx; U64 modify_time; U64 file_size; U128 md5_digest; String8 source; } DW_LineFile; typedef struct DW_LineVMFileNode { struct DW_LineVMFileNode *next; DW_LineFile file; } DW_LineVMFileNode; typedef struct DW_LineVMFileList { U64 node_count; DW_LineVMFileNode *first; DW_LineVMFileNode *last; } DW_LineVMFileList; typedef struct DW_LineVMFileArray { U64 count; DW_LineFile *v; } DW_LineVMFileArray; typedef struct DW_LineVMHeader { Rng1U64 unit_range; DW_Version version; U8 address_size; // Duplicates size from the compilation unit but is needed to support stripped exe that just have .debug_line and .debug_line_str. U8 segment_selector_size; U64 header_length; U8 min_inst_len; U8 max_ops_for_inst; U8 default_is_stmt; S8 line_base; U8 line_range; U8 opcode_base; U64 num_opcode_lens; U8 *opcode_lens; DW_LineVMFileArray dir_table; DW_LineVMFileArray file_table; } DW_LineVMHeader; typedef struct DW_LineVMState { U64 address; // Address of a machine instruction. U32 op_index; // This is used by the VLIW instructions to indicate index of operation inside the instruction. // Line table doesn't contain full path to a file, instead // DWARF encodes path as two indices. First index will point into a directory // table, and second points into a file name table. U32 file_index; U32 line; U32 column; B32 is_stmt; // Indicates that "address" points to place suitable for a breakpoint. B32 basic_block; // Indicates that the "address" is inside a basic block. // Indicates that "address" points to place where function starts. // Usually prologue is the place where compiler emits instructions to // prepare stack for a function. B32 prologue_end; B32 epilogue_begin; // Indicates that "address" points to section where function exits and unwinds stack. U64 isa; // Instruction set that is used. U64 discriminator; // Arbitrary id that indicates to which block these instructions belong. B32 end_sequence; // Indicates that "address" points to the first instruction in the instruction block that follows. } DW_LineVMState; typedef struct DW_Line { U64 file_index; U32 line; U32 column; U64 address; } DW_Line; typedef struct DW_LineNode { struct DW_LineNode *next; DW_Line v; } DW_LineNode; typedef struct DW_LineSeqNode { struct DW_LineSeqNode *next; U64 count; DW_LineNode *first; DW_LineNode *last; } DW_LineSeqNode; typedef struct DW_LineTableParseResult { DW_LineVMHeader vm_header; U64 seq_count; DW_LineSeqNode *first_seq; DW_LineSeqNode *last_seq; } DW_LineTableParseResult; //////////////////////////////// // .debug_pubnames and .debug_pubtypes typedef struct DW_PubStringsBucket { struct DW_PubStringsBucket *next; String8 string; U64 info_off; U64 cu_info_off; } DW_PubStringsBucket; typedef struct DW_PubStringsTable { U64 size; DW_PubStringsBucket **buckets; } DW_PubStringsTable; typedef struct DW_Reference { DW_CompUnit *cu; U64 info_off; } DW_Reference; // hasher internal U64 dw_hash_from_string(String8 string); // deserial helpers internal U64 str8_deserial_read_dwarf_packed_size(String8 string, U64 off, U64 *size_out); internal U64 str8_deserial_read_dwarf_uint (String8 string, U64 off, DW_Format format, U64 *uint_out); internal U64 str8_deserial_read_uleb128 (String8 string, U64 off, U64 *value_out); internal U64 str8_deserial_read_sleb128 (String8 string, U64 off, S64 *value_out); internal U64 str8_deserial_read_uleb128_array(Arena *arena, String8 string, U64 off, U64 count, U64 **arr_out); internal U64 str8_deserial_read_sleb128_array(Arena *arena, String8 string, U64 off, U64 count, S64 **arr_out); internal Rng1U64List dw_unit_ranges_from_data(Arena *arena, String8 data); // list units internal U64 dw_read_list_unit_header_addr (String8 unit_data, DW_ListUnit *lu_out); internal U64 dw_read_list_unit_header_str_offsets(String8 unit_data, DW_ListUnit *lu_out); internal U64 dw_read_list_unit_header_list (String8 unit_data, DW_ListUnit *lu_out); internal DW_ListUnitInput dw_list_unit_input_from_input(Arena *arena, DW_Input *input); internal U64 dw_offset_from_list_unit(DW_ListUnit *lu, U64 index); internal U64 dw_addr_from_list_unit (DW_ListUnit *lu, U64 index); // abbrev table internal U64 dw_read_abbrev_tag (String8 data, U64 offset, DW_Abbrev *out_abbrev); internal U64 dw_read_abbrev_attrib(String8 data, U64 offset, DW_Abbrev *out_abbrev); internal DW_AbbrevTable dw_make_abbrev_table(Arena *arena, String8 abbrev_data, U64 start_abbrev_off); internal U64 dw_abbrev_offset_from_abbrev_id(DW_AbbrevTable table, U64 abbrev_id); // form and tag internal U64 dw_read_form(String8 data, U64 off, DW_Version version, DW_Format unit_format, U64 address_size, DW_FormKind form_kind, U64 implicit_const, DW_Form *form_out); internal U64 dw_read_tag (Arena *arena, String8 tag_data, U64 tag_off, U64 tag_base, DW_AbbrevTable abbrev_table, String8 abbrev_data, DW_Version version, DW_Format unit_format, U64 address_size, DW_Tag *tag_out); internal U64 dw_read_tag_cu(Arena *arena, DW_Input *input, DW_CompUnit *cu, U64 info_off, DW_Tag *tag_out); // attrib interp internal U64 dw_interp_sec_offset(DW_FormKind form_kind, DW_Form form); internal String8 dw_interp_exprloc (DW_FormKind form_kind, DW_Form form); internal U128 dw_interp_const_u128(DW_FormKind form_kind, DW_Form form); internal U64 dw_interp_const_u64 (DW_FormKind form_kind, DW_Form form); internal U32 dw_interp_const_u32 (DW_FormKind form_kind, DW_Form form); internal S64 dw_interp_const_s64 (DW_FormKind form_kind, DW_Form form); internal S32 dw_interp_const_s32 (DW_FormKind form_kind, DW_Form form); internal B32 dw_interp_flag (DW_FormKind form_kind, DW_Form form); internal U64 dw_interp_address (U64 address_size, U64 base_addr, DW_ListUnit *addr_xlist, DW_FormKind form_kind, DW_Form form); internal String8 dw_interp_block (DW_Input *input, DW_CompUnit *cu, DW_FormKind form_kind, DW_Form form); internal String8 dw_interp_string (DW_Input *input, DW_Format unit_format, DW_ListUnit *str_offsets, DW_FormKind form_kind, DW_Form form); internal String8 dw_interp_line_ptr (DW_Input *input, DW_FormKind form_kind, DW_Form form); internal DW_LineFile * dw_interp_file (DW_LineVMHeader *line_vm, DW_FormKind form_kind, DW_Form form); internal DW_Reference dw_interp_ref (DW_Input *input, DW_CompUnit *cu, DW_FormKind form_kind, DW_Form form); internal DW_LocList dw_interp_loclist (Arena *arena, DW_Input *input, DW_CompUnit *cu, DW_FormKind form_kind, DW_Form form); internal Rng1U64List dw_interp_rnglist (Arena *arena, DW_Input *input, DW_CompUnit *cu, DW_FormKind form_kind, DW_Form form); internal String8 dw_exprloc_from_attrib (DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib); internal U128 dw_const_u128_from_attrib(DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib); internal U64 dw_const_u64_from_attrib (DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib); internal U32 dw_const_u32_from_attrib (DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib); internal S64 dw_const_s64_from_attrib (DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib); internal S32 dw_const_s32_from_attrib (DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib); internal B32 dw_flag_from_attrib (DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib); internal U64 dw_address_from_attrib (DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib); internal String8 dw_block_from_attrib (DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib); internal String8 dw_string_from_attrib (DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib); internal String8 dw_line_ptr_from_attrib (DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib); internal DW_LineFile * dw_file_from_attrib (DW_CompUnit *cu, DW_LineVMHeader *line_vm, DW_Attrib *attrib); internal DW_Reference dw_ref_from_attrib (DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib); internal DW_LocList dw_loclist_from_attrib (Arena *arena, DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib); internal Rng1U64List dw_rnglist_from_attrib (Arena *arena, DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib); internal String8 dw_exprloc_from_tag_attrib_kind (DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind); internal U128 dw_const_u128_from_tag_attrib_kind(DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind); internal U64 dw_const_u64_from_tag_attrib_kind (DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind); internal U32 dw_const_u32_from_tag_attrib_kind (DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind); internal B32 dw_flag_from_tag_attrib_kind (DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind); internal U64 dw_address_from_tag_attrib_kind (DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind); internal String8 dw_block_from_tag_attrib_kind (DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind); internal String8 dw_string_from_tag_attrib_kind (DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind); internal String8 dw_line_ptr_from_tag_attrib_kind (DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind); internal String8 dw_line_ptr_from_tag_attrib_kind (DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind); internal DW_LineFile * dw_file_from_tag_attrib_kind (DW_Input *input, DW_CompUnit *cu, DW_LineVMHeader *line_vm, DW_Tag tag, DW_AttribKind kind); internal DW_Reference dw_ref_from_tag_attrib_kind (DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind); internal DW_LocList dw_loclist_from_tag_attrib_kind (Arena *arena, DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind); internal Rng1U64List dw_rnglist_from_tag_attrib_kind (Arena *arena, DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind); // compile unit internal DW_CompUnit dw_cu_from_info_off(Arena *arena, DW_Input *input, DW_ListUnitInput lu_input, U64 offset, B32 relaxed); internal DW_TagTree dw_tag_tree_from_cu(Arena *arena, DW_Input *input, DW_CompUnit *cu); internal HashTable * dw_make_tag_hash_table(Arena *arena, DW_TagTree tag_tree); internal DW_TagNode * dw_tag_node_from_info_off(DW_CompUnit *cu, U64 info_off); // line info internal U64 dw_read_line_file(String8 line_data, U64 line_off, DW_Input *input, DW_Version unit_version, DW_Format unit_format, DW_Ext ext, U64 address_size, DW_ListUnit *str_offsets, U64 enc_count, U64 *enc_arr, DW_LineFile *line_file_out); internal U64 dw_read_line_vm_header(Arena *arena, String8 line_data, U64 line_off, DW_Input *input, String8 cu_dir, String8 cu_name, U8 cu_address_size, DW_ListUnit *cu_str_offsets, DW_LineVMHeader *header_out); internal void dw_line_vm_reset(DW_LineVMState *state, B32 default_is_stmt); internal void dw_line_vm_advance(DW_LineVMState *state, U64 advance, U64 min_inst_len, U64 max_ops_for_inst); internal DW_LineSeqNode * dw_push_line_seq(Arena* arena, DW_LineTableParseResult *parsed_tbl); internal DW_LineNode * dw_push_line(Arena *arena, DW_LineTableParseResult *tbl, DW_LineVMState *vm_state, B32 start_of_sequence); internal String8 dw_path_from_file(Arena *arena, DW_LineVMHeader *vm, DW_LineFile *file); internal String8 dw_path_from_file_idx(Arena *arena, DW_LineVMHeader *vm, U64 file_idx); internal DW_LineTableParseResult dw_parsed_line_table_from_data(Arena *arena, String8 unit_data, DW_Input *input, String8 cu_dir, String8 cu_name, U8 cu_address_size, DW_ListUnit *cu_str_offsets); // helper for .debug_pubtypes and .debug_pubnames internal DW_PubStringsTable dw_v4_pub_strings_table_from_section_kind(Arena *arena, DW_Input *input, DW_SectionKind section_kind); #endif // DWARF_PARSE_H