Files
raddebugger/src/coff/coff.c
T
2025-06-25 10:53:22 -07:00

908 lines
33 KiB
C

// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
internal U64
coff_align_size_from_section_flags(COFF_SectionFlags flags)
{
U32 align = 0;
U32 align_index = COFF_SectionFlags_ExtractAlign(flags);
switch (align_index) {
default: break;
case COFF_SectionAlign_1Bytes: align = 1; break;
case COFF_SectionAlign_2Bytes: align = 2; break;
case COFF_SectionAlign_4Bytes: align = 4; break;
case COFF_SectionAlign_8Bytes: align = 8; break;
case COFF_SectionAlign_16Bytes: align = 16; break;
case COFF_SectionAlign_32Bytes: align = 32; break;
case COFF_SectionAlign_64Bytes: align = 64; break;
case COFF_SectionAlign_128Bytes: align = 128; break;
case COFF_SectionAlign_256Bytes: align = 256; break;
case COFF_SectionAlign_512Bytes: align = 512; break;
case COFF_SectionAlign_1024Bytes: align = 1024; break;
case COFF_SectionAlign_2048Bytes: align = 2048; break;
case COFF_SectionAlign_4096Bytes: align = 4096; break;
case COFF_SectionAlign_8192Bytes: align = 8192; break;
}
return align;
}
internal COFF_SectionFlags
coff_section_flag_from_align_size(U64 align)
{
COFF_SectionFlags flags = 0;
switch (align) {
case 0: flags = COFF_SectionAlign_None; break;
case 1: flags = COFF_SectionAlign_1Bytes; break;
case 2: flags = COFF_SectionAlign_2Bytes; break;
case 4: flags = COFF_SectionAlign_4Bytes; break;
case 8: flags = COFF_SectionAlign_8Bytes; break;
case 16: flags = COFF_SectionAlign_16Bytes; break;
case 32: flags = COFF_SectionAlign_32Bytes; break;
case 64: flags = COFF_SectionAlign_64Bytes; break;
case 128: flags = COFF_SectionAlign_128Bytes; break;
case 256: flags = COFF_SectionAlign_256Bytes; break;
case 512: flags = COFF_SectionAlign_512Bytes; break;
case 1024: flags = COFF_SectionAlign_1024Bytes; break;
case 2048: flags = COFF_SectionAlign_2048Bytes; break;
case 4096: flags = COFF_SectionAlign_4096Bytes; break;
case 8192: flags = COFF_SectionAlign_8192Bytes; break;
}
flags <<= COFF_SectionFlag_AlignShift;
return flags;
}
internal String8
coff_name_from_section_header(String8 string_table, COFF_SectionHeader *header)
{
String8 name = str8_cstring_capped(header->name, header->name + sizeof(header->name));
if (name.str[0] == '/') {
String8 name_off_str = str8_skip(name, 1);
U64 name_off = u64_from_str8(name_off_str, 10);
name = str8_cstring_capped(string_table.str + name_off, string_table.str+string_table.size);
}
return name;
}
internal void
coff_parse_section_name(String8 full_name, String8 *name_out, String8 *postfix_out)
{
// dollar sign has multiple interpretations that depend on the type of the section.
// 1. when section contains code/data it indicates section precedence
// 2. when section starts with .debug it indicates type of data inside the section
// T: Types
// S: Symbols
// P: Precompiled types
// F: FPO data
// H: Clang extension produced with /debug:ghash, array of type hashes
*name_out = full_name;
*postfix_out = str8_lit("");
for (U64 i = 0; i < full_name.size; ++i) {
if (full_name.str[i] == '$') {
*name_out = str8(full_name.str, i);
*postfix_out = str8(full_name.str + i, full_name.size - i);
break;
}
}
}
internal String8
coff_read_symbol_name(String8 string_table, COFF_SymbolName *name)
{
String8 name_str = str8_lit("");
if (name->long_name.zeroes == 0) {
str8_deserial_read_cstr(string_table, name->long_name.string_table_offset, &name_str);
} else {
U32 i;
for (i = 0; i < sizeof(name->short_name); ++i) {
if (name->short_name[i] == '\0') {
break;
}
}
name_str = str8(name->short_name, i);
}
return name_str;
}
internal U64
coff_apply_size_from_reloc_x64(COFF_Reloc_X64 x)
{
switch (x) {
case COFF_Reloc_X64_Abs: return 4;
case COFF_Reloc_X64_Addr64: return 8;
case COFF_Reloc_X64_Addr32: return 4;
case COFF_Reloc_X64_Addr32Nb: return 4;
case COFF_Reloc_X64_Rel32: return 4;
case COFF_Reloc_X64_Rel32_1: return 4;
case COFF_Reloc_X64_Rel32_2: return 4;
case COFF_Reloc_X64_Rel32_3: return 4;
case COFF_Reloc_X64_Rel32_4: return 4;
case COFF_Reloc_X64_Rel32_5: return 4;
case COFF_Reloc_X64_Section: return 2;
case COFF_Reloc_X64_SecRel: return 4;
case COFF_Reloc_X64_SRel32: return 4;
case COFF_Reloc_X64_SecRel7:
case COFF_Reloc_X64_Token:
case COFF_Reloc_X64_Pair:
case COFF_Reloc_X64_SSpan32:
NotImplemented;
break;
}
return 0;
}
internal U64
coff_apply_size_from_reloc_x86(COFF_Reloc_X86 x)
{
switch (x) {
case COFF_Reloc_X86_Abs: return 4;
case COFF_Reloc_X86_Dir16: return 2;
case COFF_Reloc_X86_Rel16: return 2;
case COFF_Reloc_X86_Dir32: return 4;
case COFF_Reloc_X86_Dir32Nb: return 4;
case COFF_Reloc_X86_Seg12: return 0;
case COFF_Reloc_X86_Section: return 2;
case COFF_Reloc_X86_SecRel: return 4;
case COFF_Reloc_X86_Token: return 4;
case COFF_Reloc_X86_SecRel7: return 1;
case COFF_Reloc_X86_Rel32: return 4;
case COFF_Reloc_X86_Unknown0:
case COFF_Reloc_X86_Unknown2:
case COFF_Reloc_X86_Unknown3:
case COFF_Reloc_X86_Unknown4:
case COFF_Reloc_X86_Unknown6:
case COFF_Reloc_X86_Unknown7:
case COFF_Reloc_X86_Unknown8:
case COFF_Reloc_X86_Unknown9:
NotImplemented;
break;
}
return 0;
}
internal U64
coff_apply_size_from_reloc(COFF_MachineType machine, COFF_RelocType x)
{
switch (machine) {
case COFF_MachineType_X64: return coff_apply_size_from_reloc_x64(x);
case COFF_MachineType_X86: return coff_apply_size_from_reloc_x86(x);
default: NotImplemented;
}
return 0;
}
internal COFF_RelocValue
coff_pick_reloc_value_x64(COFF_Reloc_X64 type,
U64 image_base,
U64 reloc_virtual_offset,
U32 symbol_section_number,
U32 symbol_section_offset,
S64 symbol_virtual_offset)
{
U64 reloc_value_size = 0;
S64 reloc_value = 0;
switch (type) {
case COFF_Reloc_X64_Abs: {} break;
case COFF_Reloc_X64_Addr64: {
reloc_value_size = 8;
reloc_value = symbol_virtual_offset + (S64)image_base;
} break;
case COFF_Reloc_X64_Addr32: {
reloc_value_size = 4;
reloc_value = safe_cast_s32(symbol_virtual_offset + (S64)image_base);
} break;
case COFF_Reloc_X64_Addr32Nb: {
reloc_value_size = 4;
reloc_value = symbol_virtual_offset;
} break;
case COFF_Reloc_X64_Rel32: {
reloc_value_size = 4;
reloc_value = safe_cast_s32(symbol_virtual_offset - reloc_virtual_offset - (4 + 0));
} break;
case COFF_Reloc_X64_Rel32_1: {
reloc_value_size = 4;
reloc_value = safe_cast_s32(symbol_virtual_offset - reloc_virtual_offset - (4 + 1));
} break;
case COFF_Reloc_X64_Rel32_2: {
reloc_value_size = 4;
reloc_value = safe_cast_s32(symbol_virtual_offset - reloc_virtual_offset - (4 + 2));
} break;
case COFF_Reloc_X64_Rel32_3: {
reloc_value_size = 4;
reloc_value = safe_cast_s32(symbol_virtual_offset - reloc_virtual_offset - (4 + 3));
} break;
case COFF_Reloc_X64_Rel32_4: {
reloc_value_size = 4;
reloc_value = safe_cast_s32(symbol_virtual_offset - reloc_virtual_offset - (4 + 4));
} break;
case COFF_Reloc_X64_Rel32_5: {
reloc_value_size = 4;
reloc_value = safe_cast_s32(symbol_virtual_offset - reloc_virtual_offset - (4 + 5));
} break;
case COFF_Reloc_X64_Section: {
reloc_value_size = 4;
reloc_value = symbol_section_number;
} break;
case COFF_Reloc_X64_SecRel: {
reloc_value_size = 4;
reloc_value = symbol_section_offset;
} break;
case COFF_Reloc_X64_SecRel7:
case COFF_Reloc_X64_Token:
case COFF_Reloc_X64_SRel32:
case COFF_Reloc_X64_Pair:
case COFF_Reloc_X64_SSpan32:
case COFF_Reloc_X64_Unknown_11: {
NotImplemented;
} break;
}
COFF_RelocValue result = {0};
result.size = reloc_value_size;
result.value = reloc_value;
return result;
}
internal String8
coff_make_import_lookup(Arena *arena, U16 hint, String8 name)
{
U64 buffer_size = sizeof(hint) + (name.size + 1);
U8 *buffer = push_array(arena, U8, buffer_size);
*(U16*)buffer = hint;
MemoryCopy(buffer + sizeof(hint), name.str, name.size);
buffer[buffer_size - 1] = 0;
String8 result = str8(buffer, buffer_size);
return result;
}
internal U32
coff_make_ordinal32(U16 hint)
{
U32 ordinal = (1 << 31) | hint;
return ordinal;
}
internal U64
coff_make_ordinal64(U16 hint)
{
U64 ordinal = (1ULL << 63) | hint;
return ordinal;
}
internal String8
coff_ordinal_data_from_hint(Arena *arena, COFF_MachineType machine, U16 hint)
{
String8 ordinal_data = {0};
switch (machine) {
case COFF_MachineType_Unknown: break;
case COFF_MachineType_X64: {
U64 *ordinal = push_array(arena, U64, 1);
*ordinal = coff_make_ordinal64(hint);
ordinal_data = str8_struct(ordinal);
} break;
case COFF_MachineType_X86: {
U32 *ordinal = push_array(arena, U32, 1);
*ordinal = coff_make_ordinal32(hint);
ordinal_data = str8_struct(ordinal);
} break;
default: { NotImplemented; } break;
}
return ordinal_data;
}
internal String8
coff_make_import_header(Arena *arena,
COFF_MachineType machine,
COFF_TimeStamp time_stamp,
String8 dll_name,
COFF_ImportByType import_by,
String8 name,
U16 hint_or_ordinal,
COFF_ImportType type)
{
COFF_ImportHeaderFlags flags = 0;
flags |= (type & COFF_ImportHeader_TypeMask) << COFF_ImportHeader_TypeShift;
flags |= import_by << COFF_ImportHeader_ImportByShift;
COFF_ImportHeader header = {0};
header.sig1 = COFF_MachineType_Unknown;
header.sig2 = max_U16;
header.version = 0;
header.machine = machine;
header.time_stamp = time_stamp;
header.data_size = safe_cast_u32(name.size + dll_name.size + 2);
header.flags = flags;
// alloc memory
U64 buffer_size = sizeof(header) + header.data_size;
U8 *buffer = push_array_no_zero(arena, U8, buffer_size);
// copy header
MemoryCopy(buffer, &header, sizeof(header));
// copy function name
U8 *func_name = buffer + sizeof(header);
MemoryCopy(func_name, name.str, name.size);
func_name[name.size] = 0;
// copy dll name
U8 *dll_name_buffer = buffer + sizeof(header) + name.size + 1;
MemoryCopy(dll_name_buffer, dll_name.str, dll_name.size);
dll_name_buffer[dll_name.size] = 0;
String8 import_data = str8(buffer, buffer_size);
return import_data;
}
internal U64
coff_word_size_from_machine(COFF_MachineType machine)
{
U64 result = 0;
switch (machine) {
case COFF_MachineType_X64: result = 8; break;
case COFF_MachineType_X86: result = 4; break;
}
return result;
}
internal U64
coff_default_exe_base_from_machine(COFF_MachineType machine)
{
U64 exe_base = 0;
switch (coff_word_size_from_machine(machine)) {
case 4: exe_base = 0x400000; break;
case 8: exe_base = 0x140000000; break;
}
return exe_base;
}
internal U64
coff_default_dll_base_from_machine(COFF_MachineType machine)
{
U64 dll_base = 0;
switch (coff_word_size_from_machine(machine)) {
case 4: dll_base = 0x10000000; break;
case 8: dll_base = 0x180000000; break;
}
return dll_base;
}
internal Arch
arch_from_coff_machine(COFF_MachineType machine)
{
Arch result = Arch_Null;
switch (machine) {
case COFF_MachineType_Unknown: break;
case COFF_MachineType_X86: result = Arch_x86; break;
case COFF_MachineType_X64: result = Arch_x64; break;
case COFF_MachineType_Arm: result = Arch_arm32; break;
case COFF_MachineType_Arm64: result = Arch_arm64; break;
}
return result;
}
internal U64
coff_foff_from_voff(COFF_SectionHeader *sections, U64 section_count, U64 voff)
{
U64 foff = 0;
for(U64 sect_idx = 0; sect_idx < section_count; sect_idx += 1)
{
COFF_SectionHeader *sect = &sections[sect_idx];
if(sect->voff <= voff && voff < sect->voff+sect->vsize)
{
if(!(sect->flags & COFF_SectionFlag_CntUninitializedData))
{
foff = sect->foff + (voff - sect->voff);
}
break;
}
}
return foff;
}
////////////////////////////////
//~ rjf: Enum -> String
internal String8
coff_string_from_time_stamp(Arena *arena, COFF_TimeStamp time_stamp)
{
String8 result;
if (time_stamp == 0) {
result = str8_lit("0");
} else if (time_stamp >= max_U32) {
result = str8_lit("-1");
} else {
DateTime dt = date_time_from_unix_time(time_stamp);
result = push_date_time_string(arena, &dt);
}
return result;
}
read_only struct
{
String8 string;
COFF_MachineType machine;
} g_coff_machine_map[] = {
{ str8_lit_comp(""), COFF_MachineType_Unknown },
{ str8_lit_comp("X86"), COFF_MachineType_X86 },
{ str8_lit_comp("Amd64"), COFF_MachineType_X64 },
{ str8_lit_comp("X64"), COFF_MachineType_X64 },
{ str8_lit_comp("Am33"), COFF_MachineType_Am33 },
{ str8_lit_comp("Arm"), COFF_MachineType_Arm },
{ str8_lit_comp("Arm64"), COFF_MachineType_Arm64 },
{ str8_lit_comp("ArmNt"), COFF_MachineType_ArmNt },
{ str8_lit_comp("Ebc"), COFF_MachineType_Ebc },
{ str8_lit_comp("Ia64"), COFF_MachineType_Ia64 },
{ str8_lit_comp("M32r"), COFF_MachineType_M32R },
{ str8_lit_comp("Mips16"), COFF_MachineType_Mips16 },
{ str8_lit_comp("MipsFpu"), COFF_MachineType_MipsFpu },
{ str8_lit_comp("MipsFpu16"), COFF_MachineType_MipsFpu16 },
{ str8_lit_comp("PowerPc"), COFF_MachineType_PowerPc },
{ str8_lit_comp("PowerPcFp"), COFF_MachineType_PowerPcFp },
{ str8_lit_comp("R4000"), COFF_MachineType_R4000 },
{ str8_lit_comp("RiscV32"), COFF_MachineType_RiscV32 },
{ str8_lit_comp("RiscV64"), COFF_MachineType_RiscV64 },
{ str8_lit_comp("Sh3"), COFF_MachineType_Sh3 },
{ str8_lit_comp("Sh3Dsp"), COFF_MachineType_Sh3Dsp },
{ str8_lit_comp("Sh4"), COFF_MachineType_Sh4 },
{ str8_lit_comp("Sh5"), COFF_MachineType_Sh5 },
{ str8_lit_comp("Thumb"), COFF_MachineType_Thumb },
{ str8_lit_comp("WceMipsV2"), COFF_MachineType_WceMipsV2 },
};
read_only static struct {
char * name;
COFF_ImportType type;
} g_coff_import_header_type_map[] = {
{ "Code", COFF_ImportHeader_Code },
{ "Data", COFF_ImportHeader_Data },
{ "Const", COFF_ImportHeader_Const },
};
internal String8
coff_string_from_comdat_select_type(COFF_ComdatSelectType type)
{
String8 result = str8_zero();
switch (type) {
case COFF_ComdatSelect_Null: result = str8_lit("Null"); break;
case COFF_ComdatSelect_NoDuplicates: result = str8_lit("NoDuplicates"); break;
case COFF_ComdatSelect_Any: result = str8_lit("Any"); break;
case COFF_ComdatSelect_SameSize: result = str8_lit("SameSize"); break;
case COFF_ComdatSelect_ExactMatch: result = str8_lit("ExactMatch"); break;
case COFF_ComdatSelect_Associative: result = str8_lit("Associative"); break;
case COFF_ComdatSelect_Largest: result = str8_lit("Largest"); break;
}
return result;
}
internal String8
coff_string_from_machine_type(COFF_MachineType machine)
{
for (U64 i = 0; i < ArrayCount(g_coff_machine_map); ++i) {
if (g_coff_machine_map[i].machine == machine) {
return g_coff_machine_map[i].string;
}
}
return str8_zero();
}
internal String8
coff_string_from_flags(Arena *arena, COFF_FileHeaderFlags flags)
{
Temp scratch = scratch_begin(&arena, 1);
String8List list = {0};
if (flags & COFF_FileHeaderFlag_RelocStripped) {
str8_list_pushf(scratch.arena, &list, "Relocs Stripped");
}
if (flags & COFF_FileHeaderFlag_ExecutableImage) {
str8_list_pushf(scratch.arena, &list, "Executable");
}
if (flags & COFF_FileHeaderFlag_LineNumbersStripped) {
str8_list_pushf(scratch.arena, &list, "Line Numbers Stripped");
}
if (flags & COFF_FileHeaderFlag_SymbolsStripped) {
str8_list_pushf(scratch.arena, &list, "Symbols Stripped");
}
if (flags & COFF_FileHeaderFlag_LargeAddressAware) {
str8_list_pushf(scratch.arena, &list, "Large Address Aware");
}
if (flags & COFF_FileHeaderFlag_32BitMachine) {
str8_list_pushf(scratch.arena, &list, "32-Bit Machine");
}
if (flags & COFF_FileHeaderFlag_DebugStripped) {
str8_list_pushf(scratch.arena, &list, "Debug Stripped");
}
if (flags & COFF_FileHeaderFlag_RemovableRunFromSwap) {
str8_list_pushf(scratch.arena, &list, "Removeable Run From Swap");
}
if (flags & COFF_FileHeaderFlag_NetRunFromSwap) {
str8_list_pushf(scratch.arena, &list, "Net Run From Swap");
}
if (flags & COFF_FileHeaderFlag_System) {
str8_list_pushf(scratch.arena, &list, "System");
}
if (flags & COFF_FileHeaderFlag_Dll) {
str8_list_pushf(scratch.arena, &list, "DLL");
}
if (flags & COFF_FileHeaderFlag_UpSystemOnly) {
str8_list_pushf(scratch.arena, &list, "Up System Only");
}
String8 result = str8_list_join(arena, &list, &(StringJoin){.sep=str8_lit(", ")});
scratch_end(scratch);
return result;
}
internal String8
coff_string_from_section_flags(Arena *arena, COFF_SectionFlags flags)
{
Temp scratch = scratch_begin(&arena, 1);
String8List list = {0};
if (flags & COFF_SectionFlag_TypeNoPad) {
str8_list_pushf(scratch.arena, &list, "TypeNoPad");
}
if (flags & COFF_SectionFlag_CntCode) {
str8_list_pushf(scratch.arena, &list, "CntCode");
}
if (flags & COFF_SectionFlag_CntInitializedData) {
str8_list_pushf(scratch.arena, &list, "CntInitializedData");
}
if (flags & COFF_SectionFlag_CntUninitializedData) {
str8_list_pushf(scratch.arena, &list, "CntUninitializedData");
}
if (flags & COFF_SectionFlag_LnkOther) {
str8_list_pushf(scratch.arena, &list, "LnkOther");
}
if (flags & COFF_SectionFlag_LnkInfo) {
str8_list_pushf(scratch.arena, &list, "LnkInfo");
}
if (flags & COFF_SectionFlag_LnkCOMDAT) {
str8_list_pushf(scratch.arena, &list, "LnkCOMDAT");
}
if (flags & COFF_SectionFlag_GpRel) {
str8_list_pushf(scratch.arena, &list, "GpRel");
}
if (flags & COFF_SectionFlag_Mem16Bit) {
str8_list_pushf(scratch.arena, &list, "Mem16Bit");
}
if (flags & COFF_SectionFlag_MemLocked) {
str8_list_pushf(scratch.arena, &list, "MemLocked");
}
if (flags & COFF_SectionFlag_MemPreload) {
str8_list_pushf(scratch.arena, &list, "MemPreload");
}
if (flags & COFF_SectionFlag_LnkNRelocOvfl) {
str8_list_pushf(scratch.arena, &list, "LnkNRelocOvfl");
}
if (flags & COFF_SectionFlag_MemDiscardable) {
str8_list_pushf(scratch.arena, &list, "MemDiscardable");
}
if (flags & COFF_SectionFlag_MemNotCached) {
str8_list_pushf(scratch.arena, &list, "MemNotCached");
}
if (flags & COFF_SectionFlag_MemNotPaged) {
str8_list_pushf(scratch.arena, &list, "MemNotPaged");
}
if (flags & COFF_SectionFlag_MemShared) {
str8_list_pushf(scratch.arena, &list, "MemShared");
}
if (flags & COFF_SectionFlag_MemExecute) {
str8_list_pushf(scratch.arena, &list, "MemExecute");
}
if (flags & COFF_SectionFlag_MemRead) {
str8_list_pushf(scratch.arena, &list, "MemRead");
}
if (flags & COFF_SectionFlag_MemWrite) {
str8_list_pushf(scratch.arena, &list, "MemWrite");
}
U64 align = coff_align_size_from_section_flags(flags);
if (align) {
str8_list_pushf(scratch.arena, &list, "Align=%u", align);
}
if (!list.node_count) {
str8_list_pushf(scratch.arena, &list, "None");
}
StringJoin join = {0};
join.sep = str8_lit(", ");
String8 result = str8_list_join(arena, &list, &join);
scratch_end(scratch);
return result;
}
internal String8
coff_string_from_resource_memory_flags(Arena *arena, COFF_ResourceMemoryFlags flags)
{
Temp scratch = scratch_begin(&arena, 1);
String8List list = {0};
if (flags & COFF_ResourceMemoryFlag_Moveable) {
flags &= COFF_ResourceMemoryFlag_Moveable;
str8_list_pushf(scratch.arena, &list, "Moveable");
}
if (flags & COFF_ResourceMemoryFlag_Pure) {
flags &= COFF_ResourceMemoryFlag_Pure;
str8_list_pushf(scratch.arena, &list, "Pure");
}
if (flags & COFF_ResourceMemoryFlag_Discardable) {
flags &= COFF_ResourceMemoryFlag_Discardable;
str8_list_pushf(scratch.arena, &list, "Discardable");
}
if (flags != 0) {
str8_list_pushf(scratch.arena, &list, "%#x", flags);
}
String8 result = str8_list_join(arena, &list, &(StringJoin){.sep=str8_lit(", ")});
scratch_end(scratch);
return result;
}
internal String8
coff_string_from_import_header_type(COFF_ImportType type)
{
for (U64 i = 0; i < ArrayCount(g_coff_import_header_type_map); ++i) {
if (g_coff_import_header_type_map[i].type == type) {
return str8_cstring(g_coff_import_header_type_map[i].name);
}
}
return str8(0,0);
}
internal String8
coff_string_from_sym_dtype(COFF_SymDType x)
{
switch (x) {
case COFF_SymDType_Null: return str8_lit("Null");
case COFF_SymDType_Ptr : return str8_lit("Ptr");
case COFF_SymDType_Func: return str8_lit("Func");
case COFF_SymDType_Array: return str8_lit("Array");
}
return str8_zero();
}
internal String8
coff_string_from_sym_type(COFF_SymType x)
{
switch (x) {
case COFF_SymType_Null: return str8_lit("Null");
case COFF_SymType_Void: return str8_lit("Void");
case COFF_SymType_Char: return str8_lit("Char");
case COFF_SymType_Short: return str8_lit("Short");
case COFF_SymType_Int: return str8_lit("Int");
case COFF_SymType_Long: return str8_lit("Long");
case COFF_SymType_Float: return str8_lit("Float");
case COFF_SymType_Double: return str8_lit("Double");
case COFF_SymType_Struct: return str8_lit("Struct");
case COFF_SymType_Union: return str8_lit("Union");
case COFF_SymType_Enum: return str8_lit("Enum");
case COFF_SymType_MemberOfEnumeration: return str8_lit("MOE");
case COFF_SymType_Byte: return str8_lit("Byte");
case COFF_SymType_Word: return str8_lit("Word");
case COFF_SymType_UInt: return str8_lit("UInt");
case COFF_SymType_DWord: return str8_lit("DWord");
}
return str8_zero();
}
internal String8
coff_string_from_sym_storage_class(COFF_SymStorageClass x)
{
switch (x) {
case COFF_SymStorageClass_Null: break;
case COFF_SymStorageClass_EndOfFunction: return str8_lit("EndOfFunction");
case COFF_SymStorageClass_Automatic: return str8_lit("Automatic");
case COFF_SymStorageClass_External: return str8_lit("External");
case COFF_SymStorageClass_Static: return str8_lit("Static");
case COFF_SymStorageClass_Register: return str8_lit("Register");
case COFF_SymStorageClass_ExternalDef: return str8_lit("Def");
case COFF_SymStorageClass_Label: return str8_lit("Label");
case COFF_SymStorageClass_UndefinedLabel: return str8_lit("UndefinedLabel");
case COFF_SymStorageClass_MemberOfStruct: return str8_lit("Struct");
case COFF_SymStorageClass_Argument: return str8_lit("Argument");
case COFF_SymStorageClass_StructTag: return str8_lit("Tag");
case COFF_SymStorageClass_MemberOfUnion: return str8_lit("Union");
case COFF_SymStorageClass_UnionTag: return str8_lit("Tag");
case COFF_SymStorageClass_TypeDefinition: return str8_lit("Definition");
case COFF_SymStorageClass_UndefinedStatic: return str8_lit("Static");
case COFF_SymStorageClass_EnumTag: return str8_lit("Tag");
case COFF_SymStorageClass_MemberOfEnum: return str8_lit("Enum");
case COFF_SymStorageClass_RegisterParam: return str8_lit("Param");
case COFF_SymStorageClass_BitField: return str8_lit("Field");
case COFF_SymStorageClass_Block: return str8_lit("Block");
case COFF_SymStorageClass_Function: return str8_lit("Function");
case COFF_SymStorageClass_EndOfStruct: return str8_lit("Struct");
case COFF_SymStorageClass_File: return str8_lit("File");
case COFF_SymStorageClass_Section: return str8_lit("Section");
case COFF_SymStorageClass_WeakExternal: return str8_lit("External");
case COFF_SymStorageClass_CLRToken: return str8_lit("Token");
}
return str8_zero();
}
internal String8
coff_string_from_weak_ext_type(COFF_WeakExtType x)
{
switch (x) {
case COFF_WeakExt_NoLibrary: return str8_lit("NoLibrary");
case COFF_WeakExt_SearchLibrary: return str8_lit("SearchLibrary");
case COFF_WeakExt_SearchAlias: return str8_lit("SearchAlias");
}
return str8_zero();
}
internal String8
coff_string_from_reloc_x86(COFF_Reloc_X86 x)
{
switch (x) {
case COFF_Reloc_X86_Abs: return str8_lit("Abs");
case COFF_Reloc_X86_Dir16: return str8_lit("Dir16");
case COFF_Reloc_X86_Rel16: return str8_lit("Rel16");
case COFF_Reloc_X86_Unknown0: return str8_lit("Unknown0");
case COFF_Reloc_X86_Unknown2: return str8_lit("Unknown2");
case COFF_Reloc_X86_Unknown3: return str8_lit("Unknown3");
case COFF_Reloc_X86_Dir32: return str8_lit("Dir32");
case COFF_Reloc_X86_Dir32Nb: return str8_lit("Dir32Nb");
case COFF_Reloc_X86_Seg12: return str8_lit("Seg12");
case COFF_Reloc_X86_Section: return str8_lit("Section");
case COFF_Reloc_X86_SecRel: return str8_lit("SecRel");
case COFF_Reloc_X86_Token: return str8_lit("Token");
case COFF_Reloc_X86_SecRel7: return str8_lit("SecRel7");
case COFF_Reloc_X86_Unknown4: return str8_lit("Unknown4");
case COFF_Reloc_X86_Unknown5: return str8_lit("Unknown5");
case COFF_Reloc_X86_Unknown6: return str8_lit("Unknown6");
case COFF_Reloc_X86_Unknown7: return str8_lit("Unknown7");
case COFF_Reloc_X86_Unknown8: return str8_lit("Unknown8");
case COFF_Reloc_X86_Unknown9: return str8_lit("Unknown9");
case COFF_Reloc_X86_Rel32: return str8_lit("Rel32");
}
return str8_zero();
}
internal String8
coff_string_from_reloc_x64(COFF_Reloc_X64 x)
{
switch (x) {
case COFF_Reloc_X64_Abs: return str8_lit("Abs");
case COFF_Reloc_X64_Addr64: return str8_lit("Addr64");
case COFF_Reloc_X64_Addr32: return str8_lit("Addr32");
case COFF_Reloc_X64_Addr32Nb: return str8_lit("Addr32Nb");
case COFF_Reloc_X64_Rel32: return str8_lit("Rel32");
case COFF_Reloc_X64_Rel32_1: return str8_lit("Rel32_1");
case COFF_Reloc_X64_Rel32_2: return str8_lit("Rel32_2");
case COFF_Reloc_X64_Rel32_3: return str8_lit("Rel32_3");
case COFF_Reloc_X64_Rel32_4: return str8_lit("Rel32_4");
case COFF_Reloc_X64_Rel32_5: return str8_lit("Rel32_5");
case COFF_Reloc_X64_Section: return str8_lit("Section");
case COFF_Reloc_X64_SecRel: return str8_lit("SecRel");
case COFF_Reloc_X64_SecRel7: return str8_lit("SecRel7");
case COFF_Reloc_X64_Token: return str8_lit("Token");
case COFF_Reloc_X64_SRel32: return str8_lit("SRel32");
case COFF_Reloc_X64_Pair: return str8_lit("Pair");
case COFF_Reloc_X64_SSpan32: return str8_lit("SSpan32");
}
return str8_zero();
}
internal String8
coff_string_from_reloc_arm(COFF_Reloc_Arm x)
{
switch (x) {
case COFF_Reloc_Arm_Abs: return str8_lit("Abs");
case COFF_Reloc_Arm_Addr32: return str8_lit("Addr32");
case COFF_Reloc_Arm_Addr32Nb: return str8_lit("Addr32Nb");
case COFF_Reloc_Arm_Branch24: return str8_lit("Branch24");
case COFF_Reloc_Arm_Branch11: return str8_lit("Branch11");
case COFF_Reloc_Arm_Unknown1: return str8_lit("Unknown1");
case COFF_Reloc_Arm_Unknown2: return str8_lit("Unknown2");
case COFF_Reloc_Arm_Unknown3: return str8_lit("Unknown3");
case COFF_Reloc_Arm_Unknown4: return str8_lit("Unknown4");
case COFF_Reloc_Arm_Unknown5: return str8_lit("Unknown5");
case COFF_Reloc_Arm_Rel32: return str8_lit("Rel32");
case COFF_Reloc_Arm_Section: return str8_lit("Section");
case COFF_Reloc_Arm_SecRel: return str8_lit("SecRel");
case COFF_Reloc_Arm_Mov32: return str8_lit("Mov32");
case COFF_Reloc_Arm_ThumbMov32: return str8_lit("ThumbMov32");
case COFF_Reloc_Arm_ThumbBranch20: return str8_lit("ThumbBranch20");
case COFF_Reloc_Arm_Unused: return str8_lit("Unused");
case COFF_Reloc_Arm_ThumbBranch24: return str8_lit("ThumbBranch24");
case COFF_Reloc_Arm_ThumbBlx23: return str8_lit("ThumbBlx23");
case COFF_Reloc_Arm_Pair: return str8_lit("Pair");
}
return str8_zero();
}
internal String8
coff_string_from_reloc_arm64(COFF_Reloc_Arm64 x)
{
switch (x) {
case COFF_Reloc_Arm64_Abs: return str8_lit("Abs");
case COFF_Reloc_Arm64_Addr32: return str8_lit("Addr32");
case COFF_Reloc_Arm64_Addr32Nb: return str8_lit("Addr32Nb");
case COFF_Reloc_Arm64_Branch26: return str8_lit("Branch26");
case COFF_Reloc_Arm64_PageBaseRel21: return str8_lit("PageBaseRel21");
case COFF_Reloc_Arm64_Rel21: return str8_lit("Rel21");
case COFF_Reloc_Arm64_PageOffset12a: return str8_lit("PageOffset12a");
case COFF_Reloc_Arm64_SecRel: return str8_lit("SecRel");
case COFF_Reloc_Arm64_SecRelLow12a: return str8_lit("SecRelLow12a");
case COFF_Reloc_Arm64_SecRelHigh12a: return str8_lit("SecRelHigh12a");
case COFF_Reloc_Arm64_SecRelLow12l: return str8_lit("SecRelLow12l");
case COFF_Reloc_Arm64_Token: return str8_lit("Token");
case COFF_Reloc_Arm64_Section: return str8_lit("Section");
case COFF_Reloc_Arm64_Addr64: return str8_lit("Addr64");
case COFF_Reloc_Arm64_Branch19: return str8_lit("Branch19");
case COFF_Reloc_Arm64_Branch14: return str8_lit("Branch14");
case COFF_Reloc_Arm64_Rel32: return str8_lit("Rel32");
}
return str8_zero();
}
internal String8
coff_string_from_reloc(COFF_MachineType machine, COFF_RelocType x)
{
switch (machine) {
case COFF_MachineType_X86: return coff_string_from_reloc_x86(x);
case COFF_MachineType_X64: return coff_string_from_reloc_x64(x);
case COFF_MachineType_Arm: return coff_string_from_reloc_arm(x);
case COFF_MachineType_Arm64: return coff_string_from_reloc_arm64(x);
}
return str8_zero();
}
internal COFF_MachineType
coff_machine_from_string(String8 string)
{
for (U64 i = 0; i < ArrayCount(g_coff_machine_map); ++i) {
if (str8_match(g_coff_machine_map[i].string, string, StringMatchFlag_CaseInsensitive)) {
return g_coff_machine_map[i].machine;
}
}
return COFF_MachineType_Unknown;
}
internal COFF_ImportType
coff_import_header_type_from_string(String8 name)
{
for (U64 i = 0; i < ArrayCount(g_coff_import_header_type_map); ++i) {
if (str8_match(str8_cstring(g_coff_import_header_type_map[i].name), name, StringMatchFlag_CaseInsensitive)) {
return g_coff_import_header_type_map[i].type;
}
}
return COFF_ImportType_Invalid;
}
internal String8
coff_make_lib_member_header(Arena *arena, String8 name, COFF_TimeStamp time_stamp, U16 user_id, U16 group_id, U16 mode, U32 size)
{
Assert(name.size < 16);
Assert(user_id < 10000);
Assert(group_id < 10000);
Assert(mode < 10000);
Assert(size < 1000000000);
Temp scratch = scratch_begin(&arena, 1);
String8List list = {0};
str8_list_pushf(scratch.arena, &list, "%-16.*s", str8_varg(name));
str8_list_pushf(scratch.arena, &list, "%-12u", time_stamp);
str8_list_pushf(scratch.arena, &list, "%-6u", user_id);
str8_list_pushf(scratch.arena, &list, "%-6u", group_id);
str8_list_pushf(scratch.arena, &list, "%-8u", mode);
str8_list_pushf(scratch.arena, &list, "%-10u", size);
str8_list_pushf(scratch.arena, &list, "`\n");
String8 result = str8_list_join(arena, &list, 0);
Assert(result.size == sizeof(COFF_ArchiveMemberHeader));
scratch_end(scratch);
return result;
}