// Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) //////////////////////////////// //~ rjf: Build Options #define BUILD_VERSION_MAJOR 0 #define BUILD_VERSION_MINOR 9 #define BUILD_VERSION_PATCH 13 #define BUILD_RELEASE_PHASE_STRING_LITERAL "ALPHA" #define BUILD_TITLE "rdi_from_dwarf" #define BUILD_CONSOLE_INTERFACE 1 //////////////////////////////// //~ rjf: Includes //- rjf: [lib] #include "lib_rdi_format/rdi_format.h" #include "lib_rdi_format/rdi_format.c" #include "third_party/rad_lzb_simple/rad_lzb_simple.h" #include "third_party/rad_lzb_simple/rad_lzb_simple.c" //- rjf: [h] #include "base/base_inc.h" #include "os/os_inc.h" #include "rdi_make/rdi_make_local.h" #include "rdi_elf.h" #include "rdi_dwarf.h" #include "rdi_dwarf_stringize.h" #include "rdi_from_dwarf.h" //- rjf: [c] #include "base/base_inc.c" #include "os/os_inc.c" #include "rdi_make/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:'")); } 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, " {%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.v; 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); } } }