mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-06-13 07:32:23 -07:00
moved DWARF parser to use str8_deserial-style API, added to the parser
layer functionality for interpreting different types of attributes, added support for location lists, and API to enable parsing tags with abstract origin.
This commit is contained in:
@@ -109,7 +109,7 @@ if "%raddbg%"=="1" set didbuild=1 && %compile% ..\src\raddbg
|
||||
if "%radlink%"=="1" set didbuild=1 && %compile% ..\src\linker\lnk.c %compile_link% %link_natvis%"%~dp0\src\linker\linker.natvis" %out%radlink.exe || exit /b 1
|
||||
if "%raddump%"=="1" set didbuild=1 && %compile% ..\src\raddump\raddump_main.c %compile_link% %out%raddump.exe || exit /b 1
|
||||
if "%rdi_from_pdb%"=="1" set didbuild=1 && %compile% ..\src\rdi_from_pdb\rdi_from_pdb_main.c %compile_link% %out%rdi_from_pdb.exe || exit /b 1
|
||||
if "%rdi_from_dwarf%"=="1" set didbuild=1 && %compile% ..\src\rdi_from_dwarf\rdi_from_dwarf.c %compile_link% %out%rdi_from_dwarf.exe || exit /b 1
|
||||
if "%rdi_from_dwarf%"=="1" set didbuild=1 && %compile% ..\src\rdi_from_dwarf\rdi_from_dwarf_main.c %compile_link% %out%rdi_from_dwarf.exe || exit /b 1
|
||||
if "%rdi_dump%"=="1" set didbuild=1 && %compile% ..\src\rdi_dump\rdi_dump_main.c %compile_link% %out%rdi_dump.exe || exit /b 1
|
||||
if "%rdi_breakpad_from_pdb%"=="1" set didbuild=1 && %compile% ..\src\rdi_breakpad_from_pdb\rdi_breakpad_from_pdb_main.c %compile_link% %out%rdi_breakpad_from_pdb.exe || exit /b 1
|
||||
if "%tester%"=="1" set didbuild=1 && %compile% ..\src\tester\tester_main.c %compile_link% %out%tester.exe || exit /b 1
|
||||
|
||||
@@ -3,5 +3,5 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
internal DW_SectionArray dw_sections_from_coff_section_table(Arena *arena, String8 raw_image, U64 string_table_off, U64 section_count, COFF_SectionHeader *sections);
|
||||
internal DW_Input dw_input_from_coff_section_table(Arena *arena, String8 raw_image, U64 string_table_off, U64 section_count, COFF_SectionHeader *sections);
|
||||
|
||||
|
||||
+11
-12
@@ -1,15 +1,15 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal DW_SectionArray
|
||||
dw_sections_from_coff_section_table(Arena *arena,
|
||||
String8 raw_image,
|
||||
U64 string_table_off,
|
||||
U64 section_count,
|
||||
COFF_SectionHeader *sections)
|
||||
internal DW_Input
|
||||
dw_input_from_coff_section_table(Arena *arena,
|
||||
String8 raw_image,
|
||||
U64 string_table_off,
|
||||
U64 section_count,
|
||||
COFF_SectionHeader *sections)
|
||||
{
|
||||
DW_SectionArray result = {0};
|
||||
B32 sect_status[ArrayCount(result.v)] = {0};
|
||||
DW_Input input = {0};
|
||||
B32 sect_status[ArrayCount(input.sec)] = {0};
|
||||
|
||||
for (U64 i = 0; i < section_count; ++i) {
|
||||
COFF_SectionHeader *header = §ions[i];
|
||||
@@ -18,7 +18,7 @@ dw_sections_from_coff_section_table(Arena *arena,
|
||||
|
||||
DW_SectionKind s = DW_Section_Null;
|
||||
B32 is_dwo = 0;
|
||||
#define X(_K,_L,_M,_W) \
|
||||
#define X(_K,_L,_M,_W) \
|
||||
if (str8_match_lit(_L, name, 0)) { s = DW_Section_##_K; } \
|
||||
if (str8_match_lit(_M, name, 0)) { s = DW_Section_##_K; } \
|
||||
if (str8_match_lit(_W, name, 0)) { s = DW_Section_##_K; is_dwo = 1; }
|
||||
@@ -30,16 +30,15 @@ dw_sections_from_coff_section_table(Arena *arena,
|
||||
Assert(!"too many debug sections with identical name, picking first");
|
||||
} else {
|
||||
sect_status[s] = 1;
|
||||
DW_Section *d = &result.v[s];
|
||||
DW_Section *d = &input.sec[s];
|
||||
d->name = push_str8_copy(arena, name);
|
||||
d->data = str8_substr(raw_image, raw_data_range);
|
||||
d->mode = dim_1u64(raw_data_range) > max_U32 ? DW_Mode_64Bit : DW_Mode_32Bit;
|
||||
d->is_dwo = is_dwo;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return input;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal DW_Input
|
||||
dw_input_from_elf_section_table(Arena *arena, String8 raw_image, ELF_BinInfo *bin)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
|
||||
DW_Input result = {0};
|
||||
B32 sect_status[ArrayCount(result.sec)] = {0};
|
||||
|
||||
ELF_Shdr64Array sections = elf_shdr64_array_from_bin(scratch.arena, raw_image, &bin->hdr);
|
||||
String8 sh_names = str8_substr(raw_image, bin->sh_name_range);
|
||||
|
||||
for (U64 sect_idx = 1; sect_idx < sections.count; ++sect_idx) {
|
||||
ELF_Shdr64 *shdr = §ions.v[sect_idx];
|
||||
|
||||
// skip BSS sections
|
||||
if (shdr->sh_type != ELF_SectionCode_ProgBits) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String8 name = {0};
|
||||
str8_deserial_read_cstr(sh_names, shdr->sh_name, &name);
|
||||
|
||||
DW_SectionKind s = DW_Section_Null;
|
||||
B32 is_dwo = 0;
|
||||
#define X(_K,_L,_M,_W) \
|
||||
if (str8_match_lit(_L, name, 0)) { s = DW_Section_##_K; } \
|
||||
if (str8_match_lit(_M, name, 0)) { s = DW_Section_##_K; } \
|
||||
if (str8_match_lit(_W, name, 0)) { s = DW_Section_##_K; is_dwo = 1; }
|
||||
DW_SectionKind_XList(X)
|
||||
#undef X
|
||||
|
||||
if (s != DW_Section_Null) {
|
||||
if (sect_status[s]) {
|
||||
Assert(!"too many debug sections with identical name, picking first");
|
||||
} else {
|
||||
Rng1U64 raw_data_range = rng_1u64(shdr->sh_offset, shdr->sh_offset + shdr->sh_size);
|
||||
String8 data = str8_substr(raw_image, raw_data_range);
|
||||
|
||||
// ELF was compiled with compressed debug info
|
||||
if (shdr->sh_flags & ELF_Shf_Compressed) {
|
||||
String8 comp_data_with_header = data;
|
||||
|
||||
// read header
|
||||
ELF_Chdr64 chdr64 = {0};
|
||||
U64 chdr_size = 0;
|
||||
if (ELF_HdrIs64Bit(bin->hdr.e_ident)) {
|
||||
chdr_size = str8_deserial_read_struct(comp_data_with_header, 0, &chdr64);
|
||||
if (chdr_size != sizeof(chdr64)) {
|
||||
Assert(!"not enough bytes to read header");
|
||||
}
|
||||
} else if (ELF_HdrIs32Bit(bin->hdr.e_ident)) {
|
||||
ELF_Chdr32 chdr32 = {0};
|
||||
chdr_size = str8_deserial_read_struct(comp_data_with_header, 0, &chdr32);
|
||||
if (chdr_size == sizeof(chdr32)) {
|
||||
chdr64 = elf_chdr64_from_chdr32(chdr32);
|
||||
}
|
||||
}
|
||||
|
||||
AssertAlways(IsPow2(chdr64.ch_addr_align));
|
||||
|
||||
// skip header
|
||||
String8 comp_data = str8_skip(comp_data_with_header, chdr_size);
|
||||
|
||||
// push buffer for the decompressor
|
||||
U8 *decomp_buffer = push_array_no_zero_aligned(arena, U8, chdr64.ch_size, chdr64.ch_addr_align);
|
||||
U64 actual_decomp_size = 0;
|
||||
|
||||
// decompress
|
||||
switch (chdr64.ch_type) {
|
||||
case ELF_CompressType_None: {
|
||||
AssertAlways(!"unexpected compression type");
|
||||
} break;
|
||||
case ELF_CompressType_ZLib: {
|
||||
actual_decomp_size = zsinflate(decomp_buffer, chdr64.ch_size, comp_data.str, comp_data.size);
|
||||
} break;
|
||||
case ELF_CompressType_ZStd: {
|
||||
// TODO: zstd lib
|
||||
NotImplemented;
|
||||
} break;
|
||||
default: InvalidPath; break;
|
||||
}
|
||||
|
||||
// TODO: error handling
|
||||
AssertAlways(actual_decomp_size == chdr64.ch_size);
|
||||
|
||||
// set decompressed section data
|
||||
data = str8(decomp_buffer, actual_decomp_size);
|
||||
}
|
||||
|
||||
sect_status[s] = 1;
|
||||
DW_Section *d = &result.sec[s];
|
||||
d->name = push_str8_copy(arena, name);
|
||||
d->data = data;
|
||||
d->is_dwo = is_dwo;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef DWARF_ELF_H
|
||||
#define DWARF_ELF_H
|
||||
|
||||
internal DW_Input dw_input_from_elf_section_table(Arena *arena, String8 raw_image, ELF_BinInfo *bin);
|
||||
|
||||
#endif // DWARF_ELF_H
|
||||
|
||||
|
||||
+2718
-1991
File diff suppressed because it is too large
Load Diff
+305
-346
@@ -4,38 +4,49 @@
|
||||
#ifndef DWARF_PARSE_H
|
||||
#define DWARF_PARSE_H
|
||||
|
||||
// NOTE(rjf): Some rules about the spaces of offsets and ranges:
|
||||
//
|
||||
// - Every stored/passed offset is relative to the base of its section.
|
||||
// - Every stored/passed range has endpoints relative to the base of their section.
|
||||
// - Upon calling a syms_based_range_* function, these offsets need to be
|
||||
// converted into range-relative.
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Constants
|
||||
|
||||
#define DWARF_VOID_TYPE_ID 0xffffffffffffffffull
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Files + External Debug References
|
||||
|
||||
typedef struct DW_ExtDebugRef DW_ExtDebugRef;
|
||||
struct DW_ExtDebugRef
|
||||
typedef struct DW_Section
|
||||
{
|
||||
// NOTE(rjf): .dwo => an external DWARF V5 .dwo file
|
||||
String8 dwo_path;
|
||||
U64 dwo_id;
|
||||
};
|
||||
String8 name;
|
||||
String8 data;
|
||||
B32 is_dwo;
|
||||
} DW_Section;
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Abbrev Table
|
||||
typedef struct DW_Input
|
||||
{
|
||||
DW_Section sec[DW_Section_Count];
|
||||
DW_Section sup[DW_Section_Count];
|
||||
} DW_Input;
|
||||
|
||||
typedef struct DW_AbbrevTableEntry DW_AbbrevTableEntry;
|
||||
struct DW_AbbrevTableEntry
|
||||
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
|
||||
@@ -44,62 +55,6 @@ struct DW_AbbrevTable
|
||||
DW_AbbrevTableEntry *entries;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ Sections
|
||||
|
||||
typedef struct DW_Section DW_Section;
|
||||
struct DW_Section
|
||||
{
|
||||
String8 name;
|
||||
String8 data;
|
||||
DW_Mode mode;
|
||||
B32 is_dwo;
|
||||
};
|
||||
|
||||
typedef struct DW_SectionArray DW_SectionArray;
|
||||
struct DW_SectionArray
|
||||
{
|
||||
DW_Section v[DW_Section_Count];
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Line Info
|
||||
|
||||
typedef struct DW_LineFile DW_LineFile;
|
||||
struct DW_LineFile
|
||||
{
|
||||
String8 file_name;
|
||||
U64 dir_idx;
|
||||
U64 modify_time;
|
||||
U64 md5_digest[2];
|
||||
U64 file_size;
|
||||
};
|
||||
|
||||
typedef struct DW_LineVMFileNode DW_LineVMFileNode;
|
||||
struct DW_LineVMFileNode
|
||||
{
|
||||
DW_LineVMFileNode *next;
|
||||
DW_LineFile file;
|
||||
};
|
||||
|
||||
typedef struct DW_LineVMFileList DW_LineVMFileList;
|
||||
struct DW_LineVMFileList
|
||||
{
|
||||
U64 node_count;
|
||||
DW_LineVMFileNode *first;
|
||||
DW_LineVMFileNode *last;
|
||||
};
|
||||
|
||||
typedef struct DW_LineVMFileArray DW_LineVMFileArray;
|
||||
struct DW_LineVMFileArray
|
||||
{
|
||||
U64 count;
|
||||
DW_LineFile *v;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Abbrevs
|
||||
|
||||
typedef enum DW_AbbrevKind
|
||||
{
|
||||
DW_Abbrev_Null,
|
||||
@@ -108,215 +63,169 @@ typedef enum DW_AbbrevKind
|
||||
DW_Abbrev_AttribSequenceEnd,
|
||||
DW_Abbrev_DIEBegin,
|
||||
DW_Abbrev_DIEEnd,
|
||||
}
|
||||
DW_AbbrevKind;
|
||||
} DW_AbbrevKind;
|
||||
|
||||
typedef U32 DW_AbbrevFlags;
|
||||
enum{
|
||||
DW_AbbrevFlag_HasImplicitConst = (1<<0),
|
||||
DW_AbbrevFlag_HasChildren = (1<<1),
|
||||
enum
|
||||
{
|
||||
DW_AbbrevFlag_HasImplicitConst = (1 << 0),
|
||||
DW_AbbrevFlag_HasChildren = (1 << 1),
|
||||
};
|
||||
|
||||
typedef struct DW_Abbrev DW_Abbrev;
|
||||
struct DW_Abbrev
|
||||
typedef struct DW_Abbrev
|
||||
{
|
||||
DW_AbbrevKind kind;
|
||||
Rng1U64 abbrev_range;
|
||||
U64 sub_kind;
|
||||
U64 id;
|
||||
U64 const_value;
|
||||
DW_AbbrevFlags flags;
|
||||
};
|
||||
} DW_Abbrev;
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Attribs
|
||||
|
||||
typedef struct DW_AttribValueResolveParams DW_AttribValueResolveParams;
|
||||
struct DW_AttribValueResolveParams
|
||||
typedef union DW_Form
|
||||
{
|
||||
DW_Version version;
|
||||
DW_Language language;
|
||||
U64 addr_size; // NOTE(rjf): size in bytes of containing compilation unit's addresses
|
||||
U64 containing_unit_info_off; // NOTE(rjf): containing compilation unit's offset into the .debug_info section
|
||||
U64 debug_addrs_base; // NOTE(rjf): containing compilation unit's offset into the .debug_addrs section (DWARF V5 ONLY)
|
||||
U64 debug_rnglists_base; // NOTE(rjf): containing compilation unit's offset into the .debug_rnglists section (DWARF V5 ONLY)
|
||||
U64 debug_str_offs_base; // NOTE(rjf): containing compilation unit's offset into the .debug_str_offsets section (DWARF V5 ONLY)
|
||||
U64 debug_loclists_base; // NOTE(rjf): containing compilation unit's offset into the .debug_loclists section (DWARF V5 ONLY)
|
||||
};
|
||||
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_AttribValue DW_AttribValue;
|
||||
struct DW_AttribValue
|
||||
{
|
||||
DW_SectionKind section;
|
||||
U64 v[2];
|
||||
};
|
||||
|
||||
typedef struct DW_Attrib DW_Attrib;
|
||||
struct DW_Attrib
|
||||
typedef struct DW_Attrib
|
||||
{
|
||||
U64 info_off;
|
||||
U64 abbrev_off;
|
||||
U64 abbrev_id;
|
||||
DW_AttribKind attrib_kind;
|
||||
DW_FormKind form_kind;
|
||||
DW_AttribClass value_class;
|
||||
DW_AttribValue form_value;
|
||||
};
|
||||
DW_Form form;
|
||||
} DW_Attrib;
|
||||
|
||||
typedef struct DW_AttribArray DW_AttribArray;
|
||||
struct DW_AttribArray
|
||||
typedef struct DW_AttribNode
|
||||
{
|
||||
DW_Attrib *v;
|
||||
U64 count;
|
||||
};
|
||||
struct DW_AttribNode *next;
|
||||
DW_Attrib v;
|
||||
} DW_AttribNode;
|
||||
|
||||
typedef struct DW_AttribNode DW_AttribNode;
|
||||
struct DW_AttribNode
|
||||
{
|
||||
DW_AttribNode *next;
|
||||
DW_Attrib attrib;
|
||||
};
|
||||
|
||||
typedef struct DW_AttribList DW_AttribList;
|
||||
struct DW_AttribList
|
||||
typedef struct DW_AttribList
|
||||
{
|
||||
DW_AttribNode *first;
|
||||
DW_AttribNode *last;
|
||||
U64 count;
|
||||
};
|
||||
} DW_AttribList;
|
||||
|
||||
typedef struct DW_AttribListParseResult DW_AttribListParseResult;
|
||||
struct DW_AttribListParseResult
|
||||
typedef struct DW_Tag
|
||||
{
|
||||
DW_AttribList attribs;
|
||||
U64 max_info_off;
|
||||
U64 max_abbrev_off;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Compilation Units + Accelerators
|
||||
|
||||
typedef struct DW_CompRoot DW_CompRoot;
|
||||
struct DW_CompRoot
|
||||
{
|
||||
// NOTE(rjf): Header Data
|
||||
U64 size;
|
||||
DW_CompUnitKind kind;
|
||||
DW_Version version;
|
||||
U64 address_size;
|
||||
U64 abbrev_off;
|
||||
U64 info_off;
|
||||
Rng1U64 tags_info_range;
|
||||
DW_AbbrevTable abbrev_table;
|
||||
|
||||
// NOTE(rjf): [parsed from DWARF attributes] Offsets For More Info (DWARF V5 ONLY)
|
||||
U64 rnglist_base; // NOTE(rjf): Offset into the .debug_rnglists section where this comp unit's data is.
|
||||
U64 loclist_base; // NOTE(rjf): Offset into the .debug_loclists section where this comp unit's data is.
|
||||
U64 addrs_base; // NOTE(rjf): Offset into the .debug_addr section where this comp unit's data is.
|
||||
U64 stroffs_base; // NOTE(rjf): Offset into the .debug_str_offsets section where this comp unit's data is.
|
||||
|
||||
// NOTE(rjf): [parsed from DWARF attributes] General Info
|
||||
String8 name;
|
||||
String8 producer;
|
||||
String8 compile_dir;
|
||||
String8 external_dwo_name;
|
||||
U64 dwo_id;
|
||||
DW_Language language;
|
||||
U64 name_case;
|
||||
B32 use_utf8;
|
||||
U64 line_off;
|
||||
U64 low_pc;
|
||||
U64 high_pc;
|
||||
DW_AttribValue ranges_attrib_value;
|
||||
U64 base_addr;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Tags
|
||||
|
||||
typedef struct DW_Tag DW_Tag;
|
||||
struct DW_Tag
|
||||
{
|
||||
DW_Tag *next_sibling;
|
||||
DW_Tag *first_child;
|
||||
DW_Tag *last_child;
|
||||
DW_Tag *parent;
|
||||
Rng1U64 info_range;
|
||||
Rng1U64 abbrev_range;
|
||||
B32 has_children;
|
||||
U64 abbrev_id;
|
||||
DW_TagKind kind;
|
||||
U64 attribs_info_off;
|
||||
U64 attribs_abbrev_off;
|
||||
DW_AttribList attribs;
|
||||
};
|
||||
U64 info_off;
|
||||
} DW_Tag;
|
||||
|
||||
typedef U32 DW_TagStubFlags;
|
||||
enum
|
||||
typedef struct DW_TagNode
|
||||
{
|
||||
DW_TagStubFlag_HasObjectPointerArg = (1<<0),
|
||||
DW_TagStubFlag_HasLocation = (1<<1),
|
||||
DW_TagStubFlag_HasExternal = (1<<2),
|
||||
DW_TagStubFlag_HasSpecification = (1<<3),
|
||||
};
|
||||
DW_Tag tag;
|
||||
struct DW_TagNode *sibling;
|
||||
struct DW_TagNode *first_child;
|
||||
struct DW_TagNode *last_child;
|
||||
} DW_TagNode;
|
||||
|
||||
typedef struct DW_TagStub DW_TagStub;
|
||||
struct DW_TagStub
|
||||
typedef struct DW_Loc
|
||||
{
|
||||
U64 info_off;
|
||||
DW_TagKind kind;
|
||||
DW_TagStubFlags flags;
|
||||
U64 children_info_off;
|
||||
U64 attribs_info_off;
|
||||
U64 attribs_abbrev_off;
|
||||
|
||||
// NOTE(rjf): DW_Attrib_Specification is tacked onto definitions that
|
||||
// are filling out more info about a "prototype". That attribute is a reference
|
||||
// that points back at the declaration tag. The declaration tag has the
|
||||
// DW_Attrib_Declaration attribute, which is sort of like the reverse
|
||||
// of that, except there's no reference. So what we're doing here is just storing
|
||||
// a reference on both, that point back to each other, so it's always easy to
|
||||
// get from decl => spec, or from spec => decl.
|
||||
//SYMS_SymbolID ref;
|
||||
|
||||
// NOTE(rjf): DW_Attrib_AbstractOrigin is tacked onto some definitions
|
||||
// that are used to specify information more specific to inlining, while wanting
|
||||
// to refer to an "abstract" function DIE, that is not specific to any inline
|
||||
// sites. The DWARF generator will not duplicate information across these, so
|
||||
// we will occasionally need to look at an abstract origin to get abstract
|
||||
// information, like name/linkage-name/etc.
|
||||
//SYMS_SymbolID abstract_origin;
|
||||
|
||||
U64 _unused_;
|
||||
};
|
||||
Rng1U64 range;
|
||||
String8 expr;
|
||||
} DW_Loc;
|
||||
|
||||
typedef struct DW_TagStubNode DW_TagStubNode;
|
||||
struct DW_TagStubNode
|
||||
typedef struct DW_LocNode
|
||||
{
|
||||
DW_TagStubNode *next;
|
||||
DW_TagStub stub;
|
||||
};
|
||||
DW_Loc v;
|
||||
struct DW_LocNode *next;
|
||||
} DW_LocNode;
|
||||
|
||||
typedef struct DW_TagStubList DW_TagStubList;
|
||||
struct DW_TagStubList
|
||||
typedef struct DW_LocList
|
||||
{
|
||||
DW_TagStubNode *first;
|
||||
DW_TagStubNode *last;
|
||||
U64 count;
|
||||
};
|
||||
U64 count;
|
||||
DW_LocNode *first;
|
||||
DW_LocNode *last;
|
||||
} DW_LocList;
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Line Info VM Types
|
||||
|
||||
typedef struct DW_LineVMHeader DW_LineVMHeader;
|
||||
struct DW_LineVMHeader
|
||||
typedef struct DW_CompUnit
|
||||
{
|
||||
U64 unit_length;
|
||||
U64 unit_opl;
|
||||
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;
|
||||
U64 program_off;
|
||||
U8 min_inst_len;
|
||||
U8 max_ops_for_inst;
|
||||
U8 default_is_stmt;
|
||||
@@ -325,12 +234,11 @@ struct DW_LineVMHeader
|
||||
U8 opcode_base;
|
||||
U64 num_opcode_lens;
|
||||
U8 *opcode_lens;
|
||||
String8Array dir_table;
|
||||
DW_LineVMFileArray dir_table;
|
||||
DW_LineVMFileArray file_table;
|
||||
};
|
||||
} DW_LineVMHeader;
|
||||
|
||||
typedef struct DW_LineVMState DW_LineVMState;
|
||||
struct DW_LineVMState
|
||||
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.
|
||||
@@ -351,144 +259,195 @@ struct DW_LineVMState
|
||||
// prepare stack for a function.
|
||||
B32 prologue_end;
|
||||
|
||||
B32 epilogue_begin; // NOTE(nick): Indicates that "address" points to section where function exits and unwinds stack.
|
||||
U64 isa; // NOTE(nick): Instruction set that is used.
|
||||
U64 discriminator; // NOTE(nick): Arbitrary id that indicates to which block these instructions belong.
|
||||
B32 end_sequence; // NOTE(nick): Indicates that "address" points to the first instruction in the instruction block that follows.
|
||||
|
||||
// NOTE(rjf): it looks like LTO might sometimes zero out high PC and low PCs, causing a
|
||||
// swath of line info to map to a range starting at 0. This causes overlapping ranges
|
||||
// which we do not want to report. So this B32 will turn on emission.
|
||||
B32 busted_seq;
|
||||
};
|
||||
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 DW_Line;
|
||||
struct DW_Line
|
||||
typedef struct DW_Line
|
||||
{
|
||||
U64 file_index;
|
||||
U32 line;
|
||||
U32 column;
|
||||
U64 voff;
|
||||
};
|
||||
U64 address;
|
||||
} DW_Line;
|
||||
|
||||
typedef struct DW_LineNode DW_LineNode;
|
||||
struct DW_LineNode
|
||||
typedef struct DW_LineNode
|
||||
{
|
||||
DW_LineNode *next;
|
||||
DW_Line v;
|
||||
};
|
||||
struct DW_LineNode *next;
|
||||
DW_Line v;
|
||||
} DW_LineNode;
|
||||
|
||||
typedef struct DW_LineSeqNode DW_LineSeqNode;
|
||||
struct DW_LineSeqNode
|
||||
typedef struct DW_LineSeqNode
|
||||
{
|
||||
DW_LineSeqNode *next;
|
||||
U64 count;
|
||||
DW_LineNode *first;
|
||||
DW_LineNode *last;
|
||||
};
|
||||
struct DW_LineSeqNode *next;
|
||||
U64 count;
|
||||
DW_LineNode *first;
|
||||
DW_LineNode *last;
|
||||
} DW_LineSeqNode;
|
||||
|
||||
typedef struct DW_LineTableParseResult DW_LineTableParseResult;
|
||||
struct DW_LineTableParseResult
|
||||
typedef struct DW_LineTableParseResult
|
||||
{
|
||||
DW_LineVMHeader vm_header;
|
||||
U64 seq_count;
|
||||
DW_LineSeqNode *first_seq;
|
||||
DW_LineSeqNode *last_seq;
|
||||
};
|
||||
} DW_LineTableParseResult;
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: .debug_pubnames and .debug_pubtypes
|
||||
// .debug_pubnames and .debug_pubtypes
|
||||
|
||||
typedef struct DW_PubStringsBucket DW_PubStringsBucket;
|
||||
struct DW_PubStringsBucket
|
||||
typedef struct DW_PubStringsBucket
|
||||
{
|
||||
DW_PubStringsBucket *next;
|
||||
String8 string;
|
||||
U64 info_off;
|
||||
U64 cu_info_off;
|
||||
};
|
||||
struct DW_PubStringsBucket *next;
|
||||
String8 string;
|
||||
U64 info_off;
|
||||
U64 cu_info_off;
|
||||
} DW_PubStringsBucket;
|
||||
|
||||
typedef struct DW_PubStringsTable DW_PubStringsTable;
|
||||
struct DW_PubStringsTable
|
||||
typedef struct DW_PubStringsTable
|
||||
{
|
||||
U64 size;
|
||||
U64 size;
|
||||
DW_PubStringsBucket **buckets;
|
||||
};
|
||||
} DW_PubStringsTable;
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Helpers
|
||||
typedef struct DW_Reference
|
||||
{
|
||||
DW_CompUnit *cu;
|
||||
U64 info_off;
|
||||
} DW_Reference;
|
||||
|
||||
// hasher
|
||||
|
||||
internal U64 dw_hash_from_string(String8 string);
|
||||
|
||||
////////////////////////////////
|
||||
//~ Specific Based Range Helpers
|
||||
// deserial helpers
|
||||
|
||||
#define dw_based_range_read_struct(base, range, offset, out) dw_based_range_read(base, range, offset, sizeof(*out), out)
|
||||
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 U64 dw_based_range_read(void *base, Rng1U64 range, U64 offset, U64 size, void *out);
|
||||
internal String8 dw_based_range_read_string(void *base, Rng1U64 range, U64 offset);
|
||||
internal void* dw_based_range_ptr(void *base, Rng1U64 range, U64 offset);
|
||||
internal void* dw_based_range_ptr_size(void *base, Rng1U64 range, U64 offset, U64 size);
|
||||
internal U64 dw_based_range_read_uleb128(void *base, Rng1U64 range, U64 offset, U64 *out_value);
|
||||
internal U64 dw_based_range_read_sleb128(void *base, Rng1U64 range, U64 offset, S64 *out_value);
|
||||
internal U64 dw_based_range_read_length(void *base, Rng1U64 range, U64 offset, U64 *out_value);
|
||||
internal U64 dw_based_range_read_abbrev_tag(void *base, Rng1U64 range, U64 offset, DW_Abbrev *out_abbrev);
|
||||
internal U64 dw_based_range_read_abbrev_attrib_info(void *base, Rng1U64 range, U64 offset, DW_Abbrev *out_abbrev);
|
||||
internal U64 dw_based_range_read_attrib_form_value(void *base, Rng1U64 range, U64 offset, DW_Mode mode, U64 address_size, DW_FormKind form_kind, U64 implicit_const, DW_AttribValue *form_value_out);
|
||||
internal Rng1U64List dw_unit_ranges_from_data(Arena *arena, String8 data);
|
||||
|
||||
internal DW_Mode dw_mode_from_sec(DW_SectionArray *sections, DW_SectionKind kind);
|
||||
internal B32 dw_sec_is_present(DW_SectionArray *sections, DW_SectionKind kind);
|
||||
internal void* dw_base_from_sec(DW_SectionArray *sections, DW_SectionKind kind);
|
||||
internal Rng1U64 dw_range_from_sec(DW_SectionArray *sections, DW_SectionKind kind);
|
||||
// list units
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Abbrev Table
|
||||
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_AbbrevTable dw_make_abbrev_table(Arena *arena, DW_SectionArray *sections, U64 start_abbrev_off);
|
||||
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);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Miscellaneous DWARF Section Parsing
|
||||
// form and tag
|
||||
|
||||
//- rjf: .debug_ranges (DWARF V4)
|
||||
internal Rng1U64List dw_v4_range_list_from_range_offset(Arena *arena, DW_SectionArray *sections, U64 addr_size, U64 comp_unit_base_addr, U64 range_off);
|
||||
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);
|
||||
|
||||
//- rjf: .debug_pubtypes + .debug_pubnames (DWARF V4)
|
||||
internal DW_PubStringsTable dw_v4_pub_strings_table_from_section_kind(Arena *arena, DW_SectionArray *sections, DW_SectionKind section_kind);
|
||||
// attrib interp
|
||||
|
||||
//- rjf: .debug_str_offsets (DWARF V5)
|
||||
internal U64 dw_v5_offset_from_offs_section_base_index(DW_SectionArray *sections, DW_SectionKind section, U64 base, U64 index);
|
||||
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);
|
||||
|
||||
//- rjf: .debug_addr (DWARF V5)
|
||||
internal U64 dw_v5_addr_from_addrs_section_base_index(DW_SectionArray *sections, DW_SectionKind section, U64 base, U64 index);
|
||||
internal String8 dw_exprloc_from_attrib_ptr (DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
||||
internal U128 dw_const_u128_from_attrib_ptr(DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
||||
internal U64 dw_const_u64_from_attrib_ptr (DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
||||
internal U32 dw_const_u32_from_attrib_ptr (DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
||||
internal S64 dw_const_s64_from_attrib_ptr (DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
||||
internal S32 dw_const_s32_from_attrib_ptr (DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
||||
internal B32 dw_flag_from_attrib_ptr (DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
||||
internal U64 dw_address_from_attrib_ptr (DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
||||
internal String8 dw_block_from_attrib_ptr (DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
||||
internal String8 dw_string_from_attrib_ptr (DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
||||
internal String8 dw_line_ptr_from_attrib_ptr (DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
||||
internal DW_LineFile * dw_file_from_attrib_ptr (DW_CompUnit *cu, DW_LineVMHeader *line_vm, DW_Attrib *attrib);
|
||||
internal DW_Reference dw_ref_from_attrib_ptr (DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
||||
internal DW_LocList dw_loclist_from_attrib_ptr (Arena *arena, DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
||||
internal Rng1U64List dw_rnglist_from_attrib_ptr (Arena *arena, DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
||||
|
||||
//- rjf: .debug_rnglists parsing (DWARF V5)
|
||||
internal U64 dw_v5_sec_offset_from_rnglist_or_loclist_section_base_index(DW_SectionArray *sections, DW_SectionKind section_kind, U64 base, U64 index);
|
||||
internal Rng1U64List dw_v5_range_list_from_rnglist_offset(Arena *arena, DW_SectionArray *sections, DW_SectionKind section, U64 addr_size, U64 addr_section_base, U64 offset);
|
||||
internal String8 dw_exprloc_from_attrib (DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
||||
internal U128 dw_const_u128_from_attrib(DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
||||
internal U64 dw_const_u64_from_attrib (DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
||||
internal U32 dw_const_u32_from_attrib (DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
||||
internal B32 dw_flag_from_attrib (DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
||||
internal U64 dw_address_from_attrib (DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
||||
internal String8 dw_block_from_attrib (DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
||||
internal String8 dw_string_from_attrib (DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
||||
internal String8 dw_line_ptr_from_attrib (DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
||||
internal String8 dw_line_ptr_from_attrib (DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
||||
internal DW_LineFile * dw_file_from_attrib (DW_Input *input, DW_CompUnit *cu, DW_LineVMHeader *line_vm, DW_Tag tag, DW_AttribKind kind);
|
||||
internal DW_Reference dw_ref_from_attrib (DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
||||
internal DW_LocList dw_loclist_from_attrib (Arena *arena, DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
||||
internal Rng1U64List dw_rnglist_from_attrib (Arena *arena, DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Attrib Value Parsing
|
||||
// compile unit
|
||||
|
||||
internal DW_AttribValueResolveParams dw_attrib_value_resolve_params_from_comp_root(DW_CompRoot *root);
|
||||
internal DW_AttribValue dw_attrib_value_from_form_value(DW_SectionArray *sections, DW_AttribValueResolveParams resolve_params, DW_FormKind form_kind, DW_AttribClass value_class, DW_AttribValue form_value);
|
||||
internal String8 dw_string_from_attrib_value(DW_SectionArray *sections, DW_AttribValue value);
|
||||
internal Rng1U64List dw_range_list_from_high_low_pc_and_ranges_attrib_value(Arena *arena, DW_SectionArray *sections, U64 address_size, U64 comp_unit_base_addr, U64 addr_section_base, U64 low_pc, U64 high_pc, DW_AttribValue ranges_value);
|
||||
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);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Tag Parsing
|
||||
// line info
|
||||
|
||||
internal DW_AttribListParseResult dw_parse_attrib_list_from_info_abbrev_offsets(Arena *arena, DW_SectionArray *sections, DW_Version ver, DW_Ext ext, DW_Language lang, U64 address_size, U64 info_off, U64 abbrev_off, B32 relaxed);
|
||||
internal DW_Tag* dw_tag_from_info_offset(Arena *arena, DW_SectionArray *sections, DW_AbbrevTable abbrev_table, DW_Version ver, DW_Ext ext, DW_Language lang, U64 address_size, U64 info_offset, B32 relaxed);
|
||||
internal DW_TagStub dw_stub_from_tag(DW_SectionArray *sections, DW_AttribValueResolveParams resolve_params, DW_Tag *tag);
|
||||
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);
|
||||
|
||||
//- rjf: line info
|
||||
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 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_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 DW_LineTableParseResult dw_parsed_line_table_from_comp_root(Arena *arena, DW_SectionArray *sections, DW_CompRoot *root);
|
||||
internal U64 dw_read_line_file(void *line_base, Rng1U64 line_rng, U64 line_off, DW_Mode mode, DW_SectionArray *sections, DW_AttribValueResolveParams resolve_params, U8 address_size, U64 format_count, Rng1U64 *formats, DW_LineFile *line_file_out);
|
||||
internal U64 dw_read_line_vm_header(Arena *arena, void *line_base, Rng1U64 line_rng, U64 line_off, DW_Mode mode, DW_SectionArray *sections, DW_AttribValueResolveParams resolve_params, String8 compile_dir, String8 unit_name, DW_LineVMHeader *header_out);
|
||||
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
|
||||
|
||||
|
||||
@@ -410,6 +410,8 @@ dw_unwind_parse_pointer_x64(void *frame_base, Rng1U64 frame_range, DW_EhPtrCtx *
|
||||
internal void
|
||||
dw_unwind_parse_cie_x64(void *base, Rng1U64 range, DW_EhPtrCtx *ptr_ctx, U64 off, DW_CIEUnpacked *cie_out)
|
||||
{
|
||||
NotImplemented;
|
||||
#if 0
|
||||
MemoryZeroStruct(cie_out);
|
||||
|
||||
// get version
|
||||
@@ -521,6 +523,7 @@ dw_unwind_parse_cie_x64(void *base, Rng1U64 range, DW_EhPtrCtx *ptr_ctx, U64 off
|
||||
cie_out->cfi_range.min = cfi_off;
|
||||
cie_out->cfi_range.max = cfi_off + cfi_size;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
internal void
|
||||
|
||||
@@ -187,6 +187,13 @@ hash_table_search_u64(HashTable *ht, U64 key_u64)
|
||||
return 0;
|
||||
}
|
||||
|
||||
internal void *
|
||||
hash_table_search_u64_raw(HashTable *ht, U64 key_u64)
|
||||
{
|
||||
KeyValuePair *kv = hash_table_search_u64(ht, key_u64);
|
||||
return kv ? kv->value_raw : 0;
|
||||
}
|
||||
|
||||
internal KeyValuePair *
|
||||
hash_table_search_path(HashTable *ht, String8 path)
|
||||
{
|
||||
|
||||
+1882
-859
File diff suppressed because it is too large
Load Diff
@@ -1,50 +1,69 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef RDI_FROM_DWARF_H
|
||||
#define RDI_FROM_DWARF_H
|
||||
#pragma once
|
||||
|
||||
typedef U64 D2R_ConvertFlags;
|
||||
enum
|
||||
{
|
||||
#define X(t,n,k) D2R_ConvertFlag_##t = (1ull << RDI_SectionKind_##t),
|
||||
RDI_SectionKind_XList
|
||||
#undef X
|
||||
D2R_ConvertFlag_StrictParse,
|
||||
};
|
||||
|
||||
typedef struct D2R_User2Convert
|
||||
{
|
||||
String8 input_exe_name;
|
||||
String8 input_exe_data;
|
||||
String8 input_debug_name;
|
||||
String8 input_debug_data;
|
||||
String8 output_name;
|
||||
D2R_ConvertFlags flags;
|
||||
String8List errors;
|
||||
} D2R_User2Convert;
|
||||
|
||||
typedef struct D2R_TypeTable
|
||||
{
|
||||
HashTable *ht;
|
||||
RDIM_TypeChunkList *types;
|
||||
U64 type_chunk_cap;
|
||||
RDIM_Type *void_type;
|
||||
RDIM_Type *varg_type;
|
||||
} D2R_TypeTable;
|
||||
|
||||
typedef struct D2R_TagNode
|
||||
{
|
||||
struct D2R_TagNode *next;
|
||||
DW_TagNode *cur_node;
|
||||
RDIM_Type *type;
|
||||
RDIM_Scope *scope;
|
||||
} D2R_TagNode;
|
||||
|
||||
typedef struct D2R_CompUnitContribMap
|
||||
{
|
||||
U64 count;
|
||||
U64 *info_off_arr;
|
||||
RDIM_Rng1U64List *voff_range_arr;
|
||||
} D2R_CompUnitContribMap;
|
||||
|
||||
////////////////////////////////
|
||||
//~ Program Parameters Type
|
||||
// Command Line -> Conversion Inputs
|
||||
|
||||
typedef struct DWARFCONV_Params{
|
||||
String8 input_elf_name;
|
||||
String8 input_elf_data;
|
||||
|
||||
String8 output_name;
|
||||
|
||||
U64 unit_idx_min;
|
||||
U64 unit_idx_max;
|
||||
|
||||
struct{
|
||||
B8 input;
|
||||
} hide_errors;
|
||||
|
||||
B8 dump;
|
||||
B8 dump__first;
|
||||
B8 dump_header;
|
||||
B8 dump_sections;
|
||||
B8 dump_segments;
|
||||
B8 dump_symtab;
|
||||
B8 dump_dynsym;
|
||||
B8 dump_debug_sections;
|
||||
B8 dump_debug_info;
|
||||
B8 dump_debug_abbrev;
|
||||
B8 dump_debug_pubnames;
|
||||
B8 dump_debug_pubtypes;
|
||||
B8 dump_debug_names;
|
||||
B8 dump_debug_aranges;
|
||||
B8 dump_debug_addr;
|
||||
B8 dump__last;
|
||||
|
||||
String8List errors;
|
||||
} DWARFCONV_Params;
|
||||
internal D2R_User2Convert * d2r_user2convert_from_cmdln(Arena *arena, CmdLine *cmdline);
|
||||
|
||||
////////////////////////////////
|
||||
//~ Program Parameters Parser
|
||||
// Top-Level Conversion Entry Point
|
||||
|
||||
static DWARFCONV_Params *dwarf_convert_params_from_cmd_line(Arena *arena, CmdLine *cmdline);
|
||||
internal RDIM_BakeParams * d2r_convert (Arena *arena, D2R_User2Convert *in);
|
||||
internal RDIM_BakeResults d2r_bake (RDIM_HelpState *state, RDIM_BakeParams *in);
|
||||
internal RDIM_SerializedSectionBundle d2r_compress(Arena *arena, RDIM_SerializedSectionBundle in);
|
||||
|
||||
////////////////////////////////
|
||||
// Enum Conversion
|
||||
|
||||
internal RDI_Language rdi_language_from_dw_language(DW_Language v);
|
||||
internal RDI_RegCodeX86 rdi_reg_from_dw_reg_x86(DW_RegX86 v);
|
||||
internal B32 rdi_reg_from_dw_reg_x64(DW_RegX64 v, RDI_RegCodeX64 *code_out, U64 *off_out, U64 *size_out);
|
||||
internal B32 rdi_reg_from_dw_reg(Arch arch, DW_Reg v, RDI_RegCode *code_out, U64 *off_out, U64 *size_out);
|
||||
|
||||
#endif //RDI_FROM_DWARF_H
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#define BUILD_TITLE "Epic Games Tools (R) DWARF Converter"
|
||||
#define BUILD_CONSOLE_INTERFACE 1
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
#include "third_party/rad_lzb_simple/rad_lzb_simple.h"
|
||||
#include "third_party/rad_lzb_simple/rad_lzb_simple.c"
|
||||
#include "third_party/xxHash/xxhash.c"
|
||||
#include "third_party/xxHash/xxhash.h"
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
#include "lib_rdi_format/rdi_format.h"
|
||||
#include "lib_rdi_format/rdi_format.c"
|
||||
#include "lib_rdi_format/rdi_format_parse.h"
|
||||
#include "lib_rdi_format/rdi_format_parse.c"
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
#include "base/base_inc.h"
|
||||
#include "os/os_inc.h"
|
||||
#include "async/async.h"
|
||||
#include "rdi_make/rdi_make_local.h"
|
||||
#include "rdi_make/rdi_make_help.h"
|
||||
#include "linker/path_ext/path.h"
|
||||
#include "linker/hash_table.h"
|
||||
#include "coff/coff.h"
|
||||
#include "coff/coff_parse.h"
|
||||
#include "dwarf/dwarf.h"
|
||||
#include "dwarf/dwarf_parse.h"
|
||||
#include "dwarf/dwarf_coff.h"
|
||||
#include "pe/pe.h"
|
||||
#include "linker/rdi/rdi_coff.h"
|
||||
#include "rdi_from_dwarf/rdi_from_dwarf.h"
|
||||
|
||||
#include "base/base_inc.c"
|
||||
#include "os/os_inc.c"
|
||||
#include "async/async.c"
|
||||
#include "coff/coff.c"
|
||||
#include "coff/coff_parse.c"
|
||||
#include "pe/pe.c"
|
||||
#include "rdi_make/rdi_make_local.c"
|
||||
#include "rdi_make/rdi_make_help.c"
|
||||
#include "linker/rdi/rdi_coff.c"
|
||||
#include "linker/path_ext/path.c"
|
||||
#include "linker/hash_table.c"
|
||||
#include "dwarf/dwarf.c"
|
||||
#include "dwarf/dwarf_parse.c"
|
||||
#include "dwarf/dwarf_coff.c"
|
||||
#include "rdi_from_dwarf/rdi_from_dwarf.c"
|
||||
|
||||
////////////////////////////////
|
||||
// Entry Point
|
||||
|
||||
internal void
|
||||
entry_point(CmdLine *cmdline)
|
||||
{
|
||||
// initialize state and unpack command line
|
||||
Arena *arena = arena_alloc();
|
||||
B32 do_help = (cmd_line_has_flag(cmdline, str8_lit("help")) ||
|
||||
cmd_line_has_flag(cmdline, str8_lit("h")) ||
|
||||
cmd_line_has_flag(cmdline, str8_lit("?")));
|
||||
|
||||
D2R_User2Convert *user2convert = d2r_user2convert_from_cmdln(arena, cmdline);
|
||||
|
||||
// display help
|
||||
if (do_help) {
|
||||
fprintf(stderr, "--- rdi_from_dwarf ------------------------------------------------------------\n\n");
|
||||
|
||||
fprintf(stderr, "This utility converts debug information from DWARF into the RAD Debug Info\n");
|
||||
fprintf(stderr, "format. The following arguments are accepted:\n\n");
|
||||
|
||||
fprintf(stderr, "--exe:<path> [optional] Specifies the path of the executable filefor which the\n");
|
||||
fprintf(stderr, " debug info was generated.\n");
|
||||
fprintf(stderr, "--debug:<path> Specifies the path of the .DEBUG debug info file to\n");
|
||||
fprintf(stderr, " convert.\n");
|
||||
fprintf(stderr, "--out:<path> Specifies the path at which the output will be written.\n\n");
|
||||
|
||||
if (!do_help) {
|
||||
for (String8Node *n = user2convert->errors.first; n != 0; n = n->next) {
|
||||
fprintf(stderr, "error(input): %.*s\n", str8_varg(n->string));
|
||||
}
|
||||
}
|
||||
|
||||
os_abort(0);
|
||||
}
|
||||
|
||||
RDIM_HelpState *rdim_help_state = rdim_help_init();
|
||||
|
||||
ProfBegin("convert");
|
||||
RDIM_BakeParams *convert2bake = d2r_convert(arena, user2convert);
|
||||
ProfEnd();
|
||||
|
||||
ProfBegin("bake");
|
||||
RDIM_BakeResults bake2srlz = d2r_bake(rdim_help_state, convert2bake);
|
||||
ProfEnd();
|
||||
|
||||
ProfBegin("serialize bake");
|
||||
RDIM_SerializedSectionBundle srlz2file = rdim_serialized_section_bundle_from_bake_results(&bake2srlz);
|
||||
ProfEnd();
|
||||
|
||||
RDIM_SerializedSectionBundle srlz2file_compressed = srlz2file;
|
||||
if (cmd_line_has_flag(cmdline, str8_lit("compress"))) {
|
||||
ProfBegin("compress");
|
||||
srlz2file_compressed = d2r_compress(arena, srlz2file);
|
||||
ProfEnd();
|
||||
}
|
||||
|
||||
ProfBegin("serialize blobs");
|
||||
String8List blobs = rdim_file_blobs_from_section_bundle(arena, &srlz2file_compressed);
|
||||
ProfEnd();
|
||||
|
||||
ProfBegin("write");
|
||||
if (!os_write_data_list_to_file_path(user2convert->output_name, blobs)) {
|
||||
fprintf(stderr, "error(ouptut): unable to write to %.*s\n", str8_varg(user2convert->output_name));
|
||||
}
|
||||
ProfEnd();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user