raddbgi -> rdi

This commit is contained in:
Ryan Fleury
2024-05-23 15:09:53 -07:00
parent dc5dda3f71
commit 35c599dea3
34 changed files with 153 additions and 174 deletions
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+102
View File
@@ -0,0 +1,102 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ DWARF Stringize Functions
static char dwarf_spaces[] = " ";
static void
dwarf_stringize_info(Arena *arena, String8List *out, DWARF_InfoUnit *unit, U32 indent){
String8 unit_type_string = dwarf_string_from_unit_type((DWARF_UnitType)unit->unit_type);
str8_list_pushf(arena, out, "%.*shdr_off=0x%llx\n", indent, dwarf_spaces, unit->hdr_off);
str8_list_pushf(arena, out, "%.*sbase_off=0x%llx\n", indent, dwarf_spaces, unit->base_off);
str8_list_pushf(arena, out, "%.*sopl_off=0x%llx\n", indent, dwarf_spaces, unit->opl_off);
str8_list_pushf(arena, out, "%.*soffset_size=%u\n", indent, dwarf_spaces,
unit->offset_size);
str8_list_pushf(arena, out, "%.*sversion=%u\n", indent, dwarf_spaces, unit->version);
str8_list_pushf(arena, out, "%.*sunit_type=%.*s\n", indent, dwarf_spaces,
str8_varg(unit_type_string));
str8_list_pushf(arena, out, "%.*saddress_size=%u\n", indent, dwarf_spaces,
unit->address_size);
str8_list_pushf(arena, out, "%.*sabbrev_off=0x%llx\n", indent, dwarf_spaces,
unit->abbrev_off);
switch (unit->unit_type){
case DWARF_UnitType_skeleton: case DWARF_UnitType_split_compile:
{
str8_list_pushf(arena, out, "%.*sdwo_id=%llu\n", indent, dwarf_spaces, unit->dwo_id);
}break;
case DWARF_UnitType_type: case DWARF_UnitType_split_type:
{
str8_list_pushf(arena, out, "%.*stype_signature=%llu\n", indent, dwarf_spaces,
unit->type_signature);
str8_list_pushf(arena, out, "%.*stype_offset=%llu\n", indent, dwarf_spaces,
unit->type_offset);
}break;
}
}
static void
dwarf_stringize_pubnames(Arena *arena, String8List *out, DWARF_PubNamesUnit *unit,
U32 indent){
str8_list_pushf(arena, out, "%.*shdr_off=0x%llx\n", indent, dwarf_spaces, unit->hdr_off);
str8_list_pushf(arena, out, "%.*sbase_off=0x%llx\n", indent, dwarf_spaces, unit->base_off);
str8_list_pushf(arena, out, "%.*sopl_off=0x%llx\n", indent, dwarf_spaces, unit->opl_off);
str8_list_pushf(arena, out, "%.*soffset_size=%u\n", indent, dwarf_spaces, unit->offset_size);
str8_list_pushf(arena, out, "%.*sversion=%u\n", indent, dwarf_spaces, unit->version);
str8_list_pushf(arena, out, "%.*sinfo_off=0x%llx\n", indent, dwarf_spaces, unit->info_off);
str8_list_pushf(arena, out, "%.*sinfo_length=0x%llx\n", indent, dwarf_spaces,
unit->info_length);
}
static void
dwarf_stringize_names(Arena *arena, String8List *out, DWARF_NamesUnit *unit, U32 indent){
str8_list_pushf(arena, out, "%.*shdr_off=0x%llx\n", indent, dwarf_spaces, unit->hdr_off);
str8_list_pushf(arena, out, "%.*sbase_off=0x%llx\n", indent, dwarf_spaces, unit->base_off);
str8_list_pushf(arena, out, "%.*sopl_off=0x%llx\n", indent, dwarf_spaces, unit->opl_off);
str8_list_pushf(arena, out, "%.*sversion=%u\n", indent, dwarf_spaces, unit->version);
str8_list_pushf(arena, out, "%.*scomp_unit_count=%u\n", indent, dwarf_spaces,
unit->comp_unit_count);
str8_list_pushf(arena, out, "%.*slocal_type_unit_count=%u\n", indent, dwarf_spaces,
unit->local_type_unit_count);
str8_list_pushf(arena, out, "%.*sforeign_type_unit_count=%u\n", indent, dwarf_spaces,
unit->foreign_type_unit_count);
str8_list_pushf(arena, out, "%.*sbucket_count=%u\n", indent, dwarf_spaces,
unit->bucket_count);
str8_list_pushf(arena, out, "%.*sname_count=%u\n", indent, dwarf_spaces, unit->name_count);
str8_list_pushf(arena, out, "%.*sabbrev_table_size=%u\n", indent, dwarf_spaces,
unit->abbrev_table_size);
str8_list_pushf(arena, out, "%.*saugmentation_string=%.*s\n", indent, dwarf_spaces,
str8_varg(unit->augmentation_string));
}
static void
dwarf_stringize_aranges(Arena *arena, String8List *out, DWARF_ArangesUnit *unit, U32 indent){
str8_list_pushf(arena, out, "%.*shdr_off=0x%llx\n", indent, dwarf_spaces, unit->hdr_off);
str8_list_pushf(arena, out, "%.*sbase_off=0x%llx\n", indent, dwarf_spaces, unit->base_off);
str8_list_pushf(arena, out, "%.*sopl_off=0x%llx\n", indent, dwarf_spaces, unit->opl_off);
str8_list_pushf(arena, out, "%.*sversion=%u\n", indent, dwarf_spaces, unit->version);
str8_list_pushf(arena, out, "%.*saddress_size=%u\n", indent, dwarf_spaces,
unit->address_size);
str8_list_pushf(arena, out, "%.*ssegment_selector_size=%u\n", indent, dwarf_spaces,
unit->segment_selector_size);
str8_list_pushf(arena, out, "%.*soffset_size=%u\n", indent, dwarf_spaces, unit->offset_size);
str8_list_pushf(arena, out, "%.*sinfo_off=0x%llx\n", indent, dwarf_spaces, unit->info_off);
}
static void
dwarf_stringize_addr(Arena *arena, String8List *out, DWARF_AddrUnit *unit, U32 indent){
str8_list_pushf(arena, out, "%.*shdr_off=0x%llx\n", indent, dwarf_spaces, unit->hdr_off);
str8_list_pushf(arena, out, "%.*sbase_off=0x%llx\n", indent, dwarf_spaces, unit->base_off);
str8_list_pushf(arena, out, "%.*sopl_off=0x%llx\n", indent, dwarf_spaces, unit->opl_off);
str8_list_pushf(arena, out, "%.*soffset_size=%u\n", indent, dwarf_spaces,
unit->offset_size);
str8_list_pushf(arena, out, "%.*sversion=%u\n", indent, dwarf_spaces, unit->dwarf_version);
str8_list_pushf(arena, out, "%.*saddress_size=%u\n", indent, dwarf_spaces,
unit->address_size);
str8_list_pushf(arena, out, "%.*ssegment_selector_size=%u\n", indent, dwarf_spaces,
unit->segment_selector_size);
}
+28
View File
@@ -0,0 +1,28 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef RDI_DWARF_STRINGIZE_H
#define RDI_DWARF_STRINGIZE_H
////////////////////////////////
//~ DWARF Stringize Functions
static void
dwarf_stringize_info(Arena *arena, String8List *out, DWARF_InfoUnit *unit, U32 indent);
static void
dwarf_stringize_pubnames(Arena *arena, String8List *out, DWARF_PubNamesUnit *unit,
U32 indent);
static void
dwarf_stringize_names(Arena *arena, String8List *out, DWARF_NamesUnit *unit, U32 indent);
static void
dwarf_stringize_aranges(Arena *arena, String8List *out, DWARF_ArangesUnit *unit, U32 indent);
static void
dwarf_stringize_addr(Arena *arena, String8List *out, DWARF_AddrUnit *unit, U32 indent);
#endif //RDI_DWARF_STRINGIZE_H
+555
View File
@@ -0,0 +1,555 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ ELF Parser Functions
static ELF_Parsed*
elf_parsed_from_data(Arena *arena, String8 elf_data){
//- test magic number
B32 has_good_magic_number = 0;
if (elf_data.size >= sizeof(ELF_NIDENT) &&
MemoryMatch(elf_data.str, elf_magic, sizeof(elf_magic))){
has_good_magic_number = 1;
}
//- determine elf class
U8 elf_class = ELF_Class_NONE;
if (has_good_magic_number){
elf_class = elf_data.str[ELF_Identification_CLASS];
}
//- extract header information
B32 decoded_header = 0;
U8 e_data_encoding = ELF_DataEncoding_NONE;
U16 e_machine = ELF_Machine_NONE;
U64 e_entry = 0;
U64 e_shoff = 0;
U16 e_shentsize = 0;
U16 e_shnum = 0;
U64 e_phoff = 0;
U16 e_phentsize = 0;
U16 e_phnum = 0;
U16 e_shstrndx = 0;
switch (elf_class){
case ELF_Class_NONE: /* not good */ break;
case ELF_Class_32:
{
if (elf_data.size >= sizeof(ELF_Ehdr32)){
ELF_Ehdr32 *hdr = (ELF_Ehdr32*)elf_data.str;
decoded_header = 1;
e_data_encoding = hdr->e_ident[ELF_Identification_DATA];
e_machine = hdr->e_machine;
e_entry = hdr->e_entry;
e_phoff = hdr->e_phoff;
e_shoff = hdr->e_shoff;
e_phentsize = hdr->e_phentsize;
e_phnum = hdr->e_phnum;
e_shentsize = hdr->e_shentsize;
e_shnum = hdr->e_shnum;
e_shstrndx = hdr->e_shstrndx;
}
}break;
case ELF_Class_64:
{
if (elf_data.size >= sizeof(ELF_Ehdr64)){
ELF_Ehdr64 *hdr = (ELF_Ehdr64*)elf_data.str;
decoded_header = 1;
e_data_encoding = hdr->e_ident[ELF_Identification_DATA];
e_machine = hdr->e_machine;
e_entry = hdr->e_entry;
e_phoff = hdr->e_phoff;
e_shoff = hdr->e_shoff;
e_phentsize = hdr->e_phentsize;
e_phnum = hdr->e_phnum;
e_shentsize = hdr->e_shentsize;
e_shnum = hdr->e_shnum;
e_shstrndx = hdr->e_shstrndx;
}
}break;
}
//- validate & translate header values
B32 header_is_good = 0;
Architecture arch = Architecture_Null;
if (decoded_header){
header_is_good = 1;
// only supporting little-endian versions right now
if (header_is_good){
if (e_data_encoding != ELF_DataEncoding_2LSB){
header_is_good = 0;
}
}
// make sure this is a supported machine type
if (header_is_good){
switch (e_machine){
default: header_is_good = 0;
case ELF_Machine_386: arch = Architecture_x86; break;
case ELF_Machine_X86_64: arch = Architecture_x64; break;
}
}
// make sure section & segment sizes are correct
if (header_is_good){
switch (elf_class){
case ELF_Class_32:
{
if (e_shentsize != sizeof(ELF_Shdr32) ||
e_phentsize != sizeof(ELF_Phdr32)){
header_is_good = 0;
}
}break;
case ELF_Class_64:
{
if (e_shentsize != sizeof(ELF_Shdr64) ||
e_phentsize != sizeof(ELF_Phdr64)){
header_is_good = 0;
}
}break;
}
}
}
//- extract extra information from the special first section
U64 section_count_raw = e_shnum;
U32 section_header_string_table_index = e_shstrndx;
if (header_is_good){
if (e_shoff <= elf_data.size && e_shentsize <= elf_data.size &&
e_shoff + e_shentsize <= elf_data.size){
U64 size = 0;
U32 link = 0;
switch (elf_class){
case ELF_Class_32:
{
ELF_Shdr32 *shdr = (ELF_Shdr32*)(elf_data.str + e_shoff);
size = shdr->sh_size;
link = shdr->sh_link;
}break;
case ELF_Class_64:
{
ELF_Shdr64 *shdr = (ELF_Shdr64*)(elf_data.str + e_shoff);
size = shdr->sh_size;
link = shdr->sh_link;
}break;
}
// extended section count
if (size != 0){
section_count_raw = size;
}
// extended section header string table index
if (link != 0){
section_header_string_table_index = link;
}
}
}
//- clamp section & program arrays to size
U64 section_foff = 0;
U64 section_size = 0;
U64 section_count = 0;
U64 segment_foff = 0;
U64 segment_size = 0;
U64 segment_count = 0;
if (header_is_good){
if (e_shentsize > 0){
U64 section_opl_raw = e_shoff + e_shentsize*section_count_raw;
U64 section_opl = ClampTop(section_opl_raw, elf_data.size);
if (section_opl > e_shoff){
section_foff = e_shoff;
section_size = e_shentsize;
section_count = (section_opl - e_shoff)/e_shentsize;
}
}
if (e_phentsize > 0){
U64 segment_opl_raw = e_phoff + e_phentsize*e_phnum;
U64 segment_opl = ClampTop(segment_opl_raw, elf_data.size);
if (segment_opl > e_phoff){
segment_foff = e_phoff;
segment_size = e_phentsize;
segment_count = (segment_opl - e_phoff)/e_phentsize;
}
}
}
//- determine the vbase for this file
U64 vbase = 0;
if (header_is_good){
// find the first LOAD segment
U64 load_segment_off = 0;
{
U64 segment_cursor = segment_foff;
U64 segment_opl = segment_foff + segment_size*segment_count;
for (;segment_cursor < segment_opl; segment_cursor += segment_size){
U32 p_type = *(U32*)(elf_data.str + segment_cursor);
if (p_type == ELF_SegmentType_LOAD){
load_segment_off = segment_cursor;
break;
}
}
}
// use the segment's p_vaddr to determine vbase
if (load_segment_off != 0){
switch (elf_class){
case ELF_Class_32:
{
ELF_Phdr32 *phdr = (ELF_Phdr32*)(elf_data.str + load_segment_off);
vbase = phdr->p_vaddr;
}break;
case ELF_Class_64:
{
ELF_Phdr64 *phdr = (ELF_Phdr64*)(elf_data.str + load_segment_off);
vbase = phdr->p_vaddr;
}break;
}
}
}
//- locate the section header string table
U64 section_name_table_foff = 0;
U64 section_name_table_opl = 0;
if (header_is_good){
if (section_header_string_table_index < section_count){
U64 sec_foff = section_foff + section_header_string_table_index*section_size;
switch (elf_class){
case ELF_Class_32:
{
ELF_Shdr32 *shdr = (ELF_Shdr32*)(elf_data.str + sec_foff);
section_name_table_foff = shdr->sh_offset;
section_name_table_opl = shdr->sh_offset + shdr->sh_size;
}break;
case ELF_Class_64:
{
ELF_Shdr64 *shdr = (ELF_Shdr64*)(elf_data.str + sec_foff);
section_name_table_foff = shdr->sh_offset;
section_name_table_opl = shdr->sh_offset + shdr->sh_size;
}break;
}
}
}
//- format sections data
ELF_Shdr64 *sections = 0;
if (header_is_good && section_count > 0){
switch (elf_class){
case ELF_Class_32:
{
sections = push_array(arena, ELF_Shdr64, section_count);
{
ELF_Shdr32 *shdr32 = (ELF_Shdr32*)(elf_data.str + section_foff);
ELF_Shdr64 *shdr64 = sections;
for (U64 i = 0; i < section_count; i += 1, shdr32 += 1, shdr64 += 1){
shdr64->sh_name = shdr32->sh_name;
shdr64->sh_type = shdr32->sh_type;
shdr64->sh_flags = shdr32->sh_flags;
shdr64->sh_addr = shdr32->sh_addr;
shdr64->sh_offset = shdr32->sh_offset;
shdr64->sh_size = shdr32->sh_size;
shdr64->sh_link = shdr32->sh_link;
shdr64->sh_info = shdr32->sh_info;
shdr64->sh_addralign = shdr32->sh_addralign;
shdr64->sh_entsize = shdr32->sh_entsize;
}
}
}break;
case ELF_Class_64:
{
sections = (ELF_Shdr64*)(elf_data.str + section_foff);
}break;
}
}
//- extract section names
String8 *section_names = 0;
if (sections != 0 && section_count > 0){
U8 *string_table_opl = elf_data.str + section_name_table_opl;
section_names = push_array(arena, String8, section_count);
String8 *sec_name = section_names;
ELF_Shdr64 *sec = sections;
for (U64 i = 0;
i < section_count;
i += 1, sec += 1, sec_name += 1){
U64 name_foff = section_name_table_foff + sec->sh_name;
if (section_name_table_foff <= name_foff && name_foff < section_name_table_opl){
U8 *base = elf_data.str + name_foff;
U8 *opl = base;
for (;opl < string_table_opl && *opl != 0; opl += 1);
sec_name->str = base;
sec_name->size = (U64)(opl - base);
}
}
}
//- format segments data
ELF_Phdr64 *segments = 0;
if (header_is_good && segment_count > 0){
switch (elf_class){
case ELF_Class_32:
{
segments = push_array(arena, ELF_Phdr64, segment_count);
{
ELF_Phdr32 *phdr32 = (ELF_Phdr32*)(elf_data.str + segment_foff);
ELF_Phdr64 *phdr64 = segments;
for (U64 i = 0; i < segment_count; i += 1, phdr32 += 1, phdr64 += 1){
phdr64->p_type = phdr32->p_type;
phdr64->p_flags = phdr32->p_flags;
phdr64->p_offset = phdr32->p_offset;
phdr64->p_vaddr = phdr32->p_vaddr;
phdr64->p_paddr = phdr32->p_paddr;
phdr64->p_filesz = phdr32->p_filesz;
phdr64->p_memsz = phdr32->p_memsz;
phdr64->p_align = phdr32->p_align;
}
}
}break;
case ELF_Class_64:
{
segments = (ELF_Phdr64*)(elf_data.str + segment_foff);
}break;
}
}
//- find special sections
U64 strtab_idx = 0;
U64 symtab_idx = 0;
U64 dynsym_idx = 0;
if (section_names != 0){
for (U64 i = 0; i < section_count; i += 1){
String8 name = section_names[i];
if (str8_match(name, str8_lit(".strtab"), 0)){
strtab_idx = i;
}
else if (str8_match(name, str8_lit(".symtab"), 0)){
symtab_idx = i;
}
else if (str8_match(name, str8_lit(".dynsym"), 0)){
dynsym_idx = i;
}
}
}
//- fill result
ELF_Parsed *result = 0;
if (header_is_good){
result = push_array(arena, ELF_Parsed, 1);
result->data = elf_data;
result->elf_class = elf_class;
result->arch = arch;
result->sections = sections;
result->section_names = section_names;
result->section_foff = section_foff;
result->section_count = section_count;
result->segments = segments;
result->segment_foff = segment_foff;
result->segment_count = segment_count;
result->vbase = vbase;
result->entry_vaddr = e_entry;
result->section_name_table_foff = section_name_table_foff;
result->section_name_table_opl = section_name_table_opl;
result->strtab_idx = strtab_idx;
result->symtab_idx = symtab_idx;
result->dynsym_idx = dynsym_idx;
}
return(result);
}
static ELF_SectionArray
elf_section_array_from_elf(ELF_Parsed *elf){
ELF_SectionArray result = {0};
if (elf != 0){
result.sections = elf->sections;
result.count = elf->section_count;
}
return(result);
}
static String8Array
elf_section_name_array_from_elf(ELF_Parsed *elf){
String8Array result = {0};
if (elf != 0){
result.strings = elf->section_names;
result.count = elf->section_count;
}
return(result);
}
static ELF_SegmentArray
elf_segment_array_from_elf(ELF_Parsed *elf){
ELF_SegmentArray result = {0};
if (elf != 0){
result.segments = elf->segments;
result.count = elf->segment_count;
}
return(result);
}
static String8
elf_section_name_from_name_offset(ELF_Parsed *elf, U64 offset){
String8 result = {0};
if (elf != 0){
if (offset > 0){
U64 foff = elf->section_name_table_foff + offset;
if (elf->section_name_table_foff <= foff && foff < elf->section_name_table_opl){
U8 *base = elf->data.str + foff;
U8 *section_opl = elf->data.str + elf->section_name_table_opl;
U8 *opl = base;
for (;opl < section_opl && *opl != 0; opl += 1);
result.str = base;
result.size = opl - base;
}
}
}
return(result);
}
static String8
elf_section_name_from_idx(ELF_Parsed *elf, U32 idx){
String8 result = {0};
if (elf != 0){
if (idx < elf->section_count){
result = elf->section_names[idx];
}
}
return(result);
}
static U32
elf_section_idx_from_name(ELF_Parsed *elf, String8 name){
U32 result = 0;
if (elf != 0){
String8 *sec_name = elf->section_names;
U64 count = elf->section_count;
for (U64 i = 0; i < count; i += 1, sec_name += 1){
if (str8_match(*sec_name, name, 0)){
result = i;
break;
}
}
}
return(result);
}
static String8
elf_section_data_from_idx(ELF_Parsed *elf, U32 idx){
String8 result = {0};
if (elf != 0){
if (idx < elf->section_count){
ELF_Shdr64 *shdr = elf->sections + idx;
U64 off_raw = shdr->sh_offset;
U64 size = shdr->sh_size;
if (shdr->sh_flags & ELF_SectionType_NOBITS){
size = 0;
}
U64 opl_raw = off_raw + size;
U64 opl = ClampTop(opl_raw, elf->data.size);
U64 off = ClampTop(off_raw, opl);
result.str = elf->data.str + off;
result.size = opl - off;
}
}
return(result);
}
static ELF_SymArray
elf_sym_array_from_data(Arena *arena, ELF_Class elf_class, String8 data){
// converge to sym64 layout
ELF_Sym64 *symbols = 0;
U64 count = 0;
switch (elf_class){
case ELF_Class_32:
{
count = data.size/sizeof(ELF_Sym32);
symbols = push_array(arena, ELF_Sym64, count);
{
ELF_Sym32 *sym32 = (ELF_Sym32*)(data.str);
ELF_Sym64 *sym64 = symbols;
for (U64 i = 0; i < count; i += 1, sym32 += 1, sym64 += 1){
sym64->st_name = sym32->st_name;
sym64->st_value = sym32->st_value;
sym64->st_size = sym32->st_size;
sym64->st_info = sym32->st_info;
sym64->st_other = sym32->st_other;
sym64->st_shndx = sym32->st_shndx;
}
}
}break;
case ELF_Class_64:
{
count = data.size/sizeof(ELF_Sym64);
symbols = (ELF_Sym64*)(data.str);
}break;
}
// fill result
ELF_SymArray result = {0};
result.symbols = symbols;
result.count = count;
return(result);
}
// string functions
static String8
elf_string_from_section_type(ELF_SectionType section_type){
String8 result = str8_lit("INVALID_SECTION_TYPE");
switch (section_type){
#define X(N,C) case C: result = str8_lit(#N); break;
ELF_SectionTypeXList(X)
#undef X
}
return(result);
}
static String8
elf_string_from_symbol_binding(ELF_SymbolBinding binding){
String8 result = str8_lit("INVALID_SYMBOL_BINDING");
switch (binding){
#define X(N,C) case C: result = str8_lit(#N); break;
ELF_SymbolBindingXList(X)
#undef X
}
return(result);
}
static String8
elf_string_from_symbol_type(ELF_SymbolType type){
String8 result = str8_lit("INVALID_SYMBOL_TYPE");
switch (type){
#define X(N,C) case C: result = str8_lit(#N); break;
ELF_SymbolTypeXList(X)
#undef X
}
return(result);
}
static String8
elf_string_from_symbol_visibility(ELF_SymbolVisibility visibility){
String8 result = str8_lit("INVALID_SYMBOL_VISIBILITY");
switch (visibility){
#define X(N,C) case C: result = str8_lit(#N); break;
ELF_SymbolVisibilityXList(X)
#undef X
}
return(result);
}
+517
View File
@@ -0,0 +1,517 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef RDI_ELF_H
#define RDI_ELF_H
// https://refspecs.linuxfoundation.org/elf/elf.pdf
////////////////////////////////
//~ Elf Format Types
// elf header
#define ELF_NIDENT 16
typedef struct ELF_Ehdr32{
U8 e_ident[ELF_NIDENT];
U16 e_type;
U16 e_machine;
U32 e_version;
U32 e_entry;
U32 e_phoff;
U32 e_shoff;
U32 e_flags;
U16 e_ehsize;
U16 e_phentsize;
U16 e_phnum;
U16 e_shentsize;
U16 e_shnum;
U16 e_shstrndx;
} ELF_Ehdr32;
typedef struct ELF_Ehdr64{
U8 e_ident[ELF_NIDENT];
U16 e_type;
U16 e_machine;
U32 e_version;
U64 e_entry;
U64 e_phoff;
U64 e_shoff;
U32 e_flags;
U16 e_ehsize;
U16 e_phentsize;
U16 e_phnum;
U16 e_shentsize;
U16 e_shnum;
U16 e_shstrndx;
} ELF_Ehdr64;
typedef enum ELF_Type{
ELF_Type_NONE = 0,
ELF_Type_REL = 1,
ELF_Type_EXEC = 2,
ELF_Type_DYN = 3,
ELF_Type_CORE = 4,
ELF_Type_LOOS = 0xfe00,
ELF_Type_HIOS = 0xfeff,
ELF_Type_LOPROC = 0xff00,
ELF_Type_HIPROC = 0xffff,
} ELF_Type;
typedef enum ELF_Machine{
ELF_Machine_NONE = 0,
ELF_Machine_M32 = 1,
ELF_Machine_SPARC = 2,
ELF_Machine_386 = 3,
ELF_Machine_68K = 4,
ELF_Machine_88K = 5,
ELF_Machine_860 = 7,
ELF_Machine_MIPS = 8,
ELF_Machine_S370 = 9,
ELF_Machine_MIPS_RS3_LE = 10,
ELF_Machine_PARISC = 15,
ELF_Machine_VPP500 = 17,
ELF_Machine_SPARC32PLUS = 18,
ELF_Machine_960 = 19,
ELF_Machine_PPC = 20,
ELF_Machine_PPC64 = 21,
ELF_Machine_S390 = 22,
ELF_Machine_V800 = 36,
ELF_Machine_FR20 = 37,
ELF_Machine_RH32 = 38,
ELF_Machine_RCE = 39,
ELF_Machine_ARM = 40,
ELF_Machine_ALPHA = 41,
ELF_Machine_SH = 42,
ELF_Machine_SPARCV9 = 43,
ELF_Machine_TRICORE = 44,
ELF_Machine_ARC = 45,
ELF_Machine_H8_300 = 46,
ELF_Machine_H8_300H = 47,
ELF_Machine_H8S = 48,
ELF_Machine_H8_500 = 49,
ELF_Machine_IA_64 = 50,
ELF_Machine_MIPS_X = 51,
ELF_Machine_COLDFIRE = 52,
ELF_Machine_68HC12 = 53,
ELF_Machine_MMA = 54,
ELF_Machine_PCP = 55,
ELF_Machine_NCPU = 56,
ELF_Machine_NDR1 = 57,
ELF_Machine_STARCORE = 58,
ELF_Machine_ME16 = 59,
ELF_Machine_ST100 = 60,
ELF_Machine_TINYJ = 61,
ELF_Machine_X86_64 = 62,
ELF_Machine_PDSP = 63,
ELF_Machine_PDP10 = 64,
ELF_Machine_PDP11 = 65,
ELF_Machine_FX66 = 66,
ELF_Machine_ST9PLUS = 67,
ELF_Machine_ST7 = 68,
ELF_Machine_68HC16 = 69,
ELF_Machine_68HC11 = 70,
ELF_Machine_68HC08 = 71,
ELF_Machine_68HC05 = 72,
ELF_Machine_SVX = 73,
ELF_Machine_ST19 = 74,
ELF_Machine_VAX = 75,
ELF_Machine_CRIS = 76,
ELF_Machine_JAVELIN = 77,
ELF_Machine_FIREPATH = 78,
ELF_Machine_ZSP = 79,
ELF_Machine_MMIX = 80,
ELF_Machine_HUANY = 81,
ELF_Machine_PRISM = 82,
ELF_Machine_AVR = 83,
ELF_Machine_FR30 = 84,
ELF_Machine_D10V = 85,
ELF_Machine_D30V = 86,
ELF_Machine_V850 = 87,
ELF_Machine_M32R = 88,
ELF_Machine_MN10300 = 89,
ELF_Machine_MN10200 = 90,
ELF_Machine_PJ = 91,
ELF_Machine_OPENRISC = 92,
ELF_Machine_ARC_A5 = 93,
ELF_Machine_XTENSA = 94,
ELF_Machine_VIDEOCORE = 95,
ELF_Machine_TMM_GPP = 96,
ELF_Machine_NS32K = 97,
ELF_Machine_TPC = 98,
ELF_Machine_SNP1K = 99,
ELF_Machine_ST200 = 100,
} ELF_Machine;
typedef enum ELF_Version{
ELF_Version_NONE = 0,
ELF_Version_CURRENT = 1,
} ELF_Version;
typedef enum ELF_Identification{
ELF_Identification_MAG0 = 0,
ELF_Identification_MAG1 = 1,
ELF_Identification_MAG2 = 2,
ELF_Identification_MAG3 = 3,
ELF_Identification_CLASS = 4,
ELF_Identification_DATA = 5,
ELF_Identification_VERSION = 6,
ELF_Identification_OSABI = 7,
ELF_Identification_ABIVERSION = 8,
ELF_Identification_PAD = 9,
} ELF_Identification;
read_only global U8 elf_magic[] = {0x7F, 'E', 'L', 'F'};
typedef enum ELF_Class{
ELF_Class_NONE = 0,
ELF_Class_32 = 1,
ELF_Class_64 = 2,
} ELF_Class;
typedef enum ELF_DataEncoding{
ELF_DataEncoding_NONE = 0,
ELF_DataEncoding_2LSB = 1,
ELF_DataEncoding_2MSB = 2,
} ELF_DataEncoding;
typedef enum ELF_OsAbi{
ELF_OsAbi_NONE = 0,
ELF_OsAbi_HPUX = 1,
ELF_OsAbi_NETBSD = 2,
ELF_OsAbi_LINUX = 3,
ELF_OsAbi_SOLARIS = 6,
ELF_OsAbi_AIX = 7,
ELF_OsAbi_IRIX = 8,
ELF_OsAbi_FREEBSD = 9,
ELF_OsAbi_TRU64 = 10,
ELF_OsAbi_MODESTO = 11,
ELF_OsAbi_OPENBSD = 12,
ELF_OsAbi_OPENVMS = 13,
ELF_OsAbi_NSK = 14,
} ELF_OsAbi;
// sections
typedef enum ELF_ReservedSectionIndex{
ELF_ReservedSectionIndex_UNDEF = 0,
ELF_ReservedSectionIndex_LORESERVE = 0xFF00,
ELF_ReservedSectionIndex_LOPROC = 0xFF00,
ELF_ReservedSectionIndex_HIPROC = 0xFF1F,
ELF_ReservedSectionIndex_LOOS = 0xFF20,
ELF_ReservedSectionIndex_HIOS = 0xFF3F,
ELF_ReservedSectionIndex_ABS = 0xFFF1,
ELF_ReservedSectionIndex_COMMON = 0xFFF2,
ELF_ReservedSectionIndex_XINDEX = 0xFFFF,
ELF_ReservedSectionIndex_HIRESERVE = 0xFFFF,
} ELF_ReservedSectionIndex;
typedef struct ELF_Shdr32{
U32 sh_name;
U32 sh_type;
U32 sh_flags;
U32 sh_addr;
U32 sh_offset;
U32 sh_size;
U32 sh_link;
U32 sh_info;
U32 sh_addralign;
U32 sh_entsize;
} ELF_Shdr32;
typedef struct ELF_Shdr64{
U32 sh_name;
U32 sh_type;
U64 sh_flags;
U64 sh_addr;
U64 sh_offset;
U64 sh_size;
U32 sh_link;
U32 sh_info;
U64 sh_addralign;
U64 sh_entsize;
} ELF_Shdr64;
// X(name, code)
#define ELF_SectionTypeXList(X)\
X(NULL, 0)\
X(PROGBITS, 1)\
X(SYMTAB, 2)\
X(STRTAB, 3)\
X(RELA, 4)\
X(HASH, 5)\
X(DYNAMIC, 6)\
X(NOTE, 7)\
X(NOBITS, 8)\
X(REL, 9)\
X(SHLIB, 10)\
X(DYNSYM, 11)\
X(INIT_ARRAY, 14)\
X(FINI_ARRAY, 15)\
X(PREINIT_ARRAY, 16)\
X(GROUP, 17)\
X(SYMTAB_SHNDX, 18)\
X(LOOS, 0x60000000)\
X(HIOS, 0x6FFFFFFF)\
X(LOPROC, 0x70000000)\
X(HIPROC, 0x7FFFFFFF)\
X(LOUSER, 0x80000000)\
X(HIUSER, 0x8FFFFFFF)
typedef enum ELF_SectionType{
#define X(N,C) ELF_SectionType_##N = C,
ELF_SectionTypeXList(X)
#undef X
} ELF_SectionType;
typedef enum ELF_SectionAttributeFlags{
ELF_SectionAttributeFlag_WRITE = 0x001,
ELF_SectionAttributeFlag_ALLOC = 0x002,
ELF_SectionAttributeFlag_EXECINSTR = 0x004,
ELF_SectionAttributeFlag_MERGE = 0x010,
ELF_SectionAttributeFlag_STRINGS = 0x020,
ELF_SectionAttributeFlag_INFO_LINK = 0x040,
ELF_SectionAttributeFlag_LINK_ORDER = 0x080,
ELF_SectionAttributeFlag_OS_NONCONFORMING = 0x100,
ELF_SectionAttributeFlag_GROUP = 0x200,
ELF_SectionAttributeFlag_TLS = 0x400,
ELF_SectionAttributeFlag_MASKOS = 0x0FF00000,
ELF_SectionAttributeFlag_MASKPROC = 0xF0000000,
} ELF_SectionAttributeFlags;
typedef enum ELF_SectionGroupFlags{
ELF_SectionGroupFlag_COMDAT = 0x1,
ELF_SectionGroupFlag_MASKOS = 0x0FF00000,
ELF_SectionGroupFlag_MASKPROC = 0xF0000000,
} ELF_SectionGroupFlags;
typedef enum ELF_ReservedSymbolTableIndex{
ELF_ReservedSymbolTableIndex_UNDEF = 0,
} ELF_ReservedSymbolTableIndex;
// symbol table
typedef struct ELF_Sym32{
U32 st_name;
U32 st_value;
U32 st_size;
U8 st_info;
U8 st_other;
U16 st_shndx;
} ELF_Sym32;
typedef struct ELF_Sym64{
U32 st_name;
U8 st_info;
U8 st_other;
U16 st_shndx;
U64 st_value;
U64 st_size;
} ELF_Sym64;
#define ELF_SymBindingFromInfo(x) (ELF_SymbolBinding)((x)>>4)
#define ELF_SymTypeFromInfo(x) (ELF_SymbolType)((x)&0xF)
#define ELF_SymInfoFromBindingType(b,t) ((((b)<<4)&0xF)|((t)&0xF))
#define ELF_SymVisibilityFromOther(x) ((x)&0x3)
#define ELF_SymOtherFromVisibility(x) ((x)&0x3)
#define ELF_SymbolBindingXList(X)\
X(LOCAL, 0)\
X(GLOBAL, 1)\
X(WEAK, 2)\
X(LOOS, 10)\
X(HIOS, 12)\
X(LOPROC, 13)\
X(HIPROC, 15)\
typedef enum ELF_SymbolBinding{
#define X(N,C) ELF_SymbolBinding_##N = C,
ELF_SymbolBindingXList(X)
#undef X
} ELF_SymbolBinding;
#define ELF_SymbolTypeXList(X)\
X(NOTYPE, 0)\
X(OBJECT, 1)\
X(FUNC, 2)\
X(SECTION, 3)\
X(FILE, 4)\
X(COMMON, 5)\
X(TLS, 6)\
X(LOOS, 10)\
X(HIOS, 12)\
X(LOPROC, 13)\
X(HIPROC, 15)
typedef enum ELF_SymbolType{
#define X(N,C) ELF_SymbolType_##N = C,
ELF_SymbolTypeXList(X)
#undef X
} ELF_SymbolType;
#define ELF_SymbolVisibilityXList(X)\
X(DEFAULT, 0)\
X(INTERNAL, 1)\
X(HIDDEN, 2)\
X(PROTECTED, 3)
typedef enum ELF_SymbolVisibility{
#define X(N,C) ELF_SymbolVisibility_##N = C,
ELF_SymbolVisibilityXList(X)
#undef X
} ELF_SymbolVisibility;
// relocation
typedef struct ELF_Rel32{
U32 r_offset;
U32 r_info;
} ELF_Rel32;
typedef struct ELF_Rela32{
U32 r_offset;
U32 r_info;
S32 r_addend;
} ELF_Rela32;
typedef struct ELF_Rel64{
U64 r_offset;
U64 r_info;
} ELF_Rel64;
typedef struct ELF_Rela64{
U64 r_offset;
U64 r_info;
S64 r_addend;
} ELF_Rela64;
#define ELF_RelSymIndexFromInfo32(x) ((x)>>8)
#define ELF_RelTypeFromInfo32(x) ((x)&0xF)
#define ELF_RelInfoFromSymIndexType32(n,t) (((n)<<8)|((t)&0xF))
#define ELF_RelSymIndexFromInfo64(x) ((x)>>32)
#define ELF_RelTypeFromInfo64(x) ((x)&0xFFFFFFFFL)
#define ELF_RelInfoFromSymIndexType64(n,t) (((n)<<8)|((t)&0xFFFFFFFFL))
// program header
typedef struct ELF_Phdr32{
U32 p_type;
U32 p_offset;
U32 p_vaddr;
U32 p_paddr;
U32 p_filesz;
U32 p_memsz;
U32 p_flags;
U32 p_align;
} ELF_Phdr32;
typedef struct ELF_Phdr64{
U32 p_type;
U32 p_flags;
U64 p_offset;
U64 p_vaddr;
U64 p_paddr;
U64 p_filesz;
U64 p_memsz;
U64 p_align;
} ELF_Phdr64;
typedef enum ELF_SegmentType{
ELF_SegmentType_NULL = 0,
ELF_SegmentType_LOAD = 1,
ELF_SegmentType_DYNAMIC = 2,
ELF_SegmentType_INTERP = 3,
ELF_SegmentType_NOTE = 4,
ELF_SegmentType_SHLIB = 5,
ELF_SegmentType_PHDR = 6,
ELF_SegmentType_TLS = 7,
ELF_SegmentType_LOOS = 0x60000000,
ELF_SegmentType_HIOS = 0x6fffffff,
ELF_SegmentType_LOPROC = 0x70000000,
ELF_SegmentType_HIPROC = 0x7fffffff,
} ELF_SegmentType;
typedef enum ELF_SegmentFlags{
ELF_SegmentFlag_X = 0x1,
ELF_SegmentFlag_W = 0x2,
ELF_SegmentFlag_R = 0x4,
ELF_SegmentFlag_MASKOS = 0x0FF00000,
ELF_SegmentFlag_MASKPROC = 0xF0000000,
} ELF_SegmentFlags;
////////////////////////////////
//~ ELF Parser Types
// elf top level
typedef struct ELF_SectionArray{
ELF_Shdr64 *sections;
U64 count;
} ELF_SectionArray;
typedef struct ELF_SegmentArray{
ELF_Phdr64 *segments;
U64 count;
} ELF_SegmentArray;
typedef struct ELF_Parsed{
String8 data;
ELF_Class elf_class;
Architecture arch;
ELF_Shdr64 *sections;
String8 *section_names;
U64 section_foff;
U64 section_count;
ELF_Phdr64 *segments;
U64 segment_foff;
U64 segment_count;
U64 vbase;
U64 entry_vaddr;
U64 section_name_table_foff;
U64 section_name_table_opl;
U64 strtab_idx;
U64 symtab_idx;
U64 dynsym_idx;
} ELF_Parsed;
// elf symtab
typedef struct ELF_SymArray{
ELF_Sym64 *symbols;
U64 count;
} ELF_SymArray;
////////////////////////////////
//~ ELF Parser Functions
static ELF_Parsed* elf_parsed_from_data(Arena *arena, String8 elf_data);
static ELF_SectionArray elf_section_array_from_elf(ELF_Parsed *elf);
static String8Array elf_section_name_array_from_elf(ELF_Parsed *elf);
static ELF_SegmentArray elf_segment_array_from_elf(ELF_Parsed *elf);
static String8 elf_section_name_from_name_offset(ELF_Parsed *elf, U64 offset);
static String8 elf_section_name_from_idx(ELF_Parsed *elf, U32 idx);
static U32 elf_section_idx_from_name(ELF_Parsed *elf, String8 name);
static String8 elf_section_data_from_idx(ELF_Parsed *elf, U32 idx);
static ELF_SymArray elf_sym_array_from_data(Arena *arena, ELF_Class elf_class, String8 data);
// string functions
static String8 elf_string_from_section_type(ELF_SectionType section_type);
static String8 elf_string_from_symbol_binding(ELF_SymbolBinding binding);
static String8 elf_string_from_symbol_type(ELF_SymbolType type);
static String8 elf_string_from_symbol_visibility(ELF_SymbolVisibility visibility);
#endif //RDI_ELF_H
+884
View File
@@ -0,0 +1,884 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#include "lib_rdi_format/rdi_format.h"
#include "base/base_inc.h"
#include "os/os_inc.h"
#include "rdi_make_local/rdi_make_local.h"
#include "rdi_elf.h"
#include "rdi_dwarf.h"
#include "rdi_dwarf_stringize.h"
#include "rdi_from_dwarf.h"
#include "lib_rdi_format/rdi_format.c"
#include "base/base_inc.c"
#include "os/os_inc.c"
#include "rdi_make_local/rdi_make_local.c"
#include "rdi_elf.c"
#include "rdi_dwarf.c"
#include "rdi_dwarf_stringize.c"
// TODO(allen):
// [ ] need sample data for .debug_names
////////////////////////////////
//~ Program Parameters Parser
static DWARFCONV_Params*
dwarf_convert_params_from_cmd_line(Arena *arena, CmdLine *cmdline){
DWARFCONV_Params *result = push_array(arena, DWARFCONV_Params, 1);
result->unit_idx_max = ~0ull;
// get input pdb
{
String8 input_name = cmd_line_string(cmdline, str8_lit("elf"));
if (input_name.size == 0){
str8_list_push(arena, &result->errors,
str8_lit("missing required parameter '--elf:<elf_file>'"));
}
if (input_name.size > 0){
String8 input_data = os_data_from_file_path(arena, input_name);
if (input_data.size == 0){
str8_list_pushf(arena, &result->errors,
"could not load input file '%.*s'", str8_varg(input_name));
}
if (input_data.size != 0){
result->input_elf_name = input_name;
result->input_elf_data = input_data;
}
}
}
// get output name
{
result->output_name = cmd_line_string(cmdline, str8_lit("out"));
}
// error options
if (cmd_line_has_flag(cmdline, str8_lit("hide_errors"))){
String8List vals = cmd_line_strings(cmdline, str8_lit("hide_errors"));
// if no values - set all to hidden
if (vals.node_count == 0){
B8 *ptr = (B8*)&result->hide_errors;
B8 *opl = ptr + sizeof(result->hide_errors);
for (;ptr < opl; ptr += 1){
*ptr = 1;
}
}
// for each explicit value set the corresponding flag to hidden
for (String8Node *node = vals.first;
node != 0;
node = node->next){
if (str8_match(node->string, str8_lit("input"), 0)){
result->hide_errors.input = 1;
}
}
}
// unit idx selector
if (cmd_line_has_flag(cmdline, str8_lit("unit_idx"))){
String8List vals = cmd_line_strings(cmdline, str8_lit("unit_idx"));
// single value unit index
if (vals.node_count == 1){
U64 idx = u64_from_str8(vals.first->string, 10);
result->unit_idx_min = idx;
result->unit_idx_max = idx;
}
// range value unit index
else if (vals.node_count >= 2){
U64 idx_a = u64_from_str8(vals.first->string, 10);
U64 idx_b = u64_from_str8(vals.first->next->string, 10);
result->unit_idx_min = Min(idx_a, idx_b);
result->unit_idx_max = Max(idx_a, idx_b);
}
}
// dump options
if (cmd_line_has_flag(cmdline, str8_lit("dump"))){
result->dump = 1;
String8List vals = cmd_line_strings(cmdline, str8_lit("dump"));
if (vals.first == 0){
B8 *ptr = &result->dump__first;
for (; ptr < &result->dump__last; ptr += 1){
*ptr = 1;
}
}
else{
for (String8Node *node = vals.first;
node != 0;
node = node->next){
if (str8_match(node->string, str8_lit("header"), 0)){
result->dump_header = 1;
}
else if (str8_match(node->string, str8_lit("sections"), 0)){
result->dump_sections = 1;
}
else if (str8_match(node->string, str8_lit("segments"), 0)){
result->dump_segments = 1;
}
else if (str8_match(node->string, str8_lit("symtab"), 0)){
result->dump_symtab = 1;
}
else if (str8_match(node->string, str8_lit("dynsym"), 0)){
result->dump_dynsym = 1;
}
else if (str8_match(node->string, str8_lit("debug_sections"), 0)){
result->dump_debug_sections = 1;
}
else if (str8_match(node->string, str8_lit("debug_info"), 0)){
result->dump_debug_info = 1;
}
else if (str8_match(node->string, str8_lit("debug_abbrev"), 0)){
result->dump_debug_abbrev = 1;
}
else if (str8_match(node->string, str8_lit("debug_pubnames"), 0)){
result->dump_debug_pubnames = 1;
}
else if (str8_match(node->string, str8_lit("debug_pubtypes"), 0)){
result->dump_debug_pubtypes = 1;
}
else if (str8_match(node->string, str8_lit("debug_names"), 0)){
result->dump_debug_names = 1;
}
else if (str8_match(node->string, str8_lit("debug_aranges"), 0)){
result->dump_debug_aranges = 1;
}
else if (str8_match(node->string, str8_lit("debug_addr"), 0)){
result->dump_debug_addr = 1;
}
}
}
}
return(result);
}
////////////////////////////////
//~ Entry Point
static void
dump_symtab(Arena *arena, String8List *out, ELF_SymArray *symbols, String8 strtab,
U32 indent){
static char spaces[] = " ";
U8 *str_first = strtab.str;
U8 *str_opl = strtab.str + strtab.size;
ELF_Sym64 *symbol = symbols->symbols;
U64 count = symbols->count;
for (U64 i = 0; i < count; i += 1, symbol += 1){
U8 *name_first = str_first + symbol->st_name;
U8 *name_opl = name_first;
for (;name_opl < str_opl && *name_opl != 0;) name_opl += 1;
String8 name = str8_range(name_first, name_opl);
ELF_SymbolBinding binding = ELF_SymBindingFromInfo(symbol->st_info);
String8 binding_string = elf_string_from_symbol_binding(binding);
ELF_SymbolType type = ELF_SymTypeFromInfo(symbol->st_info);
String8 type_string = elf_string_from_symbol_type(type);
ELF_SymbolVisibility vis = ELF_SymVisibilityFromOther(symbol->st_other);
String8 vis_string = elf_string_from_symbol_visibility(vis);
str8_list_pushf(arena, out,
"%.*ssymbol[%5llu] %6.*s %7.*s %9.*s 0x%08llx size=%-5llu sec=%-5u "
"%.*s\n",
indent, spaces, i,
str8_varg(binding_string), str8_varg(type_string),
str8_varg(vis_string),
symbol->st_value, symbol->st_size,
symbol->st_shndx, str8_varg(name));
}
}
#if 0
static void
dump_entry_tree(Arena *arena, String8List *out,
DWARF_Parsed *dwarf, DWARF_InfoUnit *unit,
DWARF_InfoEntry *entry, U32 indent){
static char spaces[] = " ";
DWARF_AbbrevDecl *abbrev_decl = entry->abbrev_decl;
// tag
DWARF_Tag tag = abbrev_decl->tag;
String8 tag_string = dwarf_string_from_tag(tag);
str8_list_pushf(arena, out, "%.*sentry(@%llx) TAG %.*s\n",
indent, spaces, entry->info_offset, str8_varg(tag_string));
// attributes
U32 attrib_count = abbrev_decl->attrib_count;
DWARF_AbbrevAttribSpec *attrib_spec = abbrev_decl->attrib_specs;
DWARF_InfoAttribVal *attrib_val = entry->attrib_vals;
for (U32 i = 0; i < attrib_count; i += 1, attrib_spec += 1, attrib_val += 1){
// attribute name
DWARF_AttributeName name = attrib_spec->name;
String8 name_string = dwarf_string_from_attribute_name(name);
str8_list_pushf(arena, out, "%.*sATTR %.*s ", indent + 4, spaces, str8_varg(name_string));
// attribute value
switch (attrib_spec->form){
default:
{
String8 form_string = dwarf_string_from_attribute_form(attrib_spec->form);
str8_list_pushf(arena, out, "<form: %.*s> {%llu, 0x%p}\n",
str8_varg(form_string), attrib_val->val, attrib_val->dataptr);
}break;
case DWARF_AttributeForm_strp:
{
String8 str = {0};
String8 data = dwarf->debug_data[DWARF_SectionCode_Str];
U64 off = attrib_val->val;
if (off < data.size){
U8 *start = data.str + off;
U8 *opl = data.str + data.size;
U8 *ptr = start;
for (;ptr < opl && *ptr != 0;) ptr += 1;
str = str8_range(start, ptr);
}
str8_list_pushf(arena, out, "'%.*s'\n", str8_varg(str));
}break;
case DWARF_AttributeForm_sec_offset:
{
DWARF_AttributeClassFlags attr_classes1 = dwarf_attribute_class_from_name(name);
DWARF_AttributeClassFlags attr_classes2 = DWARF_AttributeClassFlag_sec_offset_classes;
DWARF_AttributeClassFlags attr_classes = attr_classes1&attr_classes2;
DWARF_SectionCode sec_code = DWARF_SectionCode_Null;
if (unit->dwarf_version == 5){
switch (attr_classes){
case DWARF_AttributeClassFlag_addrptr: sec_code = DWARF_SectionCode_Addr; break;
case DWARF_AttributeClassFlag_lineptr: sec_code = DWARF_SectionCode_Line; break;
case DWARF_AttributeClassFlag_loclist: sec_code = DWARF_SectionCode_LocLists; break;
case DWARF_AttributeClassFlag_loclistsptr: sec_code = DWARF_SectionCode_LocLists; break;
case DWARF_AttributeClassFlag_macptr: sec_code = DWARF_SectionCode_Macro; break;
case DWARF_AttributeClassFlag_rnglist: sec_code = DWARF_SectionCode_RngLists; break;
case DWARF_AttributeClassFlag_rnglistsptr: sec_code = DWARF_SectionCode_RngLists; break;
case DWARF_AttributeClassFlag_stroffsetsptr: sec_code = DWARF_SectionCode_StrOffsets; break;
}
}
else if (unit->dwarf_version == 4){
switch (attr_classes){
case DWARF_AttributeClassFlag_lineptr: sec_code = DWARF_SectionCode_Line; break;
case DWARF_AttributeClassFlag_loclist: sec_code = DWARF_SectionCode_Loc; break;
case DWARF_AttributeClassFlag_macptr: sec_code = DWARF_SectionCode_MacInfo; break;
case DWARF_AttributeClassFlag_rnglist: sec_code = DWARF_SectionCode_Ranges; break;
}
}
String8 sec_name = dwarf_name_from_debug_section(dwarf, sec_code);
str8_list_pushf(arena, out, "sec(%.*s) + %llu\n", str8_varg(sec_name), attrib_val->val);
}break;
case DWARF_AttributeForm_ref1:
case DWARF_AttributeForm_ref2:
case DWARF_AttributeForm_ref4:
case DWARF_AttributeForm_ref8:
case DWARF_AttributeForm_ref_udata:
{
str8_list_pushf(arena, out, "entry(@%llx)\n", attrib_val->val);
}break;
case DWARF_AttributeForm_addr:
{
str8_list_pushf(arena, out, "0x%llx\n", attrib_val->val);
}break;
case DWARF_AttributeForm_exprloc:
{
str8_list_pushf(arena, out, "expression\n");
// TODO(allen): dwarf expression dumping
}break;
case DWARF_AttributeForm_strx1:
case DWARF_AttributeForm_strx2:
case DWARF_AttributeForm_strx3:
case DWARF_AttributeForm_strx4:
{
String8 str = {0};
U32 idx = attrib_val->val;
U64 str_offsets_off = unit->str_offsets_base + idx*unit->offset_size;
String8 str_offsets = dwarf->debug_data[DWARF_SectionCode_StrOffsets];
if (str_offsets_off + unit->offset_size < str_offsets.size){
U64 off = 0;
MemoryCopy(&off, str_offsets.str + str_offsets_off, unit->offset_size);
String8 data = dwarf->debug_data[DWARF_SectionCode_Str];
if (off < data.size){
U8 *start = data.str + off;
U8 *opl = data.str + data.size;
U8 *ptr = start;
for (;ptr < opl && *ptr != 0;) ptr += 1;
str = str8_range(start, ptr);
}
}
str8_list_pushf(arena, out, "'%.*s'\n", str8_varg(str));
}break;
case DWARF_AttributeForm_addrx:
case DWARF_AttributeForm_addrx1:
case DWARF_AttributeForm_addrx2:
case DWARF_AttributeForm_addrx3:
case DWARF_AttributeForm_addrx4:
{
U64 address = 0;
U32 idx = attrib_val->val;
U64 address_off = unit->addr_base + idx*unit->address_size;
String8 data = dwarf->debug_data[DWARF_SectionCode_Addr];
if (address_off + unit->address_size < data.size){
MemoryCopy(&address, data.str + address_off, unit->address_size);
}
str8_list_pushf(arena, out, "0x%x\n", address);
}break;
case DWARF_AttributeForm_rnglistx:
{
U64 rnglist_off = unit->rnglists_base + attrib_val->val;
int x = 0;
}break;
case DWARF_AttributeForm_data1:
case DWARF_AttributeForm_data2:
case DWARF_AttributeForm_data4:
case DWARF_AttributeForm_data8:
case DWARF_AttributeForm_data16:
case DWARF_AttributeForm_udata:
case DWARF_AttributeForm_implicit_const:
case DWARF_AttributeForm_flag:
case DWARF_AttributeForm_flag_present:
{
str8_list_pushf(arena, out, "%llu\n", attrib_val->val);
}break;
case DWARF_AttributeForm_sdata:
{
str8_list_pushf(arena, out, "%lld\n", (S64)attrib_val->val);
}break;
case DWARF_AttributeForm_string:
{
str8_list_pushf(arena, out, "'%.*s'\n", (int)attrib_val->val, attrib_val->dataptr);
}break;
}
}
// dump children
for (DWARF_InfoEntry *child = entry->first_child;
child != 0;
child = child->next_sibling){
dump_entry_tree(arena, out, dwarf, unit, child, indent + 1);
}
}
#endif
internal void
entry_point(CmdLine *cmd_line)
{
Arena *arena = arena_alloc();
// parse arguments
DWARFCONV_Params *params = dwarf_convert_params_from_cmd_line(arena, cmd_line);
// show input errors
if (params->errors.node_count > 0 &&
!params->hide_errors.input){
for (String8Node *node = params->errors.first;
node != 0;
node = node->next){
fprintf(stdout, "error(input): %.*s\n", str8_varg(node->string));
}
}
// will we try to parse an input file?
B32 try_parse_input = (params->errors.node_count == 0);
// track parse success
B32 successful_parse = 1;
#define PARSE_CHECK_ERROR(p,fmt,...) do{ if ((p) == 0){ \
successful_parse = 0; \
fprintf(stdout, "error(parsing): " fmt "\n", __VA_ARGS__); \
} }while(0)
// parse elf
ELF_Parsed *elf = 0;
if (try_parse_input) ProfScope("parse elf"){
elf = elf_parsed_from_data(arena, params->input_elf_data);
PARSE_CHECK_ERROR(elf, "ELF");
}
// parse strtab
String8 strtab = {0};
if (elf != 0) ProfScope("parse strtab"){
strtab = elf_section_data_from_idx(elf, elf->strtab_idx);
}
// parse symtab
ELF_SymArray symtab = {0};
if (elf != 0) ProfScope("parse symtab"){
String8 data = elf_section_data_from_idx(elf, elf->symtab_idx);
symtab = elf_sym_array_from_data(arena, elf->elf_class, data);
}
// parse dynsym
ELF_SymArray dynsym = {0};
if (elf != 0) ProfScope("parse dynsym"){
String8 data = elf_section_data_from_idx(elf, elf->dynsym_idx);
dynsym = elf_sym_array_from_data(arena, elf->elf_class, data);
}
// parse dwarf
DWARF_Parsed *dwarf = 0;
if (elf != 0) ProfScope("parse dwarf"){
dwarf = dwarf_parsed_from_elf(arena, elf);
PARSE_CHECK_ERROR(dwarf, "DWARF");
}
// parse info
DWARF_InfoParsed *info = 0;
if (dwarf != 0){
String8 data = dwarf->debug_data[DWARF_SectionCode_Info];
if (data.size > 0) ProfScope("parse .debug_info"){
info = dwarf_info_from_data(arena, data);
PARSE_CHECK_ERROR(info, "DEBUG INFO");
}
}
// parse pubnames
DWARF_PubNamesParsed *pubnames = 0;
if (dwarf != 0){
String8 data = dwarf->debug_data[DWARF_SectionCode_PubNames];
if (data.size) ProfScope("parse .debug_pubnames"){
pubnames = dwarf_pubnames_from_data(arena, data);
PARSE_CHECK_ERROR(pubnames, "DEBUG PUBNAMES");
}
}
// parse pubtypes
DWARF_PubNamesParsed *pubtypes = 0;
if (dwarf != 0){
String8 data = dwarf->debug_data[DWARF_SectionCode_PubTypes];
if (data.size) ProfScope("parse .debug_pubtypes"){
pubtypes = dwarf_pubnames_from_data(arena, data);
PARSE_CHECK_ERROR(pubtypes, "DEBUG PUBTYPES");
}
}
// parse names
DWARF_NamesParsed *names = 0;
if (dwarf != 0){
String8 data = dwarf->debug_data[DWARF_SectionCode_Names];
if (data.size) ProfScope("parse .debug_names"){
names = dwarf_names_from_data(arena, data);
PARSE_CHECK_ERROR(names, "DEBUG NAMES");
}
}
// parse aranges
DWARF_ArangesParsed *aranges = 0;
if (dwarf != 0){
String8 data = dwarf->debug_data[DWARF_SectionCode_Aranges];
if (data.size) ProfScope("parse .debug_aranges"){
aranges = dwarf_aranges_from_data(arena, data);
PARSE_CHECK_ERROR(aranges, "DEBUG ARANGES");
}
}
// parse addr
DWARF_AddrParsed *addr = 0;
if (dwarf != 0){
String8 data = dwarf->debug_data[DWARF_SectionCode_Addr];
if (data.size) ProfScope("parse .debug_addr"){
addr = dwarf_addr_from_data(arena, data);
PARSE_CHECK_ERROR(addr, "DEBUG ADDR");
}
}
#if 0
// parse abbrev
DWARF_AbbrevParsed *abbrev = 0;
if (dwarf != 0){
String8 data = dwarf->debug_data[DWARF_SectionCode_Abbrev];
if (data.size > 0) ProfScope("parse .debug_abbrev"){
DWARF_AbbrevParams abbrev_params = {0};
abbrev_params.unit_idx_min = params->unit_idx_min;
abbrev_params.unit_idx_max = params->unit_idx_max;
abbrev = dwarf_abbrev_from_data(arena, data, &abbrev_params);
PARSE_CHECK_ERROR(abbrev, "DEBUG ABBREV");
}
}
// parse info
DWARF_InfoParsed *info = 0;
if (abbrev != 0){
String8 data = dwarf->debug_data[DWARF_SectionCode_Info];
if (data.size > 0) ProfScope("parse .debug_info"){
DWARF_InfoParams info_params = {0};
info_params.unit_idx_min = params->unit_idx_min;
info_params.unit_idx_max = params->unit_idx_max;
info = dwarf_info_from_data(arena, data, &info_params, abbrev);
PARSE_CHECK_ERROR(info, "DEBUG INFO");
}
}
#endif
// dump
if (params->dump) ProfScope("dump"){
String8List dump = {0};
// ELF
if (params->dump_header){
if (elf != 0){
str8_list_push(arena, &dump,
str8_lit("################################"
"################################\n"
"ELF:\n"));
// TODO: better stringizers for fields here
str8_list_pushf(arena, &dump, " elf_class=%u\n", elf->elf_class);
str8_list_pushf(arena, &dump, " arch=%u\n", elf->arch);
str8_list_pushf(arena, &dump, " section_count=%llu\n", elf->section_count);
str8_list_pushf(arena, &dump, " segment_count=%llu\n", elf->segment_count);
str8_list_pushf(arena, &dump, " vbase=0x%llx\n", elf->vbase);
str8_list_pushf(arena, &dump, " entry_vaddr=0x%llx\n", elf->vbase);
str8_list_push(arena, &dump, str8_lit("\n"));
}
}
// SECTIONS
if (params->dump_sections){
if (elf != 0){
ELF_SectionArray section_array = elf_section_array_from_elf(elf);
String8Array section_name_array = elf_section_name_array_from_elf(elf);
str8_list_push(arena, &dump,
str8_lit("################################"
"################################\n"
"SECTIONS:\n"));
ELF_Shdr64 *sec = section_array.sections;
String8 *sec_name = section_name_array.strings;
U64 count = section_array.count;
for (U64 i = 0 ; i < count; i += 1, sec += 1, sec_name += 1){
String8 type_string = elf_string_from_section_type(sec->sh_type);
// TODO: better stringizers for fields here
str8_list_pushf(arena, &dump, " section[%llu]:\n", i);
str8_list_pushf(arena, &dump, " name='%.*s'\n", str8_varg(*sec_name));
str8_list_pushf(arena, &dump, " type=%.*s\n", str8_varg(type_string));
str8_list_pushf(arena, &dump, " flags=0x%llx\n", sec->sh_flags);
str8_list_pushf(arena, &dump, " addr=0x%llx\n", sec->sh_addr);
str8_list_pushf(arena, &dump, " offset=0x%llx\n", sec->sh_offset);
str8_list_pushf(arena, &dump, " size=%llu\n", sec->sh_size);
str8_list_pushf(arena, &dump, " link=%u\n", sec->sh_link);
str8_list_pushf(arena, &dump, " info=%u\n", sec->sh_info);
str8_list_pushf(arena, &dump, " addralign=0x%llx\n", sec->sh_addralign);
str8_list_pushf(arena, &dump, " entsize=%llu\n", sec->sh_entsize);
str8_list_push(arena, &dump, str8_lit("\n"));
}
}
}
// SYMTAB
if (symtab.count > 0 && params->dump_symtab){
str8_list_push(arena, &dump,
str8_lit("################################"
"################################\n"
"SYMTAB:\n"));
str8_list_pushf(arena, &dump, " section: %llu\n", elf->symtab_idx);
dump_symtab(arena, &dump, &symtab, strtab, 1);
str8_list_push(arena, &dump, str8_lit("\n"));
}
// DYNSYM
if (dynsym.count > 0 && params->dump_dynsym){
str8_list_push(arena, &dump,
str8_lit("################################"
"################################\n"
"DYNSYM:\n"));
str8_list_pushf(arena, &dump, " section: %llu\n", elf->dynsym_idx);
dump_symtab(arena, &dump, &dynsym, strtab, 1);
str8_list_push(arena, &dump, str8_lit("\n"));
}
// SEGMENTS
if (params->dump_segments){
if (elf != 0){
ELF_SegmentArray segment_array = elf_segment_array_from_elf(elf);
str8_list_push(arena, &dump,
str8_lit("################################"
"################################\n"
"SEGMENTS:\n"));
ELF_Phdr64 *segments = segment_array.segments;
U64 count = segment_array.count;
for (U64 i = 0 ; i < count; i += 1){
ELF_Phdr64 *seg = segments + i;
// TODO: better stringizers for fields here
str8_list_pushf(arena, &dump, " segment[%llu]:\n", i);
str8_list_pushf(arena, &dump, " p_type=%u\n", seg->p_type);
str8_list_pushf(arena, &dump, " p_flags=0x%x\n", seg->p_flags);
str8_list_pushf(arena, &dump, " p_offset=0x%llx\n", seg->p_offset);
str8_list_pushf(arena, &dump, " p_vaddr=0x%llx\n", seg->p_vaddr);
str8_list_pushf(arena, &dump, " p_paddr=0x%llx\n", seg->p_paddr);
str8_list_pushf(arena, &dump, " p_filesz=%llu\n", seg->p_filesz);
str8_list_pushf(arena, &dump, " p_memsz=%llu\n", seg->p_memsz);
str8_list_pushf(arena, &dump, " p_align=%llu\n", seg->p_align);
str8_list_push(arena, &dump, str8_lit("\n"));
}
}
}
// DEBUG SECTIONS
if (params->dump_debug_sections){
if (dwarf != 0){
str8_list_push(arena, &dump,
str8_lit("################################"
"################################\n"
"DEBUG SECTIONS:\n"));
U32 *debug_section_idx = dwarf->debug_section_idx;
String8 *debug_data = dwarf->debug_data;
for (U32 i = 1; i < DWARF_SectionCode_COUNT; i += 1, debug_data += 1){
U32 idx = debug_section_idx[i];
String8 name = dwarf_string_from_section_code(i);
str8_list_pushf(arena, &dump, " %-10.*s section_idx=%u\n", str8_varg(name), idx);
}
str8_list_push(arena, &dump, str8_lit("\n"));
}
}
// DEBUG INFO
if (params->dump_debug_info){
if (info != 0){
str8_list_push(arena, &dump,
str8_lit("################################"
"################################\n"
"DEBUG INFO:\n"));
U32 i = 0;
for (DWARF_InfoUnit *unit = info->unit_first;
unit != 0;
unit = unit->next, i += 1){
str8_list_pushf(arena, &dump, " unit[%u]:\n", i);
dwarf_stringize_info(arena, &dump, unit, 2);
str8_list_push(arena, &dump, str8_lit("\n"));
}
}
}
// DEBUG PUBNAMES
if (params->dump_debug_pubnames){
if (pubnames != 0){
str8_list_push(arena, &dump,
str8_lit("################################"
"################################\n"
"DEBUG PUBNAMES:\n"));
U32 i = 0;
for (DWARF_PubNamesUnit *unit = pubnames->unit_first;
unit != 0;
unit = unit->next, i += 1){
str8_list_pushf(arena, &dump, " unit[%u]:\n", i);
dwarf_stringize_pubnames(arena, &dump, unit, 2);
str8_list_push(arena, &dump, str8_lit("\n"));
}
}
}
// DEBUG PUBTYPES
if (params->dump_debug_pubtypes){
if (pubtypes != 0){
str8_list_push(arena, &dump,
str8_lit("################################"
"################################\n"
"DEBUG PUBTYPES:\n"));
U32 i = 0;
for (DWARF_PubNamesUnit *unit = pubtypes->unit_first;
unit != 0;
unit = unit->next, i += 1){
str8_list_pushf(arena, &dump, " unit[%u]:\n", i);
dwarf_stringize_pubnames(arena, &dump, unit, 2);
str8_list_push(arena, &dump, str8_lit("\n"));
}
}
}
// DEBUG NAMES
if (params->dump_debug_names){
if (names != 0){
str8_list_push(arena, &dump,
str8_lit("################################"
"################################\n"
"DEBUG NAMES:\n"));
U32 i = 0;
for (DWARF_NamesUnit *unit = names->unit_first;
unit != 0;
unit = unit->next, i += 1){
str8_list_pushf(arena, &dump, " unit[%u]:\n", i);
dwarf_stringize_names(arena, &dump, unit, 2);
str8_list_push(arena, &dump, str8_lit("\n"));
}
}
}
// DEBUG ARANGES
if (params->dump_debug_aranges){
if (aranges != 0){
str8_list_push(arena, &dump,
str8_lit("################################"
"################################\n"
"DEBUG ARANGES:\n"));
U32 i = 0;
for (DWARF_ArangesUnit *unit = aranges->unit_first;
unit != 0;
unit = unit->next, i += 1){
str8_list_pushf(arena, &dump, " unit[%u]:\n", i);
dwarf_stringize_aranges(arena, &dump, unit, 2);
str8_list_push(arena, &dump, str8_lit("\n"));
}
}
}
// DEBUG ADDR
if (params->dump_debug_addr){
if (addr != 0){
str8_list_push(arena, &dump,
str8_lit("################################"
"################################\n"
"DEBUG ADDR:\n"));
U32 i = 0;
for (DWARF_AddrUnit *unit = addr->unit_first;
unit != 0;
unit = unit->next, i += 1){
str8_list_pushf(arena, &dump, " unit[%u]:\n", i);
dwarf_stringize_addr(arena, &dump, unit, 2);
str8_list_push(arena, &dump, str8_lit("\n"));
}
}
}
#if 0
// DEBUG ABBREV
if (params->dump_debug_abbrev){
if (abbrev != 0){
str8_list_push(arena, &dump,
str8_lit("################################"
"################################\n"
"DEBUG ABBREV:\n"));
U32 i = 0;
for (DWARF_AbbrevUnit *unit = abbrev->unit_first;
unit != 0;
unit = unit->next, i += 1){
U32 j = 0;
for (DWARF_AbbrevDecl *abbrev_decl = unit->first;
abbrev_decl != 0;
abbrev_decl = abbrev_decl->next, j += 1){
String8 tag_string = dwarf_string_from_tag(abbrev_decl->tag);
str8_list_pushf(arena, &dump, " unit[%u],abbrev[%u]:\n", i, j);
str8_list_pushf(arena, &dump, " code=%llu\n", abbrev_decl->abbrev_code);
str8_list_pushf(arena, &dump, " tag=%.*s\n", str8_varg(tag_string));
str8_list_pushf(arena, &dump, " has_children=%u\n", abbrev_decl->has_children);
str8_list_pushf(arena, &dump, " attrib_count=%u\n", abbrev_decl->attrib_count);
str8_list_pushf(arena, &dump, " attribs:\n", abbrev_decl->attrib_count);
U32 attrib_count = abbrev_decl->attrib_count;
DWARF_AbbrevAttribSpec *attrib_spec = abbrev_decl->attrib_specs;
for (U32 k = 0; k < attrib_count; k += 1, attrib_spec += 1){
String8 name_string = dwarf_string_from_attribute_name(attrib_spec->name);
String8 form_string = dwarf_string_from_attribute_form(attrib_spec->form);
str8_list_pushf(arena, &dump, " [%-14.*s %-10.*s]\n",
str8_varg(name_string), str8_varg(form_string));
}
str8_list_push(arena, &dump, str8_lit("\n"));
}
}
}
}
#endif
#if 0
// DEBUG INFO
if (params->dump_debug_info){
if (info != 0){
str8_list_push(arena, &dump,
str8_lit("################################"
"################################\n"
"DEBUG INFO:\n"));
U32 i = 0;
for (DWARF_InfoUnit *unit = info->unit_first;
unit != 0;
unit = unit->next, i += 1){
str8_list_pushf(arena, &dump, " unit[%u]:\n", i);
str8_list_pushf(arena, &dump, " [header]\n");
str8_list_pushf(arena, &dump, " version=%u\n", unit->dwarf_version);
str8_list_pushf(arena, &dump, " offset_size=%u\n", unit->offset_size);
str8_list_pushf(arena, &dump, " address_size=%u\n", unit->address_size);
str8_list_pushf(arena, &dump, " [extracted attributes]\n");
str8_list_pushf(arena, &dump, " langauge=%u\n", (U32)unit->language);
str8_list_pushf(arena, &dump, " line_info_offset=%llu\n", unit->line_info_offset);
str8_list_pushf(arena, &dump, " vbase=0x%llx\n", unit->vbase);
str8_list_pushf(arena, &dump, " str_offsets_base=%llu\n", unit->str_offsets_base);
str8_list_pushf(arena, &dump, " addr_base=%llu\n", unit->addr_base);
str8_list_pushf(arena, &dump, " rnglists_base=%llu\n", unit->rnglists_base);
str8_list_pushf(arena, &dump, " loclists_base=%llu\n", unit->loclists_base);
dump_entry_tree(arena, &dump, dwarf, unit, unit->entry_root, 2);
str8_list_push(arena, &dump, str8_lit("\n"));
}
}
}
#endif
// print dump
for (String8Node *node = dump.first;
node != 0;
node = node->next){
fwrite(node->string.str, 1, node->string.size, stdout);
}
}
}
+50
View File
@@ -0,0 +1,50 @@
// 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
////////////////////////////////
//~ Program Parameters Type
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;
////////////////////////////////
//~ Program Parameters Parser
static DWARFCONV_Params *dwarf_convert_params_from_cmd_line(Arena *arena, CmdLine *cmdline);
#endif //RDI_FROM_DWARF_H