Files
raddebugger/src/rdi_from_dwarf/rdi_dwarf.c
T
2024-05-23 15:09:53 -07:00

1889 lines
55 KiB
C

// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ Dwarf Decode Helpers
static U64
dwarf_leb128_decode_U64(U8 *ptr, U8 *opl){
U64 r = 0;
switch (opl - ptr){
case 10: r |= ((U64)(ptr[9]&0x7F) << 63);
case 9: r |= ((U64)(ptr[8]&0x7F) << 56);
case 8: r |= ((U64)(ptr[7]&0x7F) << 49);
case 7: r |= ((U64)(ptr[6]&0x7F) << 42);
case 6: r |= ((U64)(ptr[5]&0x7F) << 35);
case 5: r |= ((U64)(ptr[4]&0x7F) << 28);
case 4: r |= ((U64)(ptr[3]&0x7F) << 21);
case 3: r |= ((U64)(ptr[2]&0x7F) << 14);
case 2: r |= ((U64)(ptr[1]&0x7F) << 7);
case 1: r |= ((U64)(ptr[0]&0x7F) );
case 0: default: break;
}
return(r);
}
static S64
dwarf_leb128_decode_S64(U8 *ptr, U8 *opl){
U64 u = dwarf_leb128_decode_U32(ptr, opl);
U64 s = (U64)(opl - ptr)*7;
B32 neg = ((u & (1llu << s)) != 0);
if (neg){
switch (opl - ptr){
case 9: u |= ~0x7FFFFFFFFFFFFFFFllu; break;
case 8: u |= ~0x00FFFFFFFFFFFFFFllu; break;
case 7: u |= ~ 0x01FFFFFFFFFFFFllu; break;
case 6: u |= ~ 0x03FFFFFFFFFFllu; break;
case 5: u |= ~ 0x07FFFFFFFFllu; break;
case 4: u |= ~ 0x0FFFFFFFllu; break;
case 3: u |= ~ 0x1FFFFFllu; break;
case 2: u |= ~ 0x3FFFllu; break;
case 1: u |= ~ 0x7Fllu; break;
}
}
S64 r = (S64)(u);
return(r);
}
static U32
dwarf_leb128_decode_U32(U8 *ptr, U8 *opl){
U32 r = 0;
switch (opl - ptr){
case 5: r |= ((U32)(ptr[4]&0x7F) << 28);
case 4: r |= ((U32)(ptr[3]&0x7F) << 21);
case 3: r |= ((U32)(ptr[2]&0x7F) << 14);
case 2: r |= ((U32)(ptr[1]&0x7F) << 7);
case 1: r |= ((U32)(ptr[0]&0x7F) );
case 0: default: break;
}
return(r);
}
////////////////////////////////
//~ Dwarf Parser Functions
static DWARF_Parsed*
dwarf_parsed_from_elf(Arena *arena, ELF_Parsed *elf){
DWARF_Parsed *result = 0;
if (elf != 0){
//- extract debug info
U32 debug_section_idx[DWARF_SectionCode_COUNT] = {0};
String8 debug_section_name[DWARF_SectionCode_COUNT] = {0};
String8 debug_data[DWARF_SectionCode_COUNT] = {0};
for (U64 i = 1; i < DWARF_SectionCode_COUNT; i += 1){
DWARF_SectionNameRow *row = dwarf_section_name_table + i;
U32 idx = 0;
for (U32 j = 0; idx == 0 && j < DWARF_SECTION_NAME_VARIANT_COUNT; j += 1){
idx = elf_section_idx_from_name(elf, row->name[j]);
}
debug_section_idx[i] = idx;
debug_section_name[i] = elf_section_name_from_idx(elf, idx);
debug_data[i] = elf_section_data_from_idx(elf, idx);
}
//- fill result
{
result = push_array(arena, DWARF_Parsed, 1);
result->elf = elf;
MemoryCopyArray(result->debug_section_idx, debug_section_idx);
MemoryCopyArray(result->debug_section_name, debug_section_name);
MemoryCopyArray(result->debug_data, debug_data);
}
}
return(result);
}
static DWARF_IndexParsed*
dwarf_index_from_data(Arena *arena, String8 data){
DWARF_IndexParsed *result = 0;
// TODO(allen):
return(result);
}
static DWARF_SupParsed*
dwarf_sup_from_data(Arena *arena, String8 data){
DWARF_SupParsed *result = 0;
// TODO(allen):
return(result);
}
static DWARF_InfoParsed*
dwarf_info_from_data(Arena *arena, String8 data){
// supported version numbers: 4,5
// empty unit list
DWARF_InfoUnit *first = 0;
DWARF_InfoUnit *last = 0;
U64 count = 0;
// whole section loop
U64 unit_idx = 0;
U8 *ptr = data.str;
U8 *opl = data.str + data.size;
for (;ptr < opl; unit_idx += 1){
// remember header offset
U64 hdr_off = (ptr - data.str);
// initial length
U8 *unit_opl = 0;
B32 is_64bit = 0;
dwarf__initial_length(data, &ptr, &unit_opl, &is_64bit);
// version
U8 version = MemoryConsume(U16, ptr, unit_opl);
// rest of header depends on version
U64 abbrev_off = 0;
U8 address_size = 0;
U8 unit_type = 0;
U64 unit_dwo_id = 0;
U64 unit_type_signature = 0;
U64 unit_type_offset = 0;
switch (version){
case 4:
{
// abbrev_off
if (is_64bit){
abbrev_off = MemoryConsume(U64, ptr, unit_opl);
}
else{
abbrev_off = MemoryConsume(U32, ptr, unit_opl);
}
// address_size
address_size = MemoryConsume(U8, ptr, unit_opl);
}break;
case 5:
{
// unit_type
unit_type = (DWARF_UnitType)MemoryConsume(U8, ptr, unit_opl);
// address_size
address_size = MemoryConsume(U8, ptr, unit_opl);
// abbrev_off
if (is_64bit){
abbrev_off = MemoryConsume(U64, ptr, unit_opl);
}
else{
abbrev_off = MemoryConsume(U32, ptr, unit_opl);
}
// rest of header depends on unit_type
switch (unit_type){
case DWARF_UnitType_skeleton: case DWARF_UnitType_split_compile:
{
unit_dwo_id = MemoryConsume(U64, ptr, unit_opl);
}break;
case DWARF_UnitType_type: case DWARF_UnitType_split_type:
{
unit_type_signature = MemoryConsume(U64, ptr, unit_opl);
if (is_64bit){
unit_type_offset = MemoryConsume(U64, ptr, unit_opl);
}
else{
unit_type_offset = MemoryConsume(U32, ptr, unit_opl);
}
}break;
}
}break;
}
// offset size
U8 offset_size = is_64bit?8:4;
// unit offsets
U64 base_off = (ptr - data.str);
U64 opl_off = (unit_opl - data.str);
// emit unit
DWARF_InfoUnit *unit = push_array(arena, DWARF_InfoUnit, 1);
SLLQueuePush(first, last, unit);
count += 1;
unit->hdr_off = hdr_off;
unit->base_off = base_off;
unit->opl_off = opl_off;
unit->offset_size = offset_size;
unit->version = version;
unit->unit_type = unit_type;
unit->address_size = address_size;
unit->abbrev_off = abbrev_off;
switch (unit_type){
case DWARF_UnitType_skeleton: case DWARF_UnitType_split_compile:
{
unit->dwo_id = unit_dwo_id;
}break;
case DWARF_UnitType_type: case DWARF_UnitType_split_type:
{
unit->type_signature = unit_type_signature;
unit->type_offset = unit_type_offset;
}break;
}
// advance to end of unit
ptr = unit_opl;
}
// fill result
DWARF_InfoParsed *result = push_array(arena, DWARF_InfoParsed, 1);
result->unit_first = first;
result->unit_last = last;
result->unit_count = count;
return(result);
}
static DWARF_PubNamesParsed*
dwarf_pubnames_from_data(Arena *arena, String8 data){
// supported version numbers: 2
// empty unit list
DWARF_PubNamesUnit *first = 0;
DWARF_PubNamesUnit *last = 0;
U64 count = 0;
// whole section loop
U64 unit_idx = 0;
U8 *ptr = data.str;
U8 *opl = data.str + data.size;
for (;ptr < opl; unit_idx += 1){
// remember header offset
U64 hdr_off = (ptr - data.str);
// initial length
U8 *unit_opl = 0;
B32 is_64bit = 0;
dwarf__initial_length(data, &ptr, &unit_opl, &is_64bit);
// version
U8 version = MemoryConsume(U16, ptr, unit_opl);
// info_off
U64 info_off = 0;
if (is_64bit){
info_off = MemoryConsume(U64, ptr, unit_opl);
}
else{
info_off = MemoryConsume(U32, ptr, unit_opl);
}
// info_length
U64 info_length = 0;
if (is_64bit){
info_length = MemoryConsume(U64, ptr, unit_opl);
}
else{
info_length = MemoryConsume(U32, ptr, unit_opl);
}
// offset size
U8 offset_size = is_64bit?8:4;
// unit offsets
U64 base_off = (ptr - data.str);
U64 opl_off = (unit_opl - data.str);
// emit unit
DWARF_PubNamesUnit *unit = push_array(arena, DWARF_PubNamesUnit, 1);
SLLQueuePush(first, last, unit);
count += 1;
unit->hdr_off = hdr_off;
unit->base_off = base_off;
unit->opl_off = opl_off;
unit->offset_size = offset_size;
unit->version = version;
unit->info_off = info_off;
unit->info_length = info_length;
// advance to end of unit
ptr = unit_opl;
}
// fill result
DWARF_PubNamesParsed *result = push_array(arena, DWARF_PubNamesParsed, 1);
result->unit_first = first;
result->unit_last = last;
result->unit_count = count;
return(result);
}
static DWARF_NamesParsed*
dwarf_names_from_data(Arena *arena, String8 data){
// supported version numbers: 5
// empty unit list
DWARF_NamesUnit *first = 0;
DWARF_NamesUnit *last = 0;
U64 count = 0;
// whole section loop
U64 unit_idx = 0;
U8 *ptr = data.str;
U8 *opl = data.str + data.size;
for (;ptr < opl; unit_idx += 1){
// remember header offset
U64 hdr_off = (ptr - data.str);
// initial length
U8 *unit_opl = 0;
B32 is_64bit = 0;
dwarf__initial_length(data, &ptr, &unit_opl, &is_64bit);
// version
U8 version = MemoryConsume(U16, ptr, unit_opl);
// *padding*
MemoryConsume(U16, ptr, unit_opl);
// comp_unit_count
U32 comp_unit_count = MemoryConsume(U32, ptr, unit_opl);
// local_type_unit_count
U32 local_type_unit_count = MemoryConsume(U32, ptr, unit_opl);
// foreign_type_unit_count
U32 foreign_type_unit_count = MemoryConsume(U32, ptr, unit_opl);
// bucket_count
U32 bucket_count = MemoryConsume(U32, ptr, unit_opl);
// name_count
U32 name_count = MemoryConsume(U32, ptr, unit_opl);
// abbrev_table_size
U32 abbrev_table_size = MemoryConsume(U32, ptr, unit_opl);
// augmentation_string_size
U32 augmentation_string_size = MemoryConsume(U32, ptr, unit_opl);
// augmentation_string
U8 *augmentation_string = ptr;
{
U8 *ptr_raw = ptr + augmentation_string_size;
ptr = ClampTop(ptr_raw, unit_opl);
}
// offset size
U8 offset_size = is_64bit?8:4;
// unit offsets
U64 base_off = (ptr - data.str);
U64 opl_off = (unit_opl - data.str);
// emit unit
DWARF_NamesUnit *unit = push_array(arena, DWARF_NamesUnit, 1);
SLLQueuePush(first, last, unit);
count += 1;
unit->hdr_off = hdr_off;
unit->base_off = base_off;
unit->opl_off = opl_off;
unit->version = version;
unit->comp_unit_count = comp_unit_count;
unit->local_type_unit_count = local_type_unit_count;
unit->foreign_type_unit_count = foreign_type_unit_count;
unit->bucket_count = bucket_count;
unit->name_count = name_count;
unit->abbrev_table_size = abbrev_table_size;
unit->augmentation_string = str8_cstring_capped(augmentation_string, unit_opl);
// advance to end of unit
ptr = unit_opl;
}
// fill result
DWARF_NamesParsed *result = push_array(arena, DWARF_NamesParsed, 1);
result->unit_first = first;
result->unit_last = last;
result->unit_count = count;
return(result);
}
static DWARF_ArangesParsed*
dwarf_aranges_from_data(Arena *arena, String8 data){
// supported version numbers: 2
// empty unit list
DWARF_ArangesUnit *first = 0;
DWARF_ArangesUnit *last = 0;
U64 count = 0;
// whole section loop
U64 unit_idx = 0;
U8 *ptr = data.str;
U8 *opl = data.str + data.size;
for (;ptr < opl; unit_idx += 1){
// remember header offset
U64 hdr_off = (ptr - data.str);
// initial length
U8 *unit_opl = 0;
B32 is_64bit = 0;
dwarf__initial_length(data, &ptr, &unit_opl, &is_64bit);
// version
U8 version = MemoryConsume(U16, ptr, unit_opl);
// info_off
U64 info_off = 0;
if (is_64bit){
info_off = MemoryConsume(U64, ptr, unit_opl);
}
else{
info_off = MemoryConsume(U32, ptr, unit_opl);
}
// address_size
U8 address_size = MemoryConsume(U8, ptr, unit_opl);
// segment_selector_size
U8 segment_selector_size = MemoryConsume(U8, ptr, unit_opl);
// offset size
U8 offset_size = is_64bit?8:4;
// unit offsets
U64 base_off = (ptr - data.str);
U64 opl_off = (unit_opl - data.str);
// emit unit
DWARF_ArangesUnit *unit = push_array(arena, DWARF_ArangesUnit, 1);
SLLQueuePush(first, last, unit);
count += 1;
unit->hdr_off = hdr_off;
unit->base_off = base_off;
unit->opl_off = opl_off;
unit->version = version;
unit->address_size = address_size;
unit->segment_selector_size = segment_selector_size;
unit->offset_size = offset_size;
unit->info_off = info_off;
// advance to end of unit
ptr = unit_opl;
}
// fill result
DWARF_ArangesParsed *result = push_array(arena, DWARF_ArangesParsed, 1);
result->unit_first = first;
result->unit_last = last;
result->unit_count = count;
return(result);
}
static DWARF_LineParsed*
dwarf_line_from_data(Arena *arena, String8 data){
// supported version numbers: 4, 5
// empty unit list
DWARF_LineUnit *first = 0;
DWARF_LineUnit *last = 0;
U64 count = 0;
// whole section loop
U64 unit_idx = 0;
U8 *ptr = data.str;
U8 *opl = data.str + data.size;
for (;ptr < opl; unit_idx += 1){
// remember header offset
U64 hdr_off = (ptr - data.str);
// initial length
U8 *unit_opl = 0;
B32 is_64bit = 0;
dwarf__initial_length(data, &ptr, &unit_opl, &is_64bit);
// version
U8 version = MemoryConsume(U16, ptr, unit_opl);
// offset size
U8 offset_size = is_64bit?8:4;
// rest of header depends on version
U8 minimum_instruction_length = 0;
U8 maximum_operations_per_instruction = 0;
U8 default_is_stmt = 0;
S8 line_base = 0;
U8 line_range = 0;
U8 opcode_base = 0;
U8 *standard_opcode_lengths = 0;
// v4
String8List include_directories = {0};
DWARF_V4LineFileNamesList file_names = {0};
// v5
U8 address_size = 0;
U8 segment_selector_size = 0;
U8 directory_entry_format_count = 0;
DWARF_V5LinePathEntryFormat *directory_entry_format = 0;
U64 directories_count = 0;
U8 file_name_entry_format_count = 0;
DWARF_V5LinePathEntryFormat *file_name_entry_format = 0;
U64 file_names_count = 0;
switch (version){
case 4:
{
// header_length
U64 header_length = 0;
if (is_64bit){
header_length = MemoryConsume(U64, ptr, unit_opl);
}
else{
header_length = MemoryConsume(U32, ptr, unit_opl);
}
// header opl
U8 *header_opl_raw = ptr + header_length;
U8 *header_opl = ClampTop(header_opl_raw, unit_opl);
// minimum_instruction_length
minimum_instruction_length = MemoryConsume(U8, ptr, header_opl);
// maximum_operations_per_instruction
maximum_operations_per_instruction = MemoryConsume(U8, ptr, header_opl);
// default_is_stmt
default_is_stmt = MemoryConsume(U8, ptr, header_opl);
// line_base
line_base = MemoryConsume(S8, ptr, header_opl);
// line_range
line_range = MemoryConsume(U8, ptr, header_opl);
// opcode_base
opcode_base = MemoryConsume(U8, ptr, header_opl);
// standard_opcode_lengths
if (opcode_base > 1){
standard_opcode_lengths = ptr;
ptr += opcode_base - 1;
}
// include_directories
for (;ptr < header_opl;){
// null byte ends entries
if (*ptr == 0){
ptr += 1;
break;
}
// extract dir range
U8 *dir_first = ptr;
for (;ptr < header_opl && *ptr != 0;) ptr += 1;
U8 *dir_opl = ptr;
if (ptr < header_opl){
ptr += 1;
}
// attach dir to list
String8 dir = str8_range(dir_first, dir_opl);
str8_list_push(arena, &include_directories, dir);
}
// file_names
for (;ptr < header_opl;){
// null byte ends entries
if (*ptr == 0){
ptr += 1;
break;
}
// extract file_name range
U8 *file_name_first = ptr;
for (;ptr < header_opl && *ptr != 0;) ptr += 1;
U8 *file_name_opl = ptr;
if (ptr < header_opl){
ptr += 1;
}
// extract include directory index
U64 include_directory_idx = 0;
DWARF_LEB128_DECODE_ADV(U64, include_directory_idx, ptr, header_opl);
// extract last modified time
U64 last_modified_time = 0;
DWARF_LEB128_DECODE_ADV(U64, last_modified_time, ptr, header_opl);
// extract file size
U64 file_size = 0;
DWARF_LEB128_DECODE_ADV(U64, file_size, ptr, header_opl);
// emit file name entry
DWARF_V4LineFileNamesEntry *entry = push_array(arena, DWARF_V4LineFileNamesEntry, 1);
SLLQueuePush(file_names.first, file_names.last, entry);
file_names.count += 1;
entry->file_name = str8_range(file_name_first, file_name_opl);
entry->include_directory_idx = include_directory_idx;
entry->last_modified_time = last_modified_time;
entry->file_size = file_size;
}
ptr = header_opl;
}break;
case 5:
{
// address_size
address_size = MemoryConsume(U8, ptr, unit_opl);
// segment_selector_size
segment_selector_size = MemoryConsume(U8, ptr, unit_opl);
// header_length
U64 header_length = 0;
if (is_64bit){
header_length = MemoryConsume(U64, ptr, unit_opl);
}
else{
header_length = MemoryConsume(U32, ptr, unit_opl);
}
// header opl
U8 *header_opl_raw = ptr + header_length;
U8 *header_opl = ClampTop(header_opl_raw, unit_opl);
// minimum_instruction_length
minimum_instruction_length = MemoryConsume(U8, ptr, header_opl);
// maximum_operations_per_instruction
maximum_operations_per_instruction = MemoryConsume(U8, ptr, header_opl);
// default_is_stmt
default_is_stmt = MemoryConsume(U8, ptr, header_opl);
// line_base
line_base = MemoryConsume(S8, ptr, header_opl);
// line_range
line_range = MemoryConsume(U8, ptr, header_opl);
// opcode_base
opcode_base = MemoryConsume(U8, ptr, header_opl);
// standard_opcode_lengths
if (opcode_base > 1){
standard_opcode_lengths = ptr;
ptr += opcode_base - 1;
}
// directory_entry_format_count
directory_entry_format_count = MemoryConsume(U8, ptr, header_opl);
// directory_entry_format
{
directory_entry_format = push_array(arena, DWARF_V5LinePathEntryFormat,
directory_entry_format_count);
DWARF_V5LinePathEntryFormat *entry = directory_entry_format;
DWARF_V5LinePathEntryFormat *entry_opl =
directory_entry_format + directory_entry_format_count;
for (;entry < entry_opl && ptr < header_opl; entry += 1){
DWARF_LEB128_DECODE_ADV(U64, entry->content_type, ptr, header_opl);
DWARF_LEB128_DECODE_ADV(U64, entry->form, ptr, header_opl);
}
}
// directories_count
DWARF_LEB128_DECODE_ADV(U64, directories_count, ptr, header_opl);
// directories
DWARF_V5Directory *directories = push_array(arena, DWARF_V5Directory, directories_count);
dwarf__line_v5_directories(address_size, offset_size,
directory_entry_format, directory_entry_format_count,
directories, directories_count,
&ptr, header_opl);
// file_name_entry_format_count
file_name_entry_format_count = MemoryConsume(U8, ptr, header_opl);
// file_name_entry_format
{
file_name_entry_format = push_array(arena, DWARF_V5LinePathEntryFormat,
file_name_entry_format_count);
DWARF_V5LinePathEntryFormat *entry = file_name_entry_format;
for (;ptr < header_opl; entry += 1){
DWARF_LEB128_DECODE_ADV(U64, entry->content_type, ptr, header_opl);
DWARF_LEB128_DECODE_ADV(U64, entry->form, ptr, header_opl);
}
}
// file_names_count
DWARF_LEB128_DECODE_ADV(U64, file_names_count, ptr, header_opl);
// file_names
DWARF_V5Directory *file_names = push_array(arena, DWARF_V5Directory, file_names_count);
dwarf__line_v5_directories(address_size, offset_size,
directory_entry_format, directory_entry_format_count,
file_names, file_names_count,
&ptr, header_opl);
}break;
}
// unit offsets
U64 base_off = (ptr - data.str);
U64 opl_off = (unit_opl - data.str);
// emit unit
DWARF_LineUnit *unit = push_array(arena, DWARF_LineUnit, 1);
SLLQueuePush(first, last, unit);
count += 1;
unit->hdr_off = hdr_off;
unit->base_off = base_off;
unit->opl_off = opl_off;
unit->version = version;
// advance to end of unit
ptr = unit_opl;
}
// fill result
DWARF_LineParsed *result = push_array(arena, DWARF_LineParsed, 1);
result->unit_first = first;
result->unit_last = last;
result->unit_count = count;
return(result);
}
static DWARF_MacInfoParsed*
dwarf_mac_info_from_data(Arena *arena, String8 data){
DWARF_MacInfoParsed *result = 0;
// TODO(allen):
return(result);
}
static DWARF_MacroParsed*
dwarf_macro_from_data(Arena *arena, String8 data){
DWARF_MacroParsed *result = 0;
// TODO(allen):
return(result);
}
static DWARF_FrameParsed*
dwarf_frame_from_data(Arena *arena, String8 data){
DWARF_FrameParsed *result = 0;
// TODO(allen):
return(result);
}
static DWARF_RangesParsed*
dwarf_ranges_from_data(Arena *arena, String8 data){
DWARF_RangesParsed *result = 0;
// TODO(allen):
return(result);
}
static DWARF_StrOffsetsParsed*
dwarf_str_offsets_from_data(Arena *arena, String8 data){
DWARF_StrOffsetsParsed *result = 0;
// TODO(allen):
return(result);
}
static DWARF_AddrParsed*
dwarf_addr_from_data(Arena *arena, String8 data){
// supported version numbers: 5
// addr unit list
DWARF_AddrUnit *first = 0;
DWARF_AddrUnit *last = 0;
U64 count = 0;
// whole section loop
U64 unit_idx = 0;
U8 *ptr = data.str;
U8 *opl = data.str + data.size;
for (;ptr < opl; unit_idx += 1){
U64 hdr_off = (ptr - data.str);
// initial length
U8 *unit_opl = 0;
B32 is_64bit = 0;
dwarf__initial_length(data, &ptr, &unit_opl, &is_64bit);
// version
U8 version = MemoryConsume(U16, ptr, unit_opl);
// address size
U8 address_size = MemoryConsume(U8, ptr, unit_opl);
// segment selector size
U8 segment_selector_size = MemoryConsume(U8, ptr, unit_opl);
// offset size
U32 offset_size = is_64bit?8:4;
// unit offsets
U64 base_off = (ptr - data.str);
U64 opl_off = (unit_opl - data.str);
// emit addr unit
DWARF_AddrUnit *unit = push_array(arena, DWARF_AddrUnit, 1);
SLLQueuePush(first, last, unit);
count += 1;
unit->hdr_off = hdr_off;
unit->base_off = base_off;
unit->opl_off = opl_off;
unit->offset_size = offset_size;
unit->dwarf_version = version;
unit->address_size = address_size;
unit->segment_selector_size = segment_selector_size;
// advance to next unit
ptr = unit_opl;
}
// fill result
DWARF_AddrParsed *result = push_array(arena, DWARF_AddrParsed, 1);
result->unit_first = first;
result->unit_last = last;
result->unit_count = count;
return(result);
}
static DWARF_RngListsParsed*
dwarf_rng_lists_from_data(Arena *arena, String8 data){
DWARF_RngListsParsed *result = 0;
// TODO(allen):
return(result);
}
static DWARF_LocListsParsed*
dwarf_loc_lists_from_data(Arena *arena, String8 data){
DWARF_LocListsParsed *result = 0;
// TODO(allen):
return(result);
}
// parse helpers
static void
dwarf__initial_length(String8 data, U8 **ptr_inout, U8 **unit_opl_out, B32 *is_64bit_out){
U8 *unit_opl = 0;
B32 is_64bit = 0;
U8 *opl = data.str + data.size;
U8 *ptr = *ptr_inout;
{
U64 length = 0;
U32 m = MemoryConsume(U32, ptr, opl);
if (m == 0xFFFFFFFF){
is_64bit = 1;
length = MemoryConsume(U64, ptr, opl);
}
else{
length = ClampTop(m, 0xFFFFFFF0);
}
if (length > 0){
U64 unit_opl_off_raw = (ptr - data.str) + length;
U64 unit_opl_off = ClampTop(unit_opl_off_raw, data.size);
unit_opl = data.str + unit_opl_off;
}
else{
unit_opl = ptr;
}
}
*ptr_inout = ptr;
*unit_opl_out = unit_opl;
*is_64bit_out = is_64bit;
}
static void
dwarf__line_v5_directories(U64 address_size, U64 offset_size,
DWARF_V5LinePathEntryFormat *format, U64 format_count,
DWARF_V5Directory *directories_out, U64 dir_count,
U8 **ptr_io, U8 *opl){
U8 *ptr = *ptr_io;
DWARF_V5Directory *directory_ptr = directories_out;
for (U32 i = 0; i < dir_count; i += 1, directory_ptr += 1){
DWARF_V5LinePathEntryFormat *fmt = format;
for (U32 j = 0; j < format_count; j += 1){
// form decode
DWARF_FormDecodeRules rules =
dwarf_form_decode_rule(fmt->form, address_size, offset_size);
// execute decoding
DWARF_FormDecoded decoded = dwarf_form_decode(&rules, &ptr, opl, 0, 0);
// store to correct field
U64 *target = 0;
switch (fmt->content_type){
case DWARF_LineEntryFormat_path:
{
if (decoded.dataptr != 0){
directory_ptr->path_str = str8(decoded.dataptr, decoded.val);
}
else{
directory_ptr->path_off = decoded.val;
directory_ptr->path_sec_form = fmt->form;
}
}break;
case DWARF_LineEntryFormat_directory_index:
{
target = &directory_ptr->directory_index;
}goto v5_directory_u64;
case DWARF_LineEntryFormat_timestamp:
{
target = &directory_ptr->timestamp;
}goto v5_directory_u64;
case DWARF_LineEntryFormat_size:
{
target = &directory_ptr->size;
}goto v5_directory_u64;
v5_directory_u64:
{
if (decoded.dataptr != 0){
U64 size = ClampTop(decoded.val, 8);
MemoryCopy(target, decoded.dataptr, size);
}
else{
*target = decoded.val;
}
}break;
case DWARF_LineEntryFormat_MD5:
{
if (decoded.dataptr != 0){
U64 size = ClampTop(decoded.val, 16);
MemoryCopy(directory_ptr->md5_checksum, decoded.dataptr, size);
}
}break;
}
}
}
*ptr_io = ptr;
}
// debug sections
static String8
dwarf_name_from_debug_section(DWARF_Parsed *dwarf, DWARF_SectionCode sec_code){
String8 result = str8_lit("invalid_debug_section");
if (sec_code < DWARF_SectionCode_COUNT){
if (dwarf->debug_section_idx[sec_code] != 0){
result = dwarf->debug_section_name[sec_code];
}
}
return(result);
}
// abbrev functions
static DWARF_AbbrevUnit*
dwarf_abbrev_unit_from_offset(DWARF_AbbrevParsed *abbrev, U64 offset){
DWARF_AbbrevUnit *result = 0;
for (DWARF_AbbrevUnit *unit = abbrev->unit_first;
unit != 0;
unit = unit->next){
if (unit->offset == offset){
result = unit;
break;
}
}
return(result);
}
static DWARF_AbbrevDecl*
dwarf_abbrev_decl_from_code(DWARF_AbbrevUnit *unit, U32 abbrev_code){
DWARF_AbbrevDecl *result = 0;
for (DWARF_AbbrevDecl *decl = unit->first;
decl != 0;
decl = decl->next){
if (decl->abbrev_code == abbrev_code){
result = decl;
break;
}
}
return(result);
}
// attribute decoding functions
static DWARF_AttributeClassFlags
dwarf_attribute_class_from_form(DWARF_AttributeForm form){
DWARF_AttributeClassFlags result = 0;
switch (form){
#define X(N,C,f) case C: result = DWARF_AttributeClassFlag_##f; break;
DWARF_AttributeFormXList(X)
#undef X
}
return(result);
}
static DWARF_AttributeClassFlags
dwarf_attribute_class_from_name(DWARF_AttributeName name){
DWARF_AttributeClassFlags result = 0;
switch (name){
#define X(N,C,f1,f2,f3,f4) case C: result = 0\
|DWARF_AttributeClassFlag_##f1\
|DWARF_AttributeClassFlag_##f2\
|DWARF_AttributeClassFlag_##f3\
|DWARF_AttributeClassFlag_##f4\
;break;
DWARF_AttributeNameXList(X)
#undef X
}
return(result);
}
// form decoding functions
static DWARF_FormDecodeRules
dwarf_form_decode_rule(DWARF_AttributeForm form, U64 address_size, U64 offset_size){
DWARF_FormDecodeRules result = {0};
switch (form){
case DWARF_AttributeForm_addr: result.size = address_size; break;
case DWARF_AttributeForm_addrx: result.uleb128 = 1; break;
case DWARF_AttributeForm_addrx1: result.size = 1; break;
case DWARF_AttributeForm_addrx2: result.size = 2; break;
case DWARF_AttributeForm_addrx3: result.size = 3; break;
case DWARF_AttributeForm_addrx4: result.size = 4; break;
case DWARF_AttributeForm_sec_offset: result.size = offset_size; break;
case DWARF_AttributeForm_block1: result.size = 1; result.block = 1; break;
case DWARF_AttributeForm_block2: result.size = 2; result.block = 1; break;
case DWARF_AttributeForm_block4: result.size = 4; result.block = 1; break;
case DWARF_AttributeForm_block: result.uleb128 = 1; result.block = 1; break;
case DWARF_AttributeForm_data1: result.size = 1; break;
case DWARF_AttributeForm_data2: result.size = 2; break;
case DWARF_AttributeForm_data4: result.size = 4; break;
case DWARF_AttributeForm_data8: result.size = 8; break;
case DWARF_AttributeForm_data16: result.size = 16; break;
case DWARF_AttributeForm_sdata: result.sleb128 = 1; break;
case DWARF_AttributeForm_udata: result.uleb128 = 1; break;
case DWARF_AttributeForm_implicit_const: result.in_abbrev = 1; break;
case DWARF_AttributeForm_exprloc: result.uleb128 = 1; result.block = 1; break;
case DWARF_AttributeForm_flag: result.size = 1; break;
case DWARF_AttributeForm_flag_present: result.auto_1 = 1; break;
case DWARF_AttributeForm_loclistx: result.uleb128 = 1; break;
case DWARF_AttributeForm_rnglistx: result.uleb128 = 1; break;
case DWARF_AttributeForm_ref1: result.size = 1; break;
case DWARF_AttributeForm_ref2: result.size = 2; break;
case DWARF_AttributeForm_ref4: result.size = 4; break;
case DWARF_AttributeForm_ref8: result.size = 8; break;
case DWARF_AttributeForm_ref_udata: result.uleb128 = 1; break;
case DWARF_AttributeForm_ref_addr: result.size = offset_size; break;
case DWARF_AttributeForm_ref_sig8: result.size = 8; break;
case DWARF_AttributeForm_ref_sup4: result.size = 4; break;
case DWARF_AttributeForm_ref_sup8: result.size = 8; break;
case DWARF_AttributeForm_string: result.null_terminated = 1; break;
case DWARF_AttributeForm_strp: result.size = offset_size; break;
case DWARF_AttributeForm_line_strp: result.size = offset_size; break;
case DWARF_AttributeForm_strp_sup: result.size = offset_size; break;
case DWARF_AttributeForm_strx: result.uleb128 = 1; break;
case DWARF_AttributeForm_strx1: result.size = 1; break;
case DWARF_AttributeForm_strx2: result.size = 2; break;
case DWARF_AttributeForm_strx3: result.size = 3; break;
case DWARF_AttributeForm_strx4: result.size = 4; break;
}
return(result);
}
static DWARF_FormDecoded
dwarf_form_decode(DWARF_FormDecodeRules *rules, U8 **ptr_io, U8 *opl,
DWARF_AbbrevDecl *abbrev_decl, U32 attrib_i){
// local copy of ptr
U8 *ptr = *ptr_io;
// apply rules
U64 val = 0;
U8 *dataptr = 0;
B32 success = 1;
if (rules->size > 0){
if (ptr + rules->size <= opl){
MemoryCopy(&val, ptr, rules->size);
ptr += rules->size;
}
else{
success = 0;
}
}
else if (rules->uleb128 || rules->sleb128){
U8 *val_ptr = ptr;
DWARF_LEB128_ADV(ptr, opl, success);
if (success){
if (rules->uleb128){
val = dwarf_leb128_decode_U64(val_ptr, ptr);
}
else{
val = (U64)dwarf_leb128_decode_S64(val_ptr, ptr);
}
}
}
else if (rules->in_abbrev){
if (abbrev_decl != 0){
if (abbrev_decl->implicit_const != 0){
val = (U64)abbrev_decl->implicit_const[attrib_i];
}
}
else{
success = 0;
}
}
else if (rules->auto_1){
val = 1;
}
if (rules->block){
dataptr = ptr;
ptr += val;
}
else if (rules->null_terminated){
dataptr = ptr;
for (;ptr < opl && *ptr != 0;) ptr += 1;
val = (U64)(ptr - dataptr);
if (ptr < opl){
ptr += 1;
}
}
// store out ptr
*ptr_io = ptr;
// fill result
DWARF_FormDecoded result = {0};
result.val = val;
result.dataptr = dataptr;
result.error = !success;
return(result);
}
// string functions
static String8
dwarf_string_from_unit_type(DWARF_UnitType type){
String8 result = str8_lit("unrecognized_type");
switch (type){
#define X(N,C) case C: result = str8_lit(#N); break;
DWARF_UnitTypeXList(X)
#undef X
}
return(result);
}
static String8
dwarf_string_from_tag(DWARF_Tag tag){
String8 result = str8_lit("unrecognized_tag");
switch (tag){
#define X(N,C) case C: result = str8_lit(#N); break;
DWARF_TagXList(X)
#undef X
}
return(result);
}
static String8
dwarf_string_from_attribute_name(DWARF_AttributeName name){
String8 result = str8_lit("unrecognized_attribute_name");
switch (name){
#define X(N,C,f1,f2,f3,f4) case C: result = str8_lit(#N); break;
DWARF_AttributeNameXList(X)
#undef X
}
return(result);
}
static String8
dwarf_string_from_attribute_form(DWARF_AttributeForm form){
String8 result = str8_lit("unrecognized_attribute_form");
switch (form){
#define X(N,C,k) case C: result = str8_lit(#N); break;
DWARF_AttributeFormXList(X)
#undef X
}
return(result);
}
static String8
dwarf_string_from_line_std_op(DWARF_LineStdOp op){
String8 result = str8_lit("unrecognized_line_std_op");
switch (op){
#define X(N,C) case C: result = str8_lit(#N); break;
DWARF_LineStdOpXList(X)
#undef X
}
return(result);
}
static String8
dwarf_string_from_line_ext_op(DWARF_LineExtOp op){
String8 result = str8_lit("unrecognized_line_ext_op");
switch (op){
#define X(N,C) case C: result = str8_lit(#N); break;
DWARF_LineExtOpXList(X)
#undef X
}
return(result);
}
static String8
dwarf_string_from_line_entry_format(DWARF_LineEntryFormat format){
String8 result = str8_lit("unrecognized_line_entry_format");
switch (format){
#define X(N,C) case C: result = str8_lit(#N); break;
DWARF_LineEntryFormatXList(X)
#undef X
}
return(result);
}
static String8
dwarf_string_from_section_code(DWARF_SectionCode sec_code){
String8 result = str8_lit("unrecognized_section_code");
switch (sec_code){
#define X(Nc,Vf,N0,N1,N2) case DWARF_SectionCode_##Nc: result = str8_lit(#Nc); break;
DWARF_SectionNameXList(X,0,0)
#undef X
}
return(result);
}
#if 0
static DWARF_InfoParsed*
dwarf_info_from_data(Arena *arena, String8 data, DWARF_InfoParams *params,
DWARF_AbbrevParsed *abbrev){
// unit index range to extract
U64 unit_idx_min = params->unit_idx_min;
U64 unit_idx_max = params->unit_idx_max;
// empty unit list
DWARF_InfoUnit *unit_first = 0;
DWARF_InfoUnit *unit_last = 0;
U64 unit_count = 0;
B32 decoding_error = 0;
// whole section loop
U64 unit_idx = 0;
U8 *ptr = data.str;
U8 *opl = data.str + data.size;
for (;ptr < opl; unit_idx += 1){
// early escape on unit idx
if (unit_idx > unit_idx_max){
break;
}
// determine whether to full parse this unit
B32 full_parse = (unit_idx_min <= unit_idx);
// header fields
U8 *unit_opl = 0;
B32 is_64bit = 0;
U16 version = 0;
U64 abbrev_offset = 0;
U32 address_size = 0;
DWARF_UnitType unit_type = DWARF_UnitType_null;
U64 unit_dwo_id = 0;
U64 unit_type_signature = 0;
U64 unit_type_offset = 0;
// initial length
dwarf__initial_length(&ptr, opl, &unit_opl, &is_64bit);
// if this is not a full parse we may use
// unit_opl to skip to the next unit now
if (full_parse){
// version (part of header)
version = MemoryConsume(U16, ptr, unit_opl);
// rest of header depends on version
switch (version){
case 4:
{
// abbrev_offset (part of header)
if (is_64bit){
abbrev_offset = MemoryConsume(U64, ptr, unit_opl);
}
else{
abbrev_offset = MemoryConsume(U32, ptr, unit_opl);
}
// address_size (part of header)
address_size = MemoryConsume(U8, ptr, unit_opl);
}break;
case 5:
{
// unit_type (part of header)
unit_type = (DWARF_UnitType)MemoryConsume(U8, ptr, unit_opl);
// address_size (part of header)
address_size = MemoryConsume(U8, ptr, unit_opl);
// abbrev_offset (part of header)
if (is_64bit){
abbrev_offset = MemoryConsume(U64, ptr, unit_opl);
}
else{
abbrev_offset = MemoryConsume(U32, ptr, unit_opl);
}
// rest of header depends on unit_type
switch (unit_type){
case DWARF_UnitType_skeleton:
case DWARF_UnitType_split_compile:
{
unit_dwo_id = MemoryConsume(U64, ptr, unit_opl);
}break;
case DWARF_UnitType_type:
case DWARF_UnitType_split_type:
{
unit_type_signature = MemoryConsume(U64, ptr, unit_opl);
if (is_64bit){
unit_type_offset = MemoryConsume(U64, ptr, unit_opl);
}
else{
unit_type_offset = MemoryConsume(U32, ptr, unit_opl);
}
}break;
}
}break;
}
// offset size
U32 offset_size = is_64bit?8:4;
// find matching abbrev unit
DWARF_AbbrevUnit *abbrev_unit = dwarf_abbrev_unit_from_offset(abbrev, abbrev_offset);
if (abbrev_unit == 0){
// TODO: preserve error info
decoding_error = 1;
}
// consume info entries
DWARF_InfoEntry *entry_root = 0;
U64 entry_count = 0;
DWARF_InfoEntry *entry_consptr = 0;
if (abbrev_unit != 0){
for (;ptr < unit_opl;){
B32 success = 1;
// mark beginning of entry
U8 *entry_start_ptr = ptr;
// extract abbrev code
U8 *abbrev_code_ptr = ptr;
DWARF_LEB128_ADV(ptr, unit_opl, success);
if (!success){
// TODO: preserve error info
decoding_error = 1;
goto exit_unit_loop;
}
U32 abbrev_code = dwarf_leb128_decode_U32(abbrev_code_ptr, ptr);
// null abbrev code means pop
if (abbrev_code == 0){
if (entry_consptr == 0){
goto exit_unit_loop;
}
else{
entry_consptr = entry_consptr->parent;
goto skip_entry;
}
}
// get abbrev decl
DWARF_AbbrevDecl *abbrev_decl = dwarf_abbrev_decl_from_code(abbrev_unit, abbrev_code);
if (abbrev_decl == 0){
// TODO: preserve error info
decoding_error = 1;
goto exit_unit_loop;
}
// allocate entry
U32 attrib_count = abbrev_decl->attrib_count;
DWARF_InfoEntry *entry = push_array(arena, DWARF_InfoEntry, 1);
DWARF_InfoAttribVal *attrib_vals =
push_array_no_zero(arena, DWARF_InfoAttribVal, attrib_count);
// save entry offset
entry->info_offset = (U64)(entry_start_ptr - data.str);
// set root at beginning
if (entry_root == 0){
entry_root = entry;
}
// attribute loop
DWARF_AbbrevAttribSpec *attrib_spec = abbrev_decl->attrib_specs;
DWARF_InfoAttribVal *attrib_val = attrib_vals;
for (U32 i = 0; i < attrib_count; i += 1, attrib_spec += 1, attrib_val += 1){
// determine decoding rules
U32 size = 0;
B8 uleb128 = 0;
B8 sleb128 = 0;
B8 in_abbrev = 0;
B8 auto_1 = 0;
B8 block = 0;
B8 null_terminated = 0;
{
DWARF_AttributeForm form = attrib_spec->form;
switch (form){
case DWARF_AttributeForm_addr: size = address_size; break;
case DWARF_AttributeForm_addrx: uleb128 = 1; break;
case DWARF_AttributeForm_addrx1: size = 1; break;
case DWARF_AttributeForm_addrx2: size = 2; break;
case DWARF_AttributeForm_addrx3: size = 3; break;
case DWARF_AttributeForm_addrx4: size = 4; break;
case DWARF_AttributeForm_sec_offset: size = offset_size; break;
case DWARF_AttributeForm_block1: size = 1; block = 1; break;
case DWARF_AttributeForm_block2: size = 2; block = 1; break;
case DWARF_AttributeForm_block4: size = 4; block = 1; break;
case DWARF_AttributeForm_block: uleb128 = 1; block = 1; break;
case DWARF_AttributeForm_data1: size = 1; break;
case DWARF_AttributeForm_data2: size = 2; break;
case DWARF_AttributeForm_data4: size = 4; break;
case DWARF_AttributeForm_data8: size = 8; break;
case DWARF_AttributeForm_data16: size = 16; break;
case DWARF_AttributeForm_sdata: sleb128 = 1; break;
case DWARF_AttributeForm_udata: uleb128 = 1; break;
case DWARF_AttributeForm_implicit_const: in_abbrev = 1; break;
case DWARF_AttributeForm_exprloc: uleb128 = 1; block = 1; break;
case DWARF_AttributeForm_flag: size = 1; break;
case DWARF_AttributeForm_flag_present: auto_1 = 1; break;
case DWARF_AttributeForm_loclistx: uleb128 = 1; break;
case DWARF_AttributeForm_rnglistx: uleb128 = 1; break;
case DWARF_AttributeForm_ref1: size = 1; break;
case DWARF_AttributeForm_ref2: size = 2; break;
case DWARF_AttributeForm_ref4: size = 4; break;
case DWARF_AttributeForm_ref8: size = 8; break;
case DWARF_AttributeForm_ref_udata: uleb128 = 1; break;
case DWARF_AttributeForm_ref_addr: size = offset_size; break;
case DWARF_AttributeForm_ref_sig8: size = 8; break;
case DWARF_AttributeForm_ref_sup4: size = 4; break;
case DWARF_AttributeForm_ref_sup8: size = 8; break;
case DWARF_AttributeForm_string: null_terminated = 1; break;
case DWARF_AttributeForm_strp: size = offset_size; break;
case DWARF_AttributeForm_line_strp: size = offset_size; break;
case DWARF_AttributeForm_strp_sup: size = offset_size; break;
case DWARF_AttributeForm_strx: uleb128 = 1; break;
case DWARF_AttributeForm_strx1: size = 1; break;
case DWARF_AttributeForm_strx2: size = 2; break;
case DWARF_AttributeForm_strx3: size = 3; break;
case DWARF_AttributeForm_strx4: size = 4; break;
}
}
// execute decoding rules
U64 val = 0;
U8 *dataptr = 0;
{
if (size > 0){
if (ptr + size <= unit_opl){
MemoryCopy(&val, ptr, size);
ptr += size;
}
else{
// TODO: preserve error info
decoding_error = 1;
goto exit_unit_loop;
}
}
else if (uleb128 || sleb128){
U8 *val_ptr = ptr;
DWARF_LEB128_ADV(ptr, unit_opl, success);
if (!success){
// TODO: preserve error info
decoding_error = 1;
goto exit_unit_loop;
}
else{
if (uleb128){
val = dwarf_leb128_decode_U64(val_ptr, ptr);
}
else{
val = (U64)dwarf_leb128_decode_S64(val_ptr, ptr);
}
}
}
else if (in_abbrev){
if (abbrev_decl->implicit_const != 0){
val = (U64)abbrev_decl->implicit_const[i];
}
}
else if (auto_1){
val = 1;
}
if (block){
dataptr = ptr;
ptr += val;
}
else if (null_terminated){
dataptr = ptr;
for (;ptr < unit_opl && *ptr != 0;) ptr += 1;
val = (U64)(ptr - dataptr);
}
}
// save attribute
attrib_val->val = val;
attrib_val->dataptr = dataptr;
}
// emit entry
if (entry_consptr != 0){
SLLQueuePush_N(entry_consptr->first_child, entry_consptr->last_child,
entry, next_sibling);
entry_consptr->child_count += 1;
entry->parent = entry_consptr;
}
entry_count += 1;
entry->abbrev_decl = abbrev_decl;
entry->attrib_vals = attrib_vals;
// move consptr down if has children
if (abbrev_decl->has_children){
entry_consptr = entry;
}
skip_entry:;
}
}
exit_unit_loop:;
// TODO: notice errors, emit them, and exit loop here
if (decoding_error){
break;
}
// extract root attributes
U64 language = 0;
U64 str_offsets_base = 0;
U64 line_info_offset = 0;
U64 vbase = 0;
U64 addr_base = 0;
U64 rnglists_base = 0;
U64 loclists_base = 0;
if (entry_root != 0){
// pull out attributes
DWARF_AbbrevDecl *root_abbrev_decl = entry_root->abbrev_decl;
DWARF_AbbrevAttribSpec *attrib_specs = root_abbrev_decl->attrib_specs;
DWARF_InfoAttribVal *attrib_vals = entry_root->attrib_vals;
U32 attrib_count = root_abbrev_decl->attrib_count;
// examine each attribute
DWARF_AbbrevAttribSpec *attrib_spec = attrib_specs;
DWARF_InfoAttribVal *attrib_val = attrib_vals;
for (U32 i = 0; i < attrib_count; i += 1, attrib_spec += 1, attrib_val += 1){
// determine if there is a root attribute to extract here
U64 *target_u64 = 0;
switch (attrib_spec->name){
case DWARF_AttributeName_language: target_u64 = &language; break;
case DWARF_AttributeName_str_offsets_base: target_u64 = &str_offsets_base; break;
case DWARF_AttributeName_stmt_list: target_u64 = &line_info_offset; break;
case DWARF_AttributeName_low_pc: target_u64 = &vbase; break;
case DWARF_AttributeName_addr_base: target_u64 = &addr_base; break;
case DWARF_AttributeName_rnglists_base: target_u64 = &rnglists_base; break;
case DWARF_AttributeName_loclists_base: target_u64 = &loclists_base; break;
}
// set target from attrib value
if (target_u64 != 0){
*target_u64 = attrib_val->val;
}
}
}
// allocate unit
DWARF_InfoUnit *unit = push_array(arena, DWARF_InfoUnit, 1);
// fill & emit unit
SLLQueuePush(unit_first, unit_last, unit);
unit_count += 1;
// [header]
unit->dwarf_version = version;
unit->offset_size = offset_size;
unit->address_size = address_size;
// [root attributes]
unit->language = (DWARF_Language)language;
unit->str_offsets_base = str_offsets_base;
unit->line_info_offset = line_info_offset;
unit->vbase = vbase;
unit->addr_base = addr_base;
unit->rnglists_base = rnglists_base;
unit->loclists_base = loclists_base;
// [entries]
unit->entry_root = entry_root;
unit->entry_count = entry_count;
}
// set ptr to end of this unit
ptr = unit_opl;
}
// fill result
DWARF_InfoParsed *result = push_array(arena, DWARF_InfoParsed, 1);
result->unit_first = unit_first;
result->unit_last = unit_last;
result->unit_count = unit_count;
result->decoding_error = decoding_error;
return(result);
}
static DWARF_AbbrevParsed*
dwarf_abbrev_from_data(Arena *arena, String8 data, DWARF_AbbrevParams *params){
/* .debug_abbrev
** Layout
** List(Tag)
** Tag = { id:ULEB128, tag:ULEB128, has_children:B8, ListNullTerminated(Attribute) }
** Attribute = { name:ULEB128, form:ULEB128, (val:SLEB128)? }
*/
// unit index range to extract
U64 unit_idx_min = params->unit_idx_min;
U64 unit_idx_max = params->unit_idx_max;
// empty unit list
DWARF_AbbrevUnit *unit_first = 0;
DWARF_AbbrevUnit *unit_last = 0;
U64 unit_count = 0;
B32 decoding_error = 0;
// whole section loop
U64 unit_idx = 0;
U8 *ptr = data.str;
U8 *opl = data.str + data.size;
for (;ptr < opl; unit_idx += 1){
// early escape on unit idx
if (unit_idx > unit_idx_max){
break;
}
// determine whether to full parse this unit
B32 full_parse = (unit_idx_min <= unit_idx);
// save unit offset
U64 abbrev_unit_offset = (U64)(ptr - data.str);
// allocate unit
DWARF_AbbrevUnit *unit = push_array(arena, DWARF_AbbrevUnit, 1);
// empty abbrev list
DWARF_AbbrevDecl *abbrev_first = 0;
DWARF_AbbrevDecl *abbrev_last = 0;
U64 abbrev_count = 0;
// abbrev decl loop
for (;ptr < opl;){
B32 success = 1;
// mark abbrev_code field
U8 *abbrev_code_ptr = ptr;
DWARF_LEB128_ADV(ptr, opl, success);
// null abbrev code means end of unit
if (success && *abbrev_code_ptr == 0){
break;
}
// mark tag
U8 *tag_ptr = ptr;
DWARF_LEB128_ADV(ptr, opl, success);
U8 *end_tag_ptr = ptr;
// extract has_children
B8 has_children = 0;
if (ptr < opl){
has_children = *ptr;
ptr += 1;
}
else{
success = 0;
}
// count attributes
U8 *attrib_start_ptr = ptr;
U32 attrib_count = 0;
B32 has_implicit_const = 0;
if (success){
for (;;){
// decode normal attribute layout
U8 *attrib_name = ptr;
DWARF_LEB128_ADV(ptr, opl, success);
U8 *attrib_form = ptr;
DWARF_LEB128_ADV(ptr, opl, success);
// handle special case implicit_const
if (success && *attrib_form == (U8)DWARF_AttributeForm_implicit_const){
DWARF_LEB128_ADV(ptr, opl, success);
has_implicit_const = 1;
}
// termination conditions
if (ptr == opl ||
(*attrib_name == 0 && *attrib_form == 0)){
break;
}
// increment
attrib_count += 1;
}
}
// build the abbreviation declaration
if (full_parse && success){
// allocate abbrev
DWARF_AbbrevDecl *abbrev = push_array(arena, DWARF_AbbrevDecl, 1);
DWARF_AbbrevAttribSpec *attribs =
push_array_no_zero(arena, DWARF_AbbrevAttribSpec, attrib_count);
U64 *implicit_const = 0;
if (has_implicit_const){
implicit_const = push_array(arena, U64, attrib_count);
}
// extract abbrev fields
U32 abbrev_code = dwarf_leb128_decode_U32(abbrev_code_ptr, tag_ptr);
U32 tag = dwarf_leb128_decode_U32(tag_ptr, end_tag_ptr);
U8 *attrib_ptr = attrib_start_ptr;
DWARF_AbbrevAttribSpec *attrib = attribs;
for (U32 i = 0; i < attrib_count; i += 1, attrib += 1){
// mark attribute fields
U8 *attrib_name = attrib_ptr;
DWARF_LEB128_ADV_NOCAP(attrib_ptr);
U8 *attrib_form = attrib_ptr;
DWARF_LEB128_ADV_NOCAP(attrib_ptr);
// extract attribute fields
U32 name = dwarf_leb128_decode_U32(attrib_name, attrib_form);
U32 form = dwarf_leb128_decode_U32(attrib_form, attrib_ptr);
// fill attribute spec
attrib->name = (DWARF_AttributeName)name;
attrib->form = (DWARF_AttributeForm)form;
// handle special case implicit_const
if (form == DWARF_AttributeForm_implicit_const){
U8 *attrib_value = attrib_ptr;
DWARF_LEB128_ADV_NOCAP(attrib_ptr);
S64 value = dwarf_leb128_decode_S64(attrib_form, attrib_ptr);
implicit_const[i] = value;
}
}
// fill abbreviation
SLLQueuePush(abbrev_first, abbrev_last, abbrev);
abbrev_count += 1;
abbrev->abbrev_code = abbrev_code;
abbrev->tag = (DWARF_Tag)tag;
abbrev->has_children = has_children;
abbrev->attrib_count = attrib_count;
abbrev->attrib_specs = attribs;
abbrev->implicit_const = implicit_const;
}
// handle failure
if (!success){
// TODO: emit error message
decoding_error = 1;
goto done_parse;
}
}
// fill unit
if (full_parse){
SLLQueuePush(unit_first, unit_last, unit);
unit_count += 1;
unit->offset = abbrev_unit_offset;
unit->first = abbrev_first;
unit->last = abbrev_last;
unit->count = abbrev_count;
}
}
done_parse:;
// fill result
DWARF_AbbrevParsed *result = push_array(arena, DWARF_AbbrevParsed, 1);
result->unit_first = unit_first;
result->unit_last = unit_last;
result->unit_count = unit_count;
result->decoding_error = decoding_error;
return(result);
}
#endif