Files
raddebugger/src/coff/coff_dump.c
T
2025-06-19 16:48:07 -07:00

820 lines
33 KiB
C

// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#if 0
internal void
coff_print_archive_member_header(Arena *arena, String8List *out, String8 indent, COFF_ParsedArchiveMemberHeader header, String8 long_names)
{
Temp scratch = scratch_begin(&arena, 1);
String8 time_stamp = coff_string_from_time_stamp(scratch.arena, header.time_stamp);
rd_printf("Name : %S" , header.name );
rd_printf("Time Stamp: (%#x) %S" , header.time_stamp, time_stamp );
rd_printf("User ID : %u" , header.user_id );
rd_printf("Group ID : %u" , header.group_id);
rd_printf("Mode : %S" , header.mode );
rd_printf("Data : [%#llx-%#llx)", header.data_range.min, header.data_range.max);
scratch_end(scratch);
}
internal void
coff_print_section_table(Arena *arena,
String8List *out,
String8 indent,
String8 string_table,
COFF_Symbol32Array symbol_table,
U64 section_count,
COFF_SectionHeader *section_table)
{
Temp scratch = scratch_begin(&arena, 1);
String8 *symlinks = push_array(scratch.arena, String8, section_count);
for (U64 i = 0; i < symbol_table.count; ++i) {
COFF_Symbol32 *symbol = symbol_table.v+i;
COFF_SymbolValueInterpType interp = coff_interp_symbol(symbol->section_number, symbol->value, symbol->storage_class);
if (interp == COFF_SymbolValueInterp_Regular &&
symbol->aux_symbol_count == 0 &&
(symbol->storage_class == COFF_SymStorageClass_External || symbol->storage_class == COFF_SymStorageClass_Static)) {
if (symbol->section_number > 0 && symbol->section_number <= symbol_table.count) {
COFF_SectionHeader *header = section_table+(symbol->section_number-1);
if (header->flags & COFF_SectionFlag_LnkCOMDAT) {
symlinks[symbol->section_number-1] = coff_read_symbol_name(string_table, &symbol->name);
}
}
}
i += symbol->aux_symbol_count;
}
if (section_count) {
rd_printf("# Section Table");
rd_indent();
rd_printf("%-4s %-8s %-8s %-8s %-8s %-8s %-8s %-8s %-8s %-8s %-5s %-10s %s",
"No.",
"Name",
"VirtSize",
"VirtOff",
"FileSize",
"FileOff",
"RelocOff",
"LinesOff",
"RelocCnt",
"LineCnt",
"Align",
"Flags",
"Symlink");
for (U64 i = 0; i < section_count; ++i) {
COFF_SectionHeader *header = section_table+i;
String8 name = str8_cstring_capped(header->name, header->name+sizeof(header->name));
String8 full_name = coff_name_from_section_header(string_table, header);
String8 align;
{
U64 align_size = coff_align_size_from_section_flags(header->flags);
align = push_str8f(scratch.arena, "%u", align_size);
}
String8 flags;
{
String8List mem_flags = {0};
if (header->flags & COFF_SectionFlag_MemRead) {
str8_list_pushf(scratch.arena, &mem_flags, "r");
}
if (header->flags & COFF_SectionFlag_MemWrite) {
str8_list_pushf(scratch.arena, &mem_flags, "w");
}
if (header->flags & COFF_SectionFlag_MemExecute) {
str8_list_pushf(scratch.arena, &mem_flags, "x");
}
String8List cnt_flags = {0};
if (header->flags & COFF_SectionFlag_CntCode) {
str8_list_pushf(scratch.arena, &cnt_flags, "c");
}
if (header->flags & COFF_SectionFlag_CntInitializedData) {
str8_list_pushf(scratch.arena, &cnt_flags, "d");
}
if (header->flags & COFF_SectionFlag_CntUninitializedData) {
str8_list_pushf(scratch.arena, &cnt_flags, "u");
}
String8List mem_extra_flags = {0};
if (header->flags & COFF_SectionFlag_MemShared) {
str8_list_pushf(scratch.arena, &mem_flags, "s");
}
if (header->flags & COFF_SectionFlag_Mem16Bit) {
str8_list_pushf(scratch.arena, &mem_extra_flags, "h");
}
if (header->flags & COFF_SectionFlag_MemLocked) {
str8_list_pushf(scratch.arena, &mem_extra_flags, "l");
}
if (header->flags & COFF_SectionFlag_MemDiscardable) {
str8_list_pushf(scratch.arena, &mem_extra_flags, "d");
}
if (header->flags & COFF_SectionFlag_MemNotCached) {
str8_list_pushf(scratch.arena, &mem_extra_flags, "c");
}
if (header->flags & COFF_SectionFlag_MemNotPaged) {
str8_list_pushf(scratch.arena, &mem_extra_flags, "p");
}
String8List lnk_flags = {0};
if (header->flags & COFF_SectionFlag_LnkRemove) {
str8_list_pushf(scratch.arena, &lnk_flags, "r");
}
if (header->flags & COFF_SectionFlag_LnkCOMDAT) {
str8_list_pushf(scratch.arena, &lnk_flags, "c");
}
if (header->flags & COFF_SectionFlag_LnkOther) {
str8_list_pushf(scratch.arena, &lnk_flags, "o");
}
if (header->flags & COFF_SectionFlag_LnkInfo) {
str8_list_pushf(scratch.arena, &lnk_flags, "i");
}
if (header->flags & COFF_SectionFlag_LnkNRelocOvfl) {
str8_list_pushf(scratch.arena, &lnk_flags, "f");
}
String8List other_flags = {0};
if (header->flags & COFF_SectionFlag_TypeNoPad) {
str8_list_pushf(scratch.arena, &other_flags, "n");
}
if (header->flags & COFF_SectionFlag_GpRel) {
str8_list_pushf(scratch.arena, &other_flags, "g");
}
String8 mem = str8_list_join(scratch.arena, &mem_flags, 0);
String8 cnt = str8_list_join(scratch.arena, &cnt_flags, 0);
String8 lnk = str8_list_join(scratch.arena, &lnk_flags, 0);
String8 ext = str8_list_join(scratch.arena, &mem_extra_flags, 0);
String8 oth = str8_list_join(scratch.arena, &other_flags, 0);
String8List f = {0};
str8_list_push(scratch.arena, &f, mem);
str8_list_push(scratch.arena, &f, cnt);
str8_list_push(scratch.arena, &f, ext);
str8_list_push(scratch.arena, &f, lnk);
str8_list_push(scratch.arena, &f, oth);
flags = str8_list_join(scratch.arena, &f, &(StringJoin){ .sep = str8_lit("-") });
if (!flags.size) {
flags = str8_lit("none");
}
}
String8List l = {0};
str8_list_pushf(scratch.arena, &l, "%-4x", i+1 );
str8_list_pushf(scratch.arena, &l, "%-8S", name );
str8_list_pushf(scratch.arena, &l, "%08x", header->vsize );
str8_list_pushf(scratch.arena, &l, "%08x", header->voff );
str8_list_pushf(scratch.arena, &l, "%08x", header->fsize );
str8_list_pushf(scratch.arena, &l, "%08x", header->foff );
str8_list_pushf(scratch.arena, &l, "%08x", header->relocs_foff);
str8_list_pushf(scratch.arena, &l, "%08x", header->lines_foff );
str8_list_pushf(scratch.arena, &l, "%08x", header->reloc_count);
str8_list_pushf(scratch.arena, &l, "%08x", header->line_count );
str8_list_pushf(scratch.arena, &l, "%-5S", align );
str8_list_pushf(scratch.arena, &l, "%-10S", flags );
if (symlinks[i].size > 0) {
str8_list_pushf(scratch.arena, &l, "%S", symlinks[i]);
} else {
str8_list_pushf(scratch.arena, &l, "[no symlink]");
}
String8 line = str8_list_join(scratch.arena, &l, &(StringJoin){ .sep = str8_lit(" "), });
rd_printf("%S", line);
if (full_name.size != name.size) {
rd_indent();
rd_printf("Full Name: %S", full_name);
rd_unindent();
}
}
rd_newline();
rd_printf("Flags:");
rd_indent();
rd_printf("r = MemRead w = MemWrite x = MemExecute");
rd_printf("c = CntCode d = InitializedData u = UninitializedData");
rd_printf("s = MemShared h = Mem16bit l = MemLocked d = MemDiscardable c = MemNotCached p = MemNotPaged");
rd_printf("r = LnkRemove c = LnkComdat o = LnkOther i = LnkInfo f = LnkNRelocOvfl");
rd_printf("g = GpRel n = TypeNoPad");
rd_unindent();
rd_unindent();
rd_newline();
}
scratch_end(scratch);
}
internal void
coff_disasm_sections(Arena *arena,
String8List *out,
String8 indent,
String8 raw_data,
COFF_MachineType machine,
U64 image_base,
B32 is_obj,
RD_MarkerArray *section_markers,
U64 section_count,
COFF_SectionHeader *sections)
{
if (section_count) {
for (U64 sect_idx = 0; sect_idx < section_count; ++sect_idx) {
COFF_SectionHeader *sect = sections+sect_idx;
if (sect->flags & COFF_SectionFlag_CntCode) {
U64 sect_off = is_obj ? sect->foff : sect->voff;
U64 sect_size = is_obj ? sect->fsize : sect->vsize;
String8 raw_code = str8_substr(raw_data, rng_1u64(sect->foff, sect->foff+sect_size));
U64 sect_number = sect_idx+1;
RD_MarkerArray markers = section_markers[sect_number];
rd_printf("# Disassembly [Section No. %#llx]", sect_number);
rd_indent();
rd_print_disasm(arena, out, indent, arch_from_coff_machine(machine), image_base, sect_off, markers.count, markers.v, raw_code);
rd_unindent();
}
}
}
}
internal void
coff_raw_data_sections(Arena *arena,
String8List *out,
String8 indent,
String8 raw_data,
B32 is_obj,
RD_MarkerArray *section_markers,
U64 section_count,
COFF_SectionHeader *section_table)
{
if (section_count) {
for (U64 sect_idx = 0; sect_idx < section_count; ++sect_idx) {
COFF_SectionHeader *sect = section_table+sect_idx;
if (sect->fsize > 0) {
U64 sect_size = is_obj ? sect->fsize : sect->vsize;
String8 raw_sect = str8_substr(raw_data, rng_1u64(sect->foff, sect->foff+sect_size));
RD_MarkerArray markers = section_markers[sect_idx];
rd_printf("# Raw Data [Section No. %#llx]", (sect_idx+1));
rd_indent();
rd_print_raw_data(arena, out, indent, 32, markers.count, markers.v, raw_sect);
rd_unindent();
rd_newline();
}
}
}
}
internal void
coff_print_relocs(Arena *arena,
String8List *out,
String8 indent,
String8 raw_data,
String8 string_table,
COFF_MachineType machine,
U64 sect_count,
COFF_SectionHeader *sect_headers,
COFF_Symbol32Array symbols)
{
Temp scratch = scratch_begin(&arena, 1);
B32 print_header = 1;
for (U64 sect_idx = 0; sect_idx < sect_count; ++sect_idx) {
COFF_SectionHeader *sect_header = sect_headers+sect_idx;
COFF_RelocInfo reloc_info = coff_reloc_info_from_section_header(raw_data, sect_header);
if (reloc_info.count) {
if (print_header) {
print_header = 0;
rd_printf("# Relocations");
rd_indent();
}
rd_printf("## Section %llx", sect_idx);
rd_indent();
rd_printf("%-4s %-8s %-16s %-16s %-8s %-7s", "No.", "Offset", "Type", "ApplyTo", "SymIdx", "SymName");
for (U64 reloc_idx = 0; reloc_idx < reloc_info.count; ++reloc_idx) {
COFF_Reloc *reloc = (COFF_Reloc*)(raw_data.str + reloc_info.array_off) + reloc_idx;
String8 type = coff_string_from_reloc(machine, reloc->type);
U64 apply_size = coff_apply_size_from_reloc(machine, reloc->type);
U64 apply_foff = sect_header->foff + reloc->apply_off;
if (apply_foff + apply_size > raw_data.size) {
rd_errorf("out of bounds apply file offset %#llx in relocation %#llx", apply_foff, reloc_idx);
break;
}
U64 raw_apply;
AssertAlways(apply_size <= sizeof(raw_apply));
MemoryCopy(&raw_apply, raw_data.str + apply_foff, apply_size);
S64 apply = extend_sign64(raw_apply, apply_size);
if (reloc->isymbol > symbols.count) {
rd_errorf("out of bounds symbol index %u in relocation %#llx", reloc->isymbol, reloc_idx);
break;
}
COFF_Symbol32 *symbol = symbols.v+reloc->isymbol;
String8 symbol_name = coff_read_symbol_name(string_table, &symbol->name);
String8List line = {0};
str8_list_pushf(scratch.arena, &line, "%-4x", reloc_idx );
str8_list_pushf(scratch.arena, &line, "%08x", reloc->apply_off);
str8_list_pushf(scratch.arena, &line, "%-16S", type );
str8_list_pushf(scratch.arena, &line, "%016x", apply );
str8_list_pushf(scratch.arena, &line, "%S", symbol_name );
String8 l = str8_list_join(scratch.arena, &line, &(StringJoin){.sep=str8_lit(" ")});
rd_printf("%S", l);
}
rd_unindent();
}
}
if (!print_header) {
rd_unindent();
}
rd_newline();
scratch_end(scratch);
}
internal void
coff_print_symbol_table(Arena *arena,
String8List *out,
String8 indent,
String8 raw_data,
B32 is_big_obj,
String8 string_table,
COFF_Symbol32Array symbols)
{
Temp scratch = scratch_begin(&arena, 1);
if (symbols.count) {
rd_printf("# Symbol Table");
rd_indent();
rd_printf("%-4s %-8s %-10s %-4s %-4s %-4s %-16s %-20s",
"No.", "Value", "SectNum", "Aux", "Msb", "Lsb", "Storage", "Name");
for (U64 i = 0; i < symbols.count; ++i) {
COFF_Symbol32 *symbol = &symbols.v[i];
String8 name = coff_read_symbol_name(string_table, &symbol->name);
String8 msb = coff_string_from_sym_dtype(symbol->type.u.msb);
String8 lsb = coff_string_from_sym_type(symbol->type.u.lsb);
String8 storage_class = coff_string_from_sym_storage_class(symbol->storage_class);
String8 section_number;
switch (symbol->section_number) {
case COFF_Symbol_UndefinedSection: section_number = str8_lit("Undef"); break;
case COFF_Symbol_AbsSection32: section_number = str8_lit("Abs"); break;
case COFF_Symbol_DebugSection32: section_number = str8_lit("Debug"); break;
default: section_number = push_str8f(scratch.arena, "%010x", symbol->section_number); break;
}
String8List line = {0};
str8_list_pushf(scratch.arena, &line, "%-4x", i );
str8_list_pushf(scratch.arena, &line, "%08x", symbol->value );
str8_list_pushf(scratch.arena, &line, "%-10S", section_number );
str8_list_pushf(scratch.arena, &line, "%-4u", symbol->aux_symbol_count);
str8_list_pushf(scratch.arena, &line, "%-4S", msb );
str8_list_pushf(scratch.arena, &line, "%-4S", lsb );
str8_list_pushf(scratch.arena, &line, "%-16S", storage_class );
str8_list_pushf(scratch.arena, &line, "%S", name );
String8 l = str8_list_join(scratch.arena, &line, &(StringJoin){.sep = str8_lit(" ")});
rd_printf("%S", l);
rd_indent();
for (U64 k=i+1, c = i+symbol->aux_symbol_count; k <= c; ++k) {
void *raw_aux = &symbols.v[k];
switch (symbol->storage_class) {
case COFF_SymStorageClass_External: {
COFF_SymbolFuncDef *func_def = (COFF_SymbolFuncDef*)&symbols.v[k];
rd_printf("Tag Index %#x, Total Size %#x, Line Numbers %#x, Next Function %#x",
func_def->tag_index, func_def->total_size, func_def->ptr_to_ln, func_def->ptr_to_next_func);
} break;
case COFF_SymStorageClass_Function: {
COFF_SymbolFunc *func = raw_aux;
rd_printf("Ordinal Line Number %#x, Next Function %#x", func->ln, func->ptr_to_next_func);
} break;
case COFF_SymStorageClass_WeakExternal: {
COFF_SymbolWeakExt *weak = raw_aux;
String8 type = coff_string_from_weak_ext_type(weak->characteristics);
rd_printf("Tag Index %#x, Characteristics %S", weak->tag_index, type);
} break;
case COFF_SymStorageClass_File: {
COFF_SymbolFile *file = raw_aux;
String8 name = str8_cstring_capped(file->name, file->name+sizeof(file->name));
rd_printf("Name %S", name);
} break;
case COFF_SymStorageClass_Static: {
COFF_SymbolSecDef *sd = raw_aux;
String8 selection = coff_string_from_comdat_select_type(sd->selection);
U32 number = sd->number_lo;
if (is_big_obj) {
number |= (U32)sd->number_hi << 16;
}
if (number) {
rd_printf("Length %x, Reloc Count %u, Line Count %u, Checksum %x, Section %x, Selection %S",
sd->length, sd->number_of_relocations, sd->number_of_ln, sd->check_sum, number, selection);
} else {
rd_printf("Length %x, Reloc Count %u, Line Count %u, Checksum %x",
sd->length, sd->number_of_relocations, sd->number_of_ln, sd->check_sum);
}
} break;
default: {
rd_printf("???");
} break;
}
}
i += symbol->aux_symbol_count;
rd_unindent();
}
rd_unindent();
rd_newline();
}
scratch_end(scratch);
}
internal void
coff_print_big_obj_header(Arena *arena, String8List *out, String8 indent, COFF_BigObjHeader *header)
{
Temp scratch = scratch_begin(&arena, 1);
String8 time_stamp = coff_string_from_time_stamp(scratch.arena, header->time_stamp);
String8 machine = coff_string_from_machine_type(header->machine);
rd_printf("# Big Obj");
rd_indent();
rd_printf("Time Stamp : %#x (%S)", header->time_stamp, time_stamp);
rd_printf("Machine : %#x (%S)", header->machine, machine );
rd_printf("Section Count: %u", header->section_count );
rd_printf("Symbol Table : %#x", header->symbol_table_foff);
rd_printf("Symbol Count : %u", header->symbol_count );
rd_unindent();
scratch_end(scratch);
}
internal void
coff_print_file_header(Arena *arena, String8List *out, String8 indent, COFF_FileHeader *header)
{
Temp scratch = scratch_begin(&arena, 1);
String8 time_stamp = coff_string_from_time_stamp(scratch.arena, header->time_stamp);
String8 machine = coff_string_from_machine_type(header->machine);
String8 flags = coff_string_from_flags(scratch.arena, header->flags);
rd_printf("# COFF File Header");
rd_indent();
rd_printf("Time Stamp : %#x (%S)", header->time_stamp, time_stamp );
rd_printf("Machine : %#x %S", header->machine, machine );
rd_printf("Section Count : %u", header->section_count );
rd_printf("Symbol Table : %#x", header->symbol_table_foff );
rd_printf("Symbol Count : %u", header->symbol_count );
rd_printf("Optional Header Size: %#x (%m)", header->optional_header_size, header->optional_header_size);
rd_printf("Flags : %#x (%S)", header->flags, flags );
rd_unindent();
scratch_end(scratch);
}
internal void
coff_print_import(Arena *arena, String8List *out, String8 indent, COFF_ParsedArchiveImportHeader *header)
{
Temp scratch = scratch_begin(&arena, 1);
String8 machine = coff_string_from_machine_type(header->machine);
String8 time_stamp = coff_string_from_time_stamp(scratch.arena, header->time_stamp);
rd_printf("# Import");
rd_indent();
rd_printf("Version : %u", header->version );
rd_printf("Machine : %S", machine );
rd_printf("Time Stamp: %#x (%S)", header->time_stamp, time_stamp );
rd_printf("Data Size : %#x (%m)", header->data_size, header->data_size);
rd_printf("Hint : %u", header->hint_or_ordinal);
rd_printf("Type : %u", header->type );
rd_printf("Import By : %u", header->import_by );
rd_printf("Function : %S", header->func_name );
rd_printf("DLL : %S", header->dll_name );
rd_unindent();
scratch_end(scratch);
}
internal void
coff_print_big_obj(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Option opts)
{
Temp scratch = scratch_begin(&arena, 1);
COFF_FileHeaderInfo header_info = coff_file_header_info_from_data(raw_data);
String8 raw_header = str8_substr(raw_data, header_info.header_range);
String8 raw_section_table = str8_substr(raw_data, header_info.section_table_range);
String8 raw_string_table = str8_substr(raw_data, header_info.string_table_range);
COFF_BigObjHeader *big_obj = (COFF_BigObjHeader *)raw_header.str;
COFF_SectionHeader *section_table = (COFF_SectionHeader *)raw_section_table.str;
COFF_Symbol32Array symbol_table = coff_symbol_array_from_data_32(scratch.arena, raw_data, header_info.symbol_table_range.min, big_obj->symbol_count);
if (opts & RD_Option_Headers) {
coff_print_big_obj_header(arena, out, indent, big_obj);
rd_newline();
}
if (opts & RD_Option_Sections) {
Rng1U64 sect_headers_range = rng_1u64(sizeof(*big_obj), sizeof(*big_obj) + sizeof(COFF_SectionHeader)*big_obj->section_count);
Rng1U64 symbols_range = rng_1u64(big_obj->symbol_table_foff, big_obj->symbol_table_foff + sizeof(COFF_Symbol32)*big_obj->symbol_count);
if (sect_headers_range.max > raw_data.size) {
rd_errorf("not enough bytes to read big obj section headers");
goto exit;
}
if (big_obj->symbol_count) {
if (symbols_range.max > raw_data.size) {
rd_errorf("not enough bytes to read big obj symbol table");
goto exit;
}
if (contains_1u64(symbols_range, sect_headers_range.min) ||
contains_1u64(symbols_range, sect_headers_range.max)) {
rd_errorf("section headers and symbol table ranges overlap");
goto exit;
}
}
coff_print_section_table(arena, out, indent, raw_string_table, symbol_table, big_obj->section_count, section_table);
rd_newline();
}
if (opts & RD_Option_Relocs) {
coff_print_relocs(arena, out, indent, raw_data, raw_string_table, big_obj->machine, big_obj->section_count, section_table, symbol_table);
rd_newline();
}
if (opts & RD_Option_Symbols) {
coff_print_symbol_table(arena, out, indent, raw_data, 1, raw_string_table, symbol_table);
rd_newline();
}
exit:;
scratch_end(scratch);
}
internal void
coff_print_obj(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Option opts)
{
Temp scratch = scratch_begin(&arena, 1);
COFF_FileHeaderInfo header_info = coff_file_header_info_from_data(raw_data);
String8 raw_header = str8_substr(raw_data, header_info.header_range);
String8 raw_section_table = str8_substr(raw_data, header_info.section_table_range);
String8 raw_string_table = str8_substr(raw_data, header_info.string_table_range);
COFF_FileHeader *header = (COFF_FileHeader *)raw_header.str;
COFF_SectionHeader *section_table = (COFF_SectionHeader *)raw_section_table.str;
COFF_Symbol32Array symbol_table = coff_symbol_array_from_data_16(scratch.arena, raw_data, header_info.symbol_table_range.min, header->symbol_count);
Arch arch = arch_from_coff_machine(header->machine);
if (opts & RD_Option_Headers) {
coff_print_file_header(arena, out, indent, header);
rd_newline();
}
if (opts & RD_Option_Sections) {
Rng1U64 sect_headers_range = rng_1u64(sizeof(*header), sizeof(*header) + sizeof(COFF_SectionHeader)*header->section_count);
Rng1U64 symbols_range = rng_1u64(header->symbol_table_foff, header->symbol_table_foff + sizeof(COFF_Symbol16)*header->symbol_count);
if (sect_headers_range.max > raw_data.size) {
rd_errorf("not enough bytes to read obj section headers");
goto exit;
}
if (header->symbol_count) {
if (symbols_range.max > raw_data.size) {
rd_errorf("not enough bytes to read obj symbol table");
goto exit;
}
if (contains_1u64(symbols_range, sect_headers_range.min) ||
contains_1u64(symbols_range, sect_headers_range.max)) {
rd_errorf("section headers and symbol table ranges overlap");
goto exit;
}
}
coff_print_section_table(arena, out, indent, raw_string_table, symbol_table, header->section_count, section_table);
rd_newline();
}
if (opts & RD_Option_Relocs) {
coff_print_relocs(arena, out, indent, raw_data, raw_string_table, header->machine, header->section_count, section_table, symbol_table);
rd_newline();
}
if (opts & RD_Option_Symbols) {
coff_print_symbol_table(arena, out, indent, raw_data, 0, raw_string_table, symbol_table);
rd_newline();
}
RD_MarkerArray *section_markers = 0;
if (opts & (RD_Option_Disasm|RD_Option_Rawdata)) {
section_markers = rd_section_markers_from_coff_symbol_table(scratch.arena, raw_string_table, header->section_count, symbol_table);
}
if (opts & RD_Option_Rawdata) {
coff_raw_data_sections(arena, out, indent, raw_data, 1, section_markers, header->section_count, section_table);
}
if (opts & RD_Option_Disasm) {
coff_disasm_sections(arena, out, indent, raw_data, header->machine, 0, 1, section_markers, header->section_count, section_table);
rd_newline();
}
if (opts & RD_Option_Codeview) {
cv_format_debug_sections(arena, out, indent, raw_data, raw_string_table, header->section_count, section_table);
}
if (opts & RD_Option_Dwarf) {
DW_Input dwarf_input = dw_input_from_coff_section_table(scratch.arena, raw_data, raw_string_table, header->section_count, section_table);
dw_format(arena, out, indent, opts, &dwarf_input, arch, ExecutableImageKind_CoffPe);
}
exit:;
scratch_end(scratch);
}
internal void
coff_print_archive(Arena *arena, String8List *out, String8 indent, String8 raw_archive, RD_Option opts)
{
Temp scratch = scratch_begin(&arena, 1);
COFF_ArchiveParse archive_parse = coff_archive_parse_from_data(raw_archive);
if (archive_parse.error.size) {
rd_errorf("%S", archive_parse.error);
return;
}
COFF_ArchiveFirstMember first_member = archive_parse.first_member;
{
rd_printf("# First Header");
rd_indent();
rd_printf("Symbol Count : %u", first_member.symbol_count);
rd_printf("String Table Size: %#llx (%M)", first_member.string_table.size, first_member.string_table.size);
rd_printf("Members:");
rd_indent();
String8List string_table = str8_split_by_string_chars(scratch.arena, first_member.string_table, str8_lit("\0"), 0);
if (string_table.node_count == first_member.member_offset_count) {
String8Node *string_n = string_table.first;
for (U64 i = 0; i < string_table.node_count; ++i, string_n = string_n->next) {
U32 offset = from_be_u32(first_member.member_offsets[i]);
rd_printf("[%4u] %#08x %S", i, offset, string_n->string);
}
} else {
rd_errorf("Member offset count (%llu) doesn't match string table count (%llu)", first_member.member_offset_count);
}
rd_unindent();
rd_unindent();
rd_newline();
}
if (archive_parse.has_second_header) {
COFF_ArchiveSecondMember second_member = archive_parse.second_member;
rd_printf("# Second Header");
rd_indent();
rd_printf("Member Count : %u", second_member.member_count);
rd_printf("Symbol Count : %u", second_member.symbol_count);
rd_printf("String Table Size: %#llx (%M)", second_member.string_table.size, second_member.string_table.size);
String8List string_table = str8_split_by_string_chars(scratch.arena, second_member.string_table, str8_lit("\0"), 0);
rd_printf("Members:");
rd_indent();
if (second_member.symbol_index_count == second_member.symbol_count) {
String8Node *string_n = string_table.first;
for (U64 i = 0; i < second_member.symbol_count; ++i, string_n = string_n->next) {
U16 symbol_number = second_member.symbol_indices[i];
if (symbol_number > 0 && symbol_number <= second_member.member_offset_count) {
U16 symbol_idx = symbol_number - 1;
U32 member_offset = second_member.member_offsets[i];
rd_printf("[%4u] %#08x %S", i, member_offset, string_n->string);
} else {
rd_errorf("[%4u] Out of bounds symbol number %u", i, symbol_number);
break;
}
}
} else {
rd_errorf("Symbol index count %u doesn't match symbol count %u",
second_member.symbol_index_count, second_member.symbol_count);
}
rd_unindent();
rd_unindent();
rd_newline();
}
if (archive_parse.has_long_names && opts & RD_Option_LongNames) {
rd_printf("# Long Names");
rd_indent();
String8List long_names = str8_split_by_string_chars(scratch.arena, archive_parse.long_names, str8_lit("\0"), 0);
U64 name_idx = 0;
for (String8Node *name_n = long_names.first; name_n != 0; name_n = name_n->next, ++name_idx) {
U64 offset = (U64)(name_n->string.str - archive_parse.long_names.str);
rd_printf("[%-4u] %#08x %S", name_idx, offset, name_n->string);
}
rd_unindent();
rd_newline();
}
U64 member_offset_count = 0;
U32 *member_offsets = 0;
if (archive_parse.has_second_header) {
member_offset_count = archive_parse.second_member.member_offset_count;
member_offsets = archive_parse.second_member.member_offsets;
} else {
HashTable *ht = hash_table_init(scratch.arena, 0x1000);
for (U64 i = 0; i < archive_parse.first_member.member_offset_count; ++i) {
U32 member_offset = from_be_u32(archive_parse.first_member.member_offsets[i]);
if (!hash_table_search_u32(ht, member_offset)) {
hash_table_push_u32_raw(scratch.arena, ht, member_offset, 0);
}
}
member_offset_count = ht->count;
member_offsets = keys_from_hash_table_u32(scratch.arena, ht);
radsort(member_offsets, member_offset_count, u32_is_before);
}
rd_printf("# Members");
rd_indent();
for (U64 i = 0; i < member_offset_count; ++i) {
U64 next_member_offset = i+1 < member_offset_count ? member_offsets[i+1] : raw_archive.size;
U64 member_offset = member_offsets[i];
String8 raw_member = str8_substr(raw_archive, rng_1u64(member_offset, next_member_offset));
COFF_ArchiveMember member = coff_archive_member_from_data(raw_member);
COFF_DataType member_type = coff_data_type_from_data(member.data);
rd_printf("Member @ %#llx", member_offset);
rd_indent();
if (opts & RD_Option_Headers) {
coff_print_archive_member_header(arena, out, indent, member.header, archive_parse.long_names);
rd_newline();
}
switch (member_type) {
case COFF_DataType_Obj: {
coff_print_obj(arena, out, indent, member.data, opts);
} break;
case COFF_DataType_BigObj: {
coff_print_big_obj(arena, out, indent, member.data, opts);
} break;
case COFF_DataType_Import: {
if (opts & RD_Option_Headers) {
COFF_ParsedArchiveImportHeader header = {0};
U64 parse_size = coff_parse_import(member.data, 0, &header);
if (parse_size) {
coff_print_import(arena, out, indent, &header);
} else {
rd_errorf("not enough bytes to parse import header");
}
}
} break;
case COFF_DataType_Null: {
rd_errorf("unknown member format", member_offset);
} break;
}
rd_unindent();
rd_newline();
}
rd_unindent();
scratch_end(scratch);
}
#endif