Merge remote-tracking branch 'EpicGamesExt/dev'

This commit is contained in:
2025-01-30 14:44:58 -05:00
89 changed files with 27014 additions and 13480 deletions
+3 -3
View File
@@ -106,8 +106,9 @@ if not "%no_meta%"=="1" (
:: --- Build Everything (@build_targets) --------------------------------------
pushd build
if "%raddbg%"=="1" set didbuild=1 && %compile% ..\src\raddbg\raddbg_main.c %compile_link% %link_icon% %out%raddbg.exe || exit /b 1
if "%radlink%"=="1" set didbuild=1 && %compile% ..\src\linker\lnk.c %compile_link% %link_natvis%"%~dp0\src\linker\linker.natvis" %out%radlink.exe || exit /b 1
if "%rdi_from_pdb%"=="1" set didbuild=1 && %compile% ..\src\rdi_from_pdb\rdi_from_pdb_main.c %compile_link% %out%rdi_from_pdb.exe || exit /b 1
if "%radlink%"=="1" set didbuild=1 && %compile% ..\src\linker\lnk.c %compile_link% %link_natvis%"%~dp0\src\linker\linker.natvis" %out%radlink.exe || exit /b 1
if "%raddump%"=="1" set didbuild=1 && %compile% ..\src\raddump\raddump_main.c %compile_link% %out%raddump.exe || exit /b 1
if "%rdi_from_pdb%"=="1" set didbuild=1 && %compile% ..\src\rdi_from_pdb\rdi_from_pdb_main.c %compile_link% %out%rdi_from_pdb.exe || exit /b 2
if "%rdi_from_dwarf%"=="1" set didbuild=1 && %compile% ..\src\rdi_from_dwarf\rdi_from_dwarf.c %compile_link% %out%rdi_from_dwarf.exe || exit /b 1
if "%rdi_dump%"=="1" set didbuild=1 && %compile% ..\src\rdi_dump\rdi_dump_main.c %compile_link% %out%rdi_dump.exe || exit /b 1
if "%rdi_breakpad_from_pdb%"=="1" set didbuild=1 && %compile% ..\src\rdi_breakpad_from_pdb\rdi_breakpad_from_pdb_main.c %compile_link% %out%rdi_breakpad_from_pdb.exe || exit /b 1
@@ -117,7 +118,6 @@ if "%textperf%"=="1" set didbuild=1 && %compile% ..\src\scratc
if "%convertperf%"=="1" set didbuild=1 && %compile% ..\src\scratch\convertperf.c %compile_link% %out%convertperf.exe || exit /b 1
if "%debugstringperf%"=="1" set didbuild=1 && %compile% ..\src\scratch\debugstringperf.c %compile_link% %out%debugstringperf.exe || exit /b 1
if "%parse_inline_sites%"=="1" set didbuild=1 && %compile% ..\src\scratch\parse_inline_sites.c %compile_link% %out%parse_inline_sites.exe || exit /b 1
if "%coffdump%"=="1" set didbuild=1 && %compile% ..\src\dumpers\coffdump.c %compile_link% %out%coffdump.exe || exit /b 1
if "%mule_main%"=="1" set didbuild=1 && del vc*.pdb mule*.pdb && %compile_release% %only_compile% ..\src\mule\mule_inline.cpp && %compile_release% %only_compile% ..\src\mule\mule_o2.cpp && %compile_debug% %EHsc% ..\src\mule\mule_main.cpp ..\src\mule\mule_c.c mule_inline.obj mule_o2.obj %compile_link% %no_aslr% %out%mule_main.exe || exit /b 1
if "%mule_module%"=="1" set didbuild=1 && %compile% ..\src\mule\mule_module.cpp %compile_link% %link_dll% %out%mule_module.dll || exit /b 1
if "%mule_hotload%"=="1" set didbuild=1 && %compile% ..\src\mule\mule_hotload_main.c %compile_link% %out%mule_hotload.exe & %compile% ..\src\mule\mule_hotload_module_main.c %compile_link% %link_dll% %out%mule_hotload_module.dll || exit /b 1
+9
View File
@@ -454,6 +454,15 @@ typedef enum OperatingSystem
}
OperatingSystem;
typedef enum ImageType
{
Image_Null,
Image_CoffPe,
Image_Elf32,
Image_Elf64,
Image_Macho
} ImageType;
typedef enum Arch
{
Arch_Null,
+19
View File
@@ -600,6 +600,25 @@ rng1u64_list_push(Arena *arena, Rng1U64List *list, Rng1U64 rng)
list->count += 1;
}
internal void
rng1u64_list_concat(Rng1U64List *list, Rng1U64List *to_concat)
{
if(to_concat->first)
{
if(list->first)
{
list->last->next = to_concat->first;
list->last = to_concat->last;
}
else
{
list->first = to_concat->first;
list->last = to_concat->last;
}
MemoryZeroStruct(to_concat);
}
}
internal Rng1U64Array
rng1u64_array_from_list(Arena *arena, Rng1U64List *list)
{
+1
View File
@@ -666,6 +666,7 @@ internal U32 u32_from_rgba(Vec4F32 rgba);
//~ rjf: List Type Functions
internal void rng1u64_list_push(Arena *arena, Rng1U64List *list, Rng1U64 rng);
internal void rng1u64_list_concat(Rng1U64List *list, Rng1U64List *to_concat);
internal Rng1U64Array rng1u64_array_from_list(Arena *arena, Rng1U64List *list);
internal void rng1s64_list_push(Arena *arena, Rng1S64List *list, Rng1S64 rng);
+74
View File
@@ -2370,3 +2370,77 @@ str8_deserial_read_block(String8 string, U64 off, U64 size, String8 *block_out)
*block_out = str8_substr(string, range);
return block_out->size;
}
internal U64
str8_deserial_read_uleb128(String8 string, U64 off, U64 *value_out)
{
U64 value = 0;
U64 shift = 0;
U64 cursor = off;
for(;;)
{
U8 byte = 0;
U64 bytes_read = str8_deserial_read_struct(string, cursor, &byte);
if(bytes_read != sizeof(byte))
{
break;
}
U8 val = byte & 0x7fu;
value |= ((U64)val) << shift;
cursor += bytes_read;
shift += 7u;
if((byte & 0x80u) == 0)
{
break;
}
}
if(value_out != 0)
{
*value_out = value;
}
U64 bytes_read = cursor - off;
return bytes_read;
}
internal U64
str8_deserial_read_sleb128(String8 string, U64 off, S64 *value_out)
{
U64 value = 0;
U64 shift = 0;
U64 cursor = off;
for(;;)
{
U8 byte;
U64 bytes_read = str8_deserial_read_struct(string, cursor, &byte);
if(bytes_read != sizeof(byte))
{
break;
}
U8 val = byte & 0x7fu;
value |= ((U64)val) << shift;
cursor += bytes_read;
shift += 7u;
if((byte & 0x80u) == 0)
{
if(shift < sizeof(value) * 8 && (byte & 0x40u) != 0)
{
value |= -(S64)(1ull << shift);
}
break;
}
}
if(value_out != 0)
{
*value_out = value;
}
U64 bytes_read = cursor - off;
return bytes_read;
}
+5
View File
@@ -206,10 +206,13 @@ internal String8 backslashed_from_str8(Arena *arena, String8 string);
////////////////////////////////
//~ rjf: String Matching
#define str8_match_lit(a_lit, b, flags) str8_match(str8_lit(a_lit), (b), (flags))
#define str8_match_cstr(a_cstr, b, flags) str8_match(str8_cstring(a_cstr), (b), (flags))
internal B32 str8_match(String8 a, String8 b, StringMatchFlags flags);
internal U64 str8_find_needle(String8 string, U64 start_pos, String8 needle, StringMatchFlags flags);
internal U64 str8_find_needle_reverse(String8 string, U64 start_pos, String8 needle, StringMatchFlags flags);
internal B32 str8_ends_with(String8 string, String8 end, StringMatchFlags flags);
#define str8_ends_with_lit(string, end_lit, flags) str8_ends_with((string), str8_lit(end_lit), (flags))
////////////////////////////////
//~ rjf: String Slicing
@@ -404,6 +407,8 @@ internal void * str8_deserial_get_raw_ptr(String8 string, U64 off, U64 size);
internal U64 str8_deserial_read_cstr(String8 string, U64 off, String8 *cstr_out);
internal U64 str8_deserial_read_windows_utf16_string16(String8 string, U64 off, String16 *str_out);
internal U64 str8_deserial_read_block(String8 string, U64 off, U64 size, String8 *block_out);
internal U64 str8_deserial_read_uleb128(String8 string, U64 off, U64 *value_out);
internal U64 str8_deserial_read_sleb128(String8 string, U64 off, S64 *value_out);
#define str8_deserial_read_array(string, off, ptr, count) str8_deserial_read((string), (off), (ptr), sizeof(*(ptr))*(count), sizeof(*(ptr)))
#define str8_deserial_read_struct(string, off, ptr) str8_deserial_read_array(string, off, ptr, 1)
+54 -1428
View File
File diff suppressed because it is too large Load Diff
+1317 -1542
View File
File diff suppressed because it is too large Load Diff
+971
View File
@@ -0,0 +1,971 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
internal String8
cv_string_from_unknown_value(Arena *arena, U32 x)
{
return push_str8f(arena, "%#x", x);
}
internal String8
cv_string_from_type_index_source(CV_TypeIndexSource ti_source)
{
switch (ti_source) {
case CV_TypeIndexSource_NULL: return str8_lit(""); break;
case CV_TypeIndexSource_TPI: return str8_lit("TPI"); break;
case CV_TypeIndexSource_IPI: return str8_lit("IPI"); break;
case CV_TypeIndexSource_COUNT: break;
}
return str8_zero();
}
internal String8
cv_string_from_language(CV_Language x)
{
switch (x) {
#define X(_n,_i) case _i: return str8_lit(Stringify(_n));
CV_LanguageXList(X)
#undef X
}
return str8_zero();
}
internal String8
cv_string_from_numeric(Arena *arena, CV_NumericParsed num)
{
String8 result = str8_zero();
switch (num.kind) {
case CV_NumericKind_FLOAT16: NotImplemented; break; // TODO: format float16
case CV_NumericKind_FLOAT32: result = push_str8f(arena, "%f", (F64)(*(F32*)num.val)); break;
case CV_NumericKind_FLOAT48: NotImplemented; break; // TODO: format float48
case CV_NumericKind_FLOAT64: result = push_str8f(arena, "%f", *(F64*)num.val); break;
case CV_NumericKind_FLOAT80: NotImplemented; break; // TODO: format float80
case CV_NumericKind_FLOAT128: NotImplemented; break; // TODO: format float128
case CV_NumericKind_CHAR: result = push_str8f(arena, "%d", *(S8 *)num.val); break;
case CV_NumericKind_SHORT: result = push_str8f(arena, "%d", *(S16*)num.val); break;
case CV_NumericKind_LONG: result = push_str8f(arena, "%d", *(S32*)num.val); break;
case CV_NumericKind_QUADWORD: result = push_str8f(arena, "%lld", *(S64*)num.val); break;
case CV_NumericKind_USHORT: result = push_str8f(arena, "%u", *(U16*)num.val); break;
case CV_NumericKind_ULONG: result = push_str8f(arena, "%u", *(U32*)num.val); break;
case CV_NumericKind_UQUADWORD: result = push_str8f(arena, "%llu", *(U64*)num.val); break;
}
return result;
}
internal String8
cv_string_from_reg_id(Arena *arena, CV_Arch arch, U32 id)
{
String8 result = str8_zero();
switch (arch) {
case CV_Arch_8086: {
switch (id) {
#define X(_N, _ID, ...) case _ID: result = str8_lit(Stringify(_N)); break;
CV_Reg_X86_XList(X)
#undef X
}
} break;
case CV_Arch_X64: {
switch (id) {
#define X(_N, _ID, ...) case _ID: result = str8_lit(Stringify(_N)); break;
CV_Reg_X64_XList(X)
#undef X
}
} break;
default: NotImplemented; break;
}
if (result.size == 0) {
result = push_str8f(arena, "%x", id);
}
return result;
}
internal String8
cv_string_from_member_access(CV_MemberAccess x)
{
switch (x) {
case CV_MemberAccess_Null: break;
case CV_MemberAccess_Private: return str8_lit("Private");
case CV_MemberAccess_Protected: return str8_lit("Protected");
case CV_MemberAccess_Public: return str8_lit("Public");
}
return str8_zero();
}
internal String8
cv_string_from_method_prop(CV_MethodProp x)
{
switch (x) {
case CV_MethodProp_Vanilla: return str8_lit("Vanilla");
case CV_MethodProp_Virtual: return str8_lit("Virtual");
case CV_MethodProp_Static: return str8_lit("Static");
case CV_MethodProp_Friend: return str8_lit("Friend");
case CV_MethodProp_Intro: return str8_lit("Intro");
case CV_MethodProp_PureVirtual: return str8_lit("PureVirtual");
case CV_MethodProp_PureIntro: return str8_lit("PureIntro");
}
return str8_zero();
}
internal String8
cv_string_from_hfa(CV_HFAKind x)
{
switch (x) {
case CV_HFAKind_None: return str8_lit("None");
case CV_HFAKind_Float: return str8_lit("Float");
case CV_HFAKind_Double: return str8_lit("Double");
case CV_HFAKind_Other: return str8_lit("Other");
}
return str8_zero();
}
internal String8
cv_string_from_mcom(CV_MoComUDTKind x)
{
switch (x) {
case CV_MoComUDTKind_None: return str8_lit("None");
case CV_MoComUDTKind_Ref: return str8_lit("Ref");
case CV_MoComUDTKind_Value: return str8_lit("Value");
case CV_MoComUDTKind_Interface: return str8_lit("Interface");
}
return str8_zero();
}
internal String8
cv_string_from_binary_opcode(CV_InlineBinaryAnnotation x)
{
switch (x) {
case CV_InlineBinaryAnnotation_Null: break;
case CV_InlineBinaryAnnotation_CodeOffset: return str8_lit("CodeOffset");
case CV_InlineBinaryAnnotation_ChangeCodeOffsetBase: return str8_lit("ChangeCodeOffsetBase");
case CV_InlineBinaryAnnotation_ChangeCodeOffset: return str8_lit("ChangeCodeOffset");
case CV_InlineBinaryAnnotation_ChangeCodeLength: return str8_lit("ChangeCodeLength");
case CV_InlineBinaryAnnotation_ChangeFile: return str8_lit("ChangeFile");
case CV_InlineBinaryAnnotation_ChangeLineOffset: return str8_lit("ChangeLineOffset");
case CV_InlineBinaryAnnotation_ChangeLineEndDelta: return str8_lit("ChangeLineEndDelta");
case CV_InlineBinaryAnnotation_ChangeRangeKind: return str8_lit("ChangeRangeKind");
case CV_InlineBinaryAnnotation_ChangeColumnStart: return str8_lit("ChangeColumnStart");
case CV_InlineBinaryAnnotation_ChangeColumnEndDelta: return str8_lit("ChangeColumnEndDelta");
case CV_InlineBinaryAnnotation_ChangeCodeOffsetAndLineOffset: return str8_lit("ChangeCodeOffsetAndLineOffset");
case CV_InlineBinaryAnnotation_ChangeCodeLengthAndCodeOffset: return str8_lit("ChangeCodeLengthAndCodeOffset");
case CV_InlineBinaryAnnotation_ChangeColumnEnd: return str8_lit("ChangeColumnEnd");
}
return str8_zero();
}
internal String8
cv_string_from_thunk_ordinal(CV_ThunkOrdinal x)
{
switch (x) {
case CV_ThunkOrdinal_NoType: return str8_lit("NoType");
case CV_ThunkOrdinal_Adjustor: return str8_lit("Adjustor");
case CV_ThunkOrdinal_VCall: return str8_lit("VCall");
case CV_ThunkOrdinal_PCode: return str8_lit("PCode");
case CV_ThunkOrdinal_Load: return str8_lit("Load");
case CV_ThunkOrdinal_TrampIncremental: return str8_lit("TrampIncremental");
case CV_ThunkOrdinal_TrampBranchIsland: return str8_lit("TrampBranchIsland");
}
return str8_zero();
}
internal String8
cv_string_from_frame_cookie_kind(CV_FrameCookieKind x)
{
switch (x) {
case CV_FrameCookieKind_Copy: return str8_lit("Copy");
case CV_FrameCookieKind_XorSP: return str8_lit("XorSP");
case CV_FrameCookieKind_XorBP: return str8_lit("XorR13");
}
return str8_zero();
}
internal String8
cv_string_from_generic_style(CV_GenericStyle x)
{
switch (x) {
case CV_GenericStyle_VOID: return str8_lit("VOID");
case CV_GenericStyle_REG: return str8_lit("REG");
case CV_GenericStyle_ICAN: return str8_lit("ICAN");
case CV_GenericStyle_ICAF: return str8_lit("ICAF");
case CV_GenericStyle_IRAN: return str8_lit("IRAN");
case CV_GenericStyle_IRAF: return str8_lit("IRAF");
case CV_GenericStyle_UNUSED: return str8_lit("UNUSED");
}
return str8_zero();
}
internal String8
cv_string_from_trampoline_kind(CV_TrampolineKind x)
{
switch (x) {
case CV_TrampolineKind_Incremental: return str8_lit("Incremental");
case CV_TrampolineKind_BranchIsland: return str8_lit("BranchIsland");
}
return str8_zero();
}
internal String8
cv_string_from_virtual_table_shape_kind(CV_VirtualTableShape x)
{
switch (x) {
case CV_VirtualTableShape_Near: return str8_lit("Near");
case CV_VirtualTableShape_Far: return str8_lit("Far");
case CV_VirtualTableShape_Thin: return str8_lit("Thin");
case CV_VirtualTableShape_Outer: return str8_lit("Outer");
case CV_VirtualTableShape_Meta: return str8_lit("Meta");
case CV_VirtualTableShape_Near32: return str8_lit("Near32");
case CV_VirtualTableShape_Far32: return str8_lit("Far32");
}
return str8_zero();
}
internal String8
cv_string_from_call_kind(CV_CallKind x)
{
switch (x) {
case CV_CallKind_NearC: return str8_lit("NearC");
case CV_CallKind_FarC: return str8_lit("FarC");
case CV_CallKind_NearPascal: return str8_lit("NearPascal");
case CV_CallKind_FarPascal: return str8_lit("FarPascal");
case CV_CallKind_NearFast: return str8_lit("NearFast");
case CV_CallKind_FarFast: return str8_lit("FarFast");
case CV_CallKind_UNUSED: return str8_lit("UNUSED");
case CV_CallKind_NearStd: return str8_lit("NearStd");
case CV_CallKind_FarStd: return str8_lit("FarStd");
case CV_CallKind_NearSys: return str8_lit("NearSys");
case CV_CallKind_FarSys: return str8_lit("FarSys");
case CV_CallKind_This: return str8_lit("This");
case CV_CallKind_Mips: return str8_lit("Mips");
case CV_CallKind_Generic: return str8_lit("Generic");
case CV_CallKind_Alpha: return str8_lit("Alpha");
case CV_CallKind_PPC: return str8_lit("PPC");
case CV_CallKind_HitachiSuperH: return str8_lit("HitachiSuperH");
case CV_CallKind_Arm: return str8_lit("Arm");
case CV_CallKind_AM33: return str8_lit("AM33");
case CV_CallKind_TriCore: return str8_lit("TriCore");
case CV_CallKind_HitachiSuperH5: return str8_lit("HitachiSuperH5");
case CV_CallKind_M32R: return str8_lit("M32R");
case CV_CallKind_Clr: return str8_lit("Clr");
case CV_CallKind_Inline: return str8_lit("Inline");
case CV_CallKind_NearVector: return str8_lit("NearVector");
}
return str8_zero();
}
internal String8
cv_string_from_member_pointer_kind(CV_MemberPointerKind x)
{
switch (x) {
case CV_MemberPointerKind_Undef: return str8_lit("Undef");
case CV_MemberPointerKind_DataSingle: return str8_lit("DataSingle");
case CV_MemberPointerKind_DataMultiple: return str8_lit("DataMultiple");
case CV_MemberPointerKind_DataVirtual: return str8_lit("DataVirtual");
case CV_MemberPointerKind_DataGeneral: return str8_lit("DataGeneral");
case CV_MemberPointerKind_FuncSingle: return str8_lit("FuncSingle");
case CV_MemberPointerKind_FuncMultiple: return str8_lit("FuncMultiple");
case CV_MemberPointerKind_FuncGeneral: return str8_lit("FuncGeneral");
}
return str8_zero();
}
internal String8
cv_string_from_pointer_kind(CV_PointerKind x)
{
switch (x) {
case CV_PointerKind_Near: return str8_lit("Near");
case CV_PointerKind_Far: return str8_lit("Far");
case CV_PointerKind_Huge: return str8_lit("Huge");
case CV_PointerKind_BaseSeg: return str8_lit("BaseSeg");
case CV_PointerKind_BaseVal: return str8_lit("BaseVal");
case CV_PointerKind_BaseSegVal: return str8_lit("BaseSegVal");
case CV_PointerKind_BaseAddr: return str8_lit("BaseAddr");
case CV_PointerKind_BaseSegAddr: return str8_lit("BaseSegAddr");
case CV_PointerKind_BaseType: return str8_lit("BaseType");
case CV_PointerKind_BaseSelf: return str8_lit("BaseSelf");
case CV_PointerKind_Near32: return str8_lit("Near32");
case CV_PointerKind_Far32: return str8_lit("Far32");
case CV_PointerKind_64: return str8_lit("64Bit");
}
return str8_zero();
}
internal String8
cv_string_from_pointer_mode(CV_PointerMode x)
{
switch (x) {
case CV_PointerMode_Ptr: return str8_lit("Ptr");
case CV_PointerMode_LRef: return str8_lit("LRef");
case CV_PointerMode_PtrMem: return str8_lit("PtrMem");
case CV_PointerMode_PtrMethod: return str8_lit("PtrMethod");
case CV_PointerMode_RRef: return str8_lit("RRef");
}
return str8_zero();
}
internal String8
cv_string_from_c13_checksum_kind(CV_C13ChecksumKind x)
{
switch (x) {
case CV_C13ChecksumKind_Null: break;
case CV_C13ChecksumKind_MD5: return str8_lit("MD5");
case CV_C13ChecksumKind_SHA1: return str8_lit("SHA1");
case CV_C13ChecksumKind_SHA256: return str8_lit("SHA256");
}
return str8_zero();
}
internal String8
cv_string_from_label_kind(Arena *arena, CV_LabelKind x)
{
switch (x) {
case CV_LabelKind_Near: return str8_lit("Near");
case CV_LabelKind_Far: return str8_lit("Far");
}
return cv_string_from_unknown_value(arena, x);
}
internal String8
cv_string_from_c13_subsection_kind(CV_C13SubSectionKind x)
{
switch (x) {
#define X(_N, _ID) case CV_C13SubSectionKind_##_N: return str8_lit(Stringify(_N));
CV_C13SubSectionKindXList(X)
#undef X
}
return str8_zero();
}
internal String8
cv_string_from_modifier_flags(Arena *arena, CV_ModifierFlags x)
{
Temp scratch = scratch_begin(&arena, 1);
String8List list = {0};
if (x & CV_ModifierFlag_Const) {
str8_list_pushf(scratch.arena, &list, "Const");
}
if (x & CV_ModifierFlag_Volatile) {
str8_list_pushf(scratch.arena, &list, "Volatile");
}
if (x & CV_ModifierFlag_Unaligned) {
str8_list_pushf(scratch.arena, &list, "Unaligned");
}
String8 result = str8_list_join(arena, &list, &(StringJoin){.sep=str8_lit(", ")});
scratch_end(scratch);
return result;
}
internal String8
cv_string_from_pointer_attribs(Arena *arena, CV_PointerAttribs x)
{
Temp scratch = scratch_begin(&arena, 1);
String8List list = {0};
if (x & CV_PointerAttrib_IsFlat) {
x &= ~CV_PointerAttrib_IsFlat;
str8_list_pushf(scratch.arena, &list, "IsFlat");
}
if (x & CV_PointerAttrib_Volatile) {
x &= ~CV_PointerAttrib_Volatile;
str8_list_pushf(scratch.arena, &list, "Volatile");
}
if (x & CV_PointerAttrib_Const) {
x &= ~CV_PointerAttrib_Const;
str8_list_pushf(scratch.arena, &list, "Const");
}
if (x & CV_PointerAttrib_Unaligned) {
x &= ~CV_PointerAttrib_Unaligned;
str8_list_pushf(scratch.arena, &list, "Unaligned");
}
if (x & CV_PointerAttrib_Restricted) {
x &= ~CV_PointerAttrib_Restricted;
str8_list_pushf(scratch.arena, &list, "Restricted");
}
if (x & CV_PointerAttrib_MOCOM) {
x &= ~CV_PointerAttrib_MOCOM;
str8_list_pushf(scratch.arena, &list, "MOCOM");
}
if (x & CV_PointerAttrib_LRef) {
x &= ~CV_PointerAttrib_LRef;
str8_list_pushf(scratch.arena, &list, "LRef");
}
if (x & CV_PointerAttrib_RRef) {
x &= ~CV_PointerAttrib_RRef;
str8_list_pushf(scratch.arena, &list, "RRef");
}
CV_PointerKind kind = CV_PointerAttribs_Extract_Kind(x);
CV_PointerMode mode = CV_PointerAttribs_Extract_Mode(x);
U64 size = CV_PointerAttribs_Extract_Size(x);
x &= ~(0x1f|(0x7<<5)|(0x3f<<13));
if (kind) {
String8 kind_str = cv_string_from_pointer_kind(kind);
str8_list_pushf(scratch.arena, &list, "Kind=%S", kind_str);
}
if (mode) {
String8 mode_str = cv_string_from_pointer_mode(mode);
str8_list_pushf(scratch.arena, &list, "Mode=%S", mode_str);
}
if (size) {
str8_list_pushf(scratch.arena, &list, "Size=%llu", size);
}
if (x != 0) {
str8_list_pushf(scratch.arena, &list, "Unknown=%x", x);
}
String8 result = str8_list_join(arena, &list, &(StringJoin){.sep=str8_lit(", ")});
scratch_end(scratch);
return result;
}
internal String8
cv_string_from_function_attribs(Arena *arena, CV_FunctionAttribs x)
{
Temp scratch = scratch_begin(&arena, 1);
String8List list = {0};
if (x & CV_FunctionAttrib_CxxReturnUDT) {
str8_list_pushf(scratch.arena, &list, "CxxReturnUDT");
}
if (x & CV_FunctionAttrib_Constructor) {
str8_list_pushf(scratch.arena, &list, "Constructor");
}
if (x & CV_FunctionAttrib_ConstructorVBase) {
str8_list_pushf(scratch.arena, &list, "ConstructorVBase");
}
String8 result = str8_list_join(arena, &list, &(StringJoin){.sep=str8_lit(", ")});
scratch_end(scratch);
return result;
}
internal String8
cv_string_from_export_flags(Arena *arena, CV_ExportFlags x)
{
Temp scratch = scratch_begin(&arena, 1);
String8List list = {0};
if (x & CV_ExportFlag_Constant) {
str8_list_pushf(scratch.arena, &list, "Constant");
}
if (x & CV_ExportFlag_Data) {
str8_list_pushf(scratch.arena, &list, "Data");
}
if (x & CV_ExportFlag_Private) {
str8_list_pushf(scratch.arena, &list, "Private");
}
if (x & CV_ExportFlag_NoName) {
str8_list_pushf(scratch.arena, &list, "NoName");
}
if (x & CV_ExportFlag_Ordinal) {
str8_list_pushf(scratch.arena, &list, "Ordinal");
}
if (x & CV_ExportFlag_Forwarder) {
str8_list_pushf(scratch.arena, &list, "Forwarder");
}
String8 result = str8_list_join(arena, &list, &(StringJoin){.sep=str8_lit(", ")});
scratch_end(scratch);
return result;
}
internal String8
cv_string_from_sepcode(Arena *arena, CV_SepcodeFlags x)
{
Temp scratch = scratch_begin(&arena,1);
String8List list = {0};
if (x & CV_SepcodeFlag_IsLexicalScope) {
str8_list_pushf(scratch.arena, &list, "IsLexicalScope");
}
if (x & CV_SepcodeFlag_ReturnsToParent) {
str8_list_pushf(scratch.arena, &list, "ReturnsToParent");
}
String8 result = str8_list_join(arena, &list, &(StringJoin){.sep=str8_lit(", ")});
scratch_end(scratch);
return result;
}
internal String8
cv_string_from_pub32_flags(Arena *arena, CV_Pub32Flags x)
{
Temp scratch = scratch_begin(&arena, 1);
String8List list = {0};
if (x & CV_Pub32Flag_Code) {
str8_list_pushf(scratch.arena, &list, "Code");
}
if (x & CV_Pub32Flag_Function) {
str8_list_pushf(scratch.arena, &list, "Function");
}
if (x & CV_Pub32Flag_ManagedCode) {
str8_list_pushf(scratch.arena, &list, "ManagedCode");
}
if (x & CV_Pub32Flag_MSIL) {
str8_list_pushf(scratch.arena, &list, "MSIL");
}
String8 result = str8_list_join(scratch.arena, &list, &(StringJoin){.sep=str8_lit(", ")});
scratch_end(scratch);
return result;
}
internal String8
cv_string_from_generic_flags(Arena *arena, CV_GenericFlags x)
{
Temp scratch = scratch_begin(&arena, 1);
String8List list = {0};
if (x & CV_GenericFlags_CSTYLE) {
str8_list_pushf(scratch.arena, &list, "CSTYLE");
}
if (x & CV_GenericFlags_RSCLEAN) {
str8_list_pushf(scratch.arena, &list, "RSCLEAN");
}
String8 result = str8_list_join(arena, &list, &(StringJoin){.sep=str8_lit(", ")});
scratch_end(scratch);
return result;
}
internal String8
cv_string_from_frame_proc_flags(Arena *arena, CV_FrameprocFlags x)
{
Temp scratch = scratch_begin(&arena, 1);
String8List list = {0};
if (x & CV_FrameprocFlag_UsesAlloca) {
str8_list_pushf(scratch.arena, &list, "UsesAlloca");
}
if (x & CV_FrameprocFlag_UsesSetJmp) {
str8_list_pushf(scratch.arena, &list, "UsesSetJmp");
}
if (x & CV_FrameprocFlag_UsesLongJmp) {
str8_list_pushf(scratch.arena, &list, "UsesLongJmp");
}
if (x & CV_FrameprocFlag_UsesInlAsm) {
str8_list_pushf(scratch.arena, &list, "UsesInlAsm");
}
if (x & CV_FrameprocFlag_UsesEH) {
str8_list_pushf(scratch.arena, &list, "UsesEH");
}
if (x & CV_FrameprocFlag_Inline) {
str8_list_pushf(scratch.arena, &list, "Inline");
}
if (x & CV_FrameprocFlag_HasSEH) {
str8_list_pushf(scratch.arena, &list, "HasSEH");
}
if (x & CV_FrameprocFlag_Naked) {
str8_list_pushf(scratch.arena, &list, "Naked");
}
if (x & CV_FrameprocFlag_HasSecurityChecks) {
str8_list_pushf(scratch.arena, &list, "HasSecurityChecks");
}
if (x & CV_FrameprocFlag_AsyncEH) {
str8_list_pushf(scratch.arena, &list, "AsyncEH");
}
if (x & CV_FrameprocFlag_GSNoStackOrdering) {
str8_list_pushf(scratch.arena, &list, "GSNoStackOrdering");
}
if (x & CV_FrameprocFlag_WasInlined) {
str8_list_pushf(scratch.arena, &list, "WasInlined");
}
if (x & CV_FrameprocFlag_GSCheck) {
str8_list_pushf(scratch.arena, &list, "GSCheck");
}
if (x & CV_FrameprocFlag_SafeBuffers) {
str8_list_pushf(scratch.arena, &list, "SafeBuffers");
}
if (x & CV_FrameprocFlag_PogoOn) {
str8_list_pushf(scratch.arena, &list, "PogoOn");
}
if (x & CV_FrameprocFlag_PogoCountsValid) {
str8_list_pushf(scratch.arena, &list, "PogoCountsValid");
}
if (x & CV_FrameprocFlag_OptSpeed) {
str8_list_pushf(scratch.arena, &list, "OptSpeed");
}
if (x & CV_FrameprocFlag_HasCFG) {
str8_list_pushf(scratch.arena, &list, "HasCFG");
}
if (x & CV_FrameprocFlag_HasCFW) {
str8_list_pushf(scratch.arena, &list, "HasCFW");
}
String8 result = str8_list_join(arena, &list, &(StringJoin){.sep=str8_lit(", ")});
scratch_end(scratch);
return result;
}
internal String8
cv_string_from_type_props(Arena *arena, CV_TypeProps32 x)
{
Temp scratch = scratch_begin(&arena, 1);
U32 hfa = CV_TypeProps_Extract_HFA(x);
U32 mcom = CV_TypeProps_Extract_MOCOM(x);
String8 hfa_str = cv_string_from_hfa(hfa);
String8 mcom_str = cv_string_from_mcom(mcom);
String8 flags_str;
{
String8List list = {0};
if (x & CV_TypeProp_Packed) {
x &= ~CV_TypeProp_Packed;
str8_list_pushf(scratch.arena, &list, "Packed");
}
if (x & CV_TypeProp_HasConstructorsDestructors) {
x &= ~CV_TypeProp_HasConstructorsDestructors;
str8_list_pushf(scratch.arena, &list, "HasConstructorsDestructors");
}
if (x & CV_TypeProp_OverloadedOperators) {
x &= ~CV_TypeProp_OverloadedOperators;
str8_list_pushf(scratch.arena, &list, "OverloadedOperators");
}
if (x & CV_TypeProp_IsNested) {
x &= ~CV_TypeProp_IsNested;
str8_list_pushf(scratch.arena, &list, "IsNested");
}
if (x & CV_TypeProp_ContainsNested) {
x &= ~CV_TypeProp_ContainsNested;
str8_list_pushf(scratch.arena, &list, "ContainsNested");
}
if (x & CV_TypeProp_OverloadedAssignment) {
x &= ~CV_TypeProp_OverloadedAssignment;
str8_list_pushf(scratch.arena, &list, "OverloadedAssignment");
}
if (x & CV_TypeProp_OverloadedCasting) {
x &= ~CV_TypeProp_OverloadedCasting;
str8_list_pushf(scratch.arena, &list, "OverloadedCasting");
}
if (x & CV_TypeProp_FwdRef) {
x &= ~CV_TypeProp_FwdRef;
str8_list_pushf(scratch.arena, &list, "FwdRef");
}
if (x & CV_TypeProp_Scoped) {
x &= ~CV_TypeProp_Scoped;
str8_list_pushf(scratch.arena, &list, "Scoped");
}
if (x & CV_TypeProp_HasUniqueName) {
x &= ~CV_TypeProp_HasUniqueName;
str8_list_pushf(scratch.arena, &list, "HasUniqueName");
}
if (x & CV_TypeProp_Sealed) {
x &= ~CV_TypeProp_Sealed;
str8_list_pushf(scratch.arena, &list, "Sealed");
}
if (x & CV_TypeProp_Intrinsic) {
x &= ~CV_TypeProp_Intrinsic;
str8_list_pushf(scratch.arena, &list, "Intrinsic");
}
if (x != 0) {
str8_list_pushf(scratch.arena, &list, "%x", x);
}
flags_str = str8_list_join(scratch.arena, &list, &(StringJoin){.sep=str8_lit(", ") });
if (hfa) {
str8_list_pushf(scratch.arena, &list, "HFA = %S", hfa_str);
}
if (mcom) {
str8_list_pushf(scratch.arena, &list, "MCOM = %S", mcom_str);
}
}
String8 result = push_str8f(arena, "%S", flags_str);
scratch_end(scratch);
return result;
}
internal String8
cv_string_from_local_flags(Arena *arena, CV_LocalFlags x)
{
Temp scratch = scratch_begin(&arena, 1);
String8List list = {0};
if (x & CV_LocalFlag_Param) {
str8_list_pushf(scratch.arena, &list, "Param");
}
if (x & CV_LocalFlag_AddrTaken) {
str8_list_pushf(scratch.arena, &list, "AddrTaken");
}
if (x & CV_LocalFlag_Compgen) {
str8_list_pushf(scratch.arena, &list, "Compgen");
}
if (x & CV_LocalFlag_Aggregate) {
str8_list_pushf(scratch.arena, &list, "Aggregate");
}
if (x & CV_LocalFlag_PartOfAggregate) {
str8_list_pushf(scratch.arena, &list, "PartOfAggregate");
}
if (x & CV_LocalFlag_Aliased) {
str8_list_pushf(scratch.arena, &list, "Aliased");
}
if (x & CV_LocalFlag_Alias) {
str8_list_pushf(scratch.arena, &list, "Alias");
}
if (x & CV_LocalFlag_Retval) {
str8_list_pushf(scratch.arena, &list, "Retval");
}
if (x & CV_LocalFlag_OptOut) {
str8_list_pushf(scratch.arena, &list, "OptOut");
}
if (x & CV_LocalFlag_Global) {
str8_list_pushf(scratch.arena, &list, "Global");
}
if (x & CV_LocalFlag_Static) {
str8_list_pushf(scratch.arena, &list, "Static");
}
String8 result = str8_list_join(arena, &list, &(StringJoin){.sep=str8_lit(", ")});
scratch_end(scratch);
return result;
}
internal String8
cv_string_from_proc_flags(Arena *arena, CV_ProcFlags x)
{
Temp scratch = scratch_begin(&arena, 1);
String8List list = {0};
if (x & CV_ProcFlag_NoFPO) {
x &= ~CV_ProcFlag_NoFPO;
str8_list_pushf(scratch.arena, &list, "NoFPO");
}
if (x & CV_ProcFlag_IntReturn) {
x &= ~CV_ProcFlag_IntReturn;
str8_list_pushf(scratch.arena, &list, "IntReturn");
}
if (x & CV_ProcFlag_FarReturn) {
x &= ~CV_ProcFlag_FarReturn;
str8_list_pushf(scratch.arena, &list, "FarReturn");
}
if (x & CV_ProcFlag_NeverReturn) {
x &= ~CV_ProcFlag_NeverReturn;
str8_list_pushf(scratch.arena, &list, "NeverReturn");
}
if (x & CV_ProcFlag_NotReached) {
x &= ~CV_ProcFlag_NotReached;
str8_list_pushf(scratch.arena, &list, "NotReached");
}
if (x & CV_ProcFlag_CustomCall) {
x &= ~CV_ProcFlag_CustomCall;
str8_list_pushf(scratch.arena, &list, "CustomCall");
}
if (x & CV_ProcFlag_NoInline) {
x &= ~CV_ProcFlag_NoInline;
str8_list_pushf(scratch.arena, &list, "NoInline");
}
if (x & CV_ProcFlag_OptDbgInfo) {
x &= ~CV_ProcFlag_OptDbgInfo;
str8_list_pushf(scratch.arena, &list, "OptDbgInfo");
}
if (x != 0) {
str8_list_pushf(scratch.arena, &list, "%#x", x);
}
String8 result;
if (list.node_count == 0) {
result = str8_lit("None");
} else {
result = str8_list_join(arena, &list, &(StringJoin){.sep=str8_lit(", ")});
}
temp_end(scratch);
return result;
}
internal String8
cv_string_from_range_attribs(Arena *arena, CV_RangeAttribs x)
{ (void)arena;
String8 result = str8_lit("None");
if (x == CV_RangeAttrib_Maybe) {
result = str8_lit("Maybe");
}
return result;
}
internal String8
cv_string_from_defrange_register_rel_flags(Arena *arena, CV_DefrangeRegisterRelFlags x)
{ (void)arena;
String8 result = str8_lit("None");
if (x == CV_DefrangeRegisterRelFlag_SpilledOutUDTMember) {
result = str8_lit("SpilledOutUDTMember");
}
return result;
}
internal String8
cv_string_from_field_attribs(Arena *arena, CV_FieldAttribs attribs)
{
Temp scratch = scratch_begin(&arena, 1);
U32 access = CV_FieldAttribs_Extract_Access(attribs);
U32 mprop = CV_FieldAttribs_Extract_MethodProp(attribs);
attribs &= ~(0x3 | 0x7);
String8 access_str = cv_string_from_member_access(access);
String8 mprop_str = cv_string_from_method_prop(mprop);
String8List list = {0};
{
if (attribs & CV_FieldAttrib_Pseudo) {
attribs &= ~CV_FieldAttrib_Pseudo;
str8_list_pushf(scratch.arena, &list, "Pseudo");
}
if (attribs & CV_FieldAttrib_NoInherit) {
attribs &= ~CV_FieldAttrib_NoInherit;
str8_list_pushf(scratch.arena, &list, "NoInherit");
}
if (attribs & CV_FieldAttrib_NoConstruct) {
attribs &= ~CV_FieldAttrib_NoConstruct;
str8_list_pushf(scratch.arena, &list, "NoConstruct");
}
if (attribs & CV_FieldAttrib_CompilerGenated) {
attribs &= ~CV_FieldAttrib_CompilerGenated;
str8_list_pushf(scratch.arena, &list, "CompilerGenerated");
}
if (attribs & CV_FieldAttrib_Sealed) {
attribs &= ~CV_FieldAttrib_Sealed;
str8_list_pushf(scratch.arena, &list, "Sealed");
}
if (attribs) {
str8_list_pushf(scratch.arena, &list, "Unknown: %x", attribs);
}
}
if (access) {
str8_list_pushf(scratch.arena, &list, "%S", access_str);
}
if (mprop) {
str8_list_pushf(scratch.arena, &list, "%S", mprop_str);
}
String8 result = str8_list_join(scratch.arena, &list, &(StringJoin){.sep=str8_lit(", ")});
scratch_end(scratch);
return result;
}
internal String8
cv_string_from_itype(Arena *arena, CV_TypeIndex min_itype, CV_TypeIndex itype)
{
String8 result = str8_zero();
if (itype < min_itype) {
String8 n = cv_type_name_from_basic_type((CV_BasicType)itype);
if (n.size) {
Temp scratch = scratch_begin(&arena, 1);
U64 type = CV_BasicTypeFromTypeId(itype);
char *type_str = "???";
switch (type) {
case CV_BasicType_NOTYPE: type_str = "NOTYPE"; break;
case CV_BasicType_ABS: type_str = "ABS"; break;
case CV_BasicType_SEGMENT: type_str = "SEGMENT"; break;
case CV_BasicType_VOID: type_str = "VOID"; break;
case CV_BasicType_CURRENCY: type_str = "CURRENCY"; break;
case CV_BasicType_NBASICSTR: type_str = "NBASICSTR"; break;
case CV_BasicType_FBASICSTR: type_str = "FBASICSTR"; break;
case CV_BasicType_NOTTRANS: type_str = "NOTTRANS"; break;
case CV_BasicType_HRESULT: type_str = "HRESULT"; break;
case CV_BasicType_CHAR: type_str = "CHAR"; break;
case CV_BasicType_SHORT: type_str = "SHORT"; break;
case CV_BasicType_LONG: type_str = "LONG"; break;
case CV_BasicType_QUAD: type_str = "QUAD"; break;
case CV_BasicType_OCT: type_str = "OCT"; break;
case CV_BasicType_UCHAR: type_str = "UCHAR"; break;
case CV_BasicType_USHORT: type_str = "USHORT"; break;
case CV_BasicType_ULONG: type_str = "ULONG"; break;
case CV_BasicType_UQUAD: type_str = "UQUAD"; break;
case CV_BasicType_UOCT: type_str = "UOCT"; break;
case CV_BasicType_BOOL8: type_str = "BOOL8"; break;
case CV_BasicType_BOOL16: type_str = "BOOL16"; break;
case CV_BasicType_BOOL32: type_str = "BOOL32"; break;
case CV_BasicType_BOOL64: type_str = "BOOL64"; break;
case CV_BasicType_FLOAT32: type_str = "FLOAT32"; break;
case CV_BasicType_FLOAT64: type_str = "FLOAT64"; break;
case CV_BasicType_FLOAT80: type_str = "FLOAT80"; break;
case CV_BasicType_FLOAT128: type_str = "FLOAT128"; break;
case CV_BasicType_FLOAT48: type_str = "FLOAT48"; break;
case CV_BasicType_FLOAT32PP: type_str = "FLOAT32PP"; break;
case CV_BasicType_FLOAT16: type_str = "FLOAT16"; break;
case CV_BasicType_COMPLEX32: type_str = "COMPLEX32"; break;
case CV_BasicType_COMPLEX64: type_str = "COMPLEX64"; break;
case CV_BasicType_COMPLEX80: type_str = "COMPLEX80"; break;
case CV_BasicType_COMPLEX128: type_str = "COMPLEX128"; break;
case CV_BasicType_BIT: type_str = "BIT"; break;
case CV_BasicType_PASCHAR: type_str = "PASCHAR"; break;
case CV_BasicType_BOOL32FF: type_str = "BOOL32FF"; break;
case CV_BasicType_INT8: type_str = "INT8"; break;
case CV_BasicType_UINT8: type_str = "UINT8"; break;
case CV_BasicType_RCHAR: type_str = "RCHAR"; break;
case CV_BasicType_WCHAR: type_str = "WCHAR"; break;
case CV_BasicType_INT16: type_str = "INT16"; break;
case CV_BasicType_UINT16: type_str = "UINT16"; break;
case CV_BasicType_INT32: type_str = "INT32"; break;
case CV_BasicType_UINT32: type_str = "UINT32"; break;
case CV_BasicType_INT64: type_str = "INT64"; break;
case CV_BasicType_UINT64: type_str = "UINT64"; break;
case CV_BasicType_INT128: type_str = "INT128"; break;
case CV_BasicType_UINT128: type_str = "UINT128"; break;
case CV_BasicType_CHAR16: type_str = "CHAR16"; break;
case CV_BasicType_CHAR32: type_str = "CHAR32"; break;
case CV_BasicType_CHAR8: type_str = "CHAR8"; break;
case CV_BasicType_PTR: type_str = "PTR"; break;
}
U64 ptr = CV_BasicPointerKindFromTypeId(itype);
char *ptr_str = "";
switch (ptr) {
case 0x1: ptr_str = "P"; break;
case 0x2: ptr_str = "PF"; break;
case 0x3: ptr_str = "PH"; break;
case 0x4: ptr_str = "32P"; break;
case 0x5: ptr_str = "32PF"; break;
case 0x6: ptr_str = "64P"; break;
}
n = upper_from_str8(scratch.arena, n);
result = push_str8f(arena, "T_%s%s(%x)", ptr_str, type_str, itype);
scratch_end(scratch);
} else {
result = push_str8f(arena, "%x", itype);
}
} else {
result = push_str8f(arena, "%x", itype);
}
return result;
}
internal String8
cv_string_from_itemid(Arena *arena, CV_ItemId itemid)
{
String8 result = push_str8f(arena, "%x", itemid);
return result;
}
internal String8
cv_string_from_reg_off(Arena *arena, CV_Arch arch, U32 reg, U32 off)
{
Temp scratch = scratch_begin(&arena, 1);
String8 result = push_str8f(arena, "%S+%x", cv_string_from_reg_id(scratch.arena, arch, reg), off);
scratch_end(scratch);
return result;
}
internal String8
cv_string_from_symbol_type(Arena *arena, CV_SymKind symbol_type)
{
String8 str = cv_string_from_sym_kind(symbol_type);
String8 result = push_str8f(arena, "S_%S", str);
return result;
}
internal String8
cv_string_from_symbol_kind(Arena *arena, CV_SymKind kind)
{
String8 str = cv_string_from_sym_kind(kind);
String8 result = push_str8f(arena, "S_%S", str);
return result;
}
internal String8
cv_string_from_leaf_name(Arena *arena, U32 leaf_type)
{
String8 str = cv_string_from_leaf_kind(leaf_type);
String8 result = push_str8f(arena, "LF_%S", str);
return result;
}
internal String8
cv_string_sec_off(Arena *arena, U32 sec, U32 off)
{
return push_str8f(arena, "%04x:%08x", sec, off);
}
+52
View File
@@ -0,0 +1,52 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef CODEVIEW_ENUM_H
#define CODEVIEW_ENUM_H
internal String8 cv_string_from_type_index_source(CV_TypeIndexSource ti_source);
internal String8 cv_string_from_language(CV_Language x);
internal String8 cv_string_from_numeric(Arena *arena, CV_NumericParsed num);
internal String8 cv_string_from_reg_id(Arena *arena, CV_Arch arch, U32 id);
internal String8 cv_string_from_member_access(CV_MemberAccess x);
internal String8 cv_string_from_method_prop(CV_MethodProp x);
internal String8 cv_string_from_hfa(CV_HFAKind x);
internal String8 cv_string_from_mcom(CV_MoComUDTKind x);
internal String8 cv_string_from_binary_opcode(CV_InlineBinaryAnnotation x);
internal String8 cv_string_from_thunk_ordinal(CV_ThunkOrdinal x);
internal String8 cv_string_from_frame_cookie_kind(CV_FrameCookieKind x);
internal String8 cv_string_from_generic_style(CV_GenericStyle x);
internal String8 cv_string_from_trampoline_kind(CV_TrampolineKind x);
internal String8 cv_string_from_virtual_table_shape_kind(CV_VirtualTableShape x);
internal String8 cv_string_from_call_kind(CV_CallKind x);
internal String8 cv_string_from_member_pointer_kind(CV_MemberPointerKind x);
internal String8 cv_string_from_pointer_kind(CV_PointerKind x);
internal String8 cv_string_from_pointer_mode(CV_PointerMode x);
internal String8 cv_string_from_c13_checksum_kind(CV_C13ChecksumKind x);
internal String8 cv_string_from_label_kind(Arena *arena, CV_LabelKind x);
internal String8 cv_string_from_c13_subsection_kind(CV_C13SubSectionKind x);
internal String8 cv_string_from_modifier_flags(Arena *arena, CV_ModifierFlags x);
internal String8 cv_string_from_pointer_attribs(Arena *arena, CV_PointerAttribs x);
internal String8 cv_string_from_function_attribs(Arena *arena, CV_FunctionAttribs x);
internal String8 cv_string_from_export_flags(Arena *arena, CV_ExportFlags x);
internal String8 cv_string_from_sepcode(Arena *arena, CV_SepcodeFlags x);
internal String8 cv_string_from_pub32_flags(Arena *arena, CV_Pub32Flags x);
internal String8 cv_string_from_generic_flags(Arena *arena, CV_GenericFlags x);
internal String8 cv_string_from_frame_proc_flags(Arena *arena, CV_FrameprocFlags x);
internal String8 cv_string_from_type_props(Arena *arena, CV_TypeProps32 x);
internal String8 cv_string_from_local_flags(Arena *arena, CV_LocalFlags x);
internal String8 cv_string_from_proc_flags(Arena *arena, CV_ProcFlags x);
internal String8 cv_string_from_range_attribs(Arena *arena, CV_RangeAttribs x);
internal String8 cv_string_from_defrange_register_rel_flags(Arena *arena, CV_DefrangeRegisterRelFlags x);
internal String8 cv_string_from_field_attribs(Arena *arena, CV_FieldAttribs attribs);
internal String8 cv_string_from_itype(Arena *arena, CV_TypeIndex min_itype, CV_TypeIndex itype);
internal String8 cv_string_from_itemid(Arena *arena, CV_ItemId itemid);
internal String8 cv_string_from_reg_off(Arena *arena, CV_Arch arch, U32 reg, U32 off);
internal String8 cv_string_from_symbol_type(Arena *arena, CV_SymKind symbol_type);
internal String8 cv_string_from_symbol_kind(Arena *arena, CV_SymKind kind);
internal String8 cv_string_from_leaf_name(Arena *arena, U32 leaf_type);
internal String8 cv_string_sec_off(Arena *arena, U32 sec, U32 off);
#endif // CODEVIEW_ENUM_H
File diff suppressed because it is too large Load Diff
+301
View File
@@ -0,0 +1,301 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef CODEVIEW_PARSE_H
#define CODEVIEW_PARSE_H
////////////////////////////////
//~ CodeView Common Parser Types
// CV_Numeric layout
// x: U16
// buf: U8[]
// case (x < 0x8000): kind=U16 val=x
// case (x >= 0x8000): kind=x val=buf
typedef struct CV_NumericParsed CV_NumericParsed;
struct CV_NumericParsed
{
CV_NumericKind kind;
U8 *val;
U64 encoded_size;
};
typedef struct CV_RecRange CV_RecRange;
struct CV_RecRange
{
U32 off;
CV_RecHeader hdr;
};
#define CV_REC_RANGE_CHUNK_SIZE 511
typedef struct CV_RecRangeChunk CV_RecRangeChunk;
struct CV_RecRangeChunk
{
struct CV_RecRangeChunk *next;
CV_RecRange ranges[CV_REC_RANGE_CHUNK_SIZE];
};
typedef struct CV_RecRangeStream CV_RecRangeStream;
struct CV_RecRangeStream
{
CV_RecRangeChunk *first_chunk;
CV_RecRangeChunk *last_chunk;
U64 total_count;
};
typedef struct CV_RecRangeArray CV_RecRangeArray;
struct CV_RecRangeArray
{
CV_RecRange *ranges;
U64 count;
};
////////////////////////////////
//~ CodeView Sym Parser Types
typedef struct CV_SymTopLevelInfo CV_SymTopLevelInfo;
struct CV_SymTopLevelInfo
{
CV_Arch arch;
CV_Language language;
String8 compiler_name;
};
typedef struct CV_SymParsed CV_SymParsed;
struct CV_SymParsed
{
// source information
String8 data;
U64 sym_align;
// sym index derived from source
CV_RecRangeArray sym_ranges;
// top-level info derived from the syms
CV_SymTopLevelInfo info;
};
////////////////////////////////
//~ CodeView Leaf Parser Types
typedef struct CV_LeafParsed CV_LeafParsed;
struct CV_LeafParsed
{
// source information
String8 data;
CV_TypeId itype_first;
CV_TypeId itype_opl;
// leaf index derived from source
CV_RecRangeArray leaf_ranges;
};
////////////////////////////////
//~ CodeView C13 Info Parser Types
typedef struct CV_C13InlineSiteDecoder CV_C13InlineSiteDecoder;
struct CV_C13InlineSiteDecoder
{
U64 cursor;
U64 parent_voff;
CV_InlineRangeKind range_kind;
U32 code_length;
U32 code_offset;
U32 file_off;
S32 ln;
S32 cn;
U64 code_offset_lo;
B32 code_offset_changed;
B32 code_offset_lo_changed;
B32 code_length_changed;
B32 ln_changed;
B32 file_off_changed;
Rng1U64 last_range;
U32 file_count;
Rng1U64 file_last_range;
U64 file_line_count;
U64 file_last_ln;
};
typedef U32 CV_C13InlineSiteDecoderStepFlags;
enum
{
CV_C13InlineSiteDecoderStepFlag_EmitRange = (1 << 0),
CV_C13InlineSiteDecoderStepFlag_ExtendLastRange = (1 << 1),
CV_C13InlineSiteDecoderStepFlag_EmitFile = (1 << 2),
CV_C13InlineSiteDecoderStepFlag_EmitLine = (1 << 3),
};
typedef struct CV_C13InlineSiteDecoderStep CV_C13InlineSiteDecoderStep;
struct CV_C13InlineSiteDecoderStep
{
CV_C13InlineSiteDecoderStepFlags flags;
Rng1U64 range;
U64 line_voff;
U64 line_voff_end;
U64 ln;
U64 cn;
U32 file_off;
};
typedef struct CV_C13LinesParsed CV_C13LinesParsed;
struct CV_C13LinesParsed
{
// raw info
U32 sec_idx;
U32 file_off;
U64 secrel_base_off;
// parsed info
String8 file_name;
U64 *voffs; // [line_count + 1]
U32 *line_nums; // [line_count]
U16 *col_nums; // [2*line_count]
U32 line_count;
};
typedef struct CV_C13LinesParsedNode CV_C13LinesParsedNode;
struct CV_C13LinesParsedNode
{
CV_C13LinesParsedNode *next;
CV_C13LinesParsed v;
};
typedef struct CV_C13InlineeLinesParsed CV_C13InlineeLinesParsed;
struct CV_C13InlineeLinesParsed
{
CV_ItemId inlinee;
U32 file_off;
String8 file_name;
U32 first_source_ln;
U32 extra_file_count;
U32 *extra_files;
};
typedef struct CV_C13InlineeLinesParsedNode CV_C13InlineeLinesParsedNode;
struct CV_C13InlineeLinesParsedNode
{
CV_C13InlineeLinesParsedNode *next;
CV_C13InlineeLinesParsedNode *hash_next;
CV_C13InlineeLinesParsed v;
};
typedef struct CV_C13SubSectionNode CV_C13SubSectionNode;
struct CV_C13SubSectionNode
{
struct CV_C13SubSectionNode *next;
CV_C13SubSectionKind kind;
U32 off;
U32 size;
CV_C13LinesParsedNode *lines_first;
CV_C13LinesParsedNode *lines_last;
CV_C13InlineeLinesParsedNode *inlinee_lines_first;
CV_C13InlineeLinesParsedNode *inlinee_lines_last;
};
typedef struct CV_C13Parsed CV_C13Parsed;
struct CV_C13Parsed
{
// rjf: source data
String8 data;
// rjf: full sub-section list
CV_C13SubSectionNode *first_sub_section;
CV_C13SubSectionNode *last_sub_section;
U64 sub_section_count;
// rjf: fastpath to file checksums section
CV_C13SubSectionNode *file_chksms_sub_section;
// rjf: fastpath to map inlinee CV_ItemId -> CV_InlineeLinesParsed quickly
CV_C13InlineeLinesParsedNode **inlinee_lines_parsed_slots;
U64 inlinee_lines_parsed_slots_count;
};
typedef struct CV_UDTInfo CV_UDTInfo;
struct CV_UDTInfo
{
String8 name;
String8 unique_name;
CV_TypeProps props;
};
////////////////////////////////
//~ CodeView Compound Types
typedef struct CV_TypeIdArray CV_TypeIdArray;
struct CV_TypeIdArray
{
CV_TypeId *itypes;
U64 count;
};
////////////////////////////////
//- Hasher
internal U64 cv_hash_from_string(String8 string);
internal U64 cv_hash_from_item_id(CV_ItemId item_id);
//- Numeric Decoder
internal CV_NumericParsed cv_numeric_from_data_range(U8 *first, U8 *opl);
internal U64 cv_read_numeric(String8 data, U64 offset, CV_NumericParsed *out);
internal B32 cv_numeric_fits_in_u64(CV_NumericParsed *num);
internal B32 cv_numeric_fits_in_s64(CV_NumericParsed *num);
internal B32 cv_numeric_fits_in_f64(CV_NumericParsed *num);
internal U64 cv_u64_from_numeric(CV_NumericParsed *num);
internal S64 cv_s64_from_numeric(CV_NumericParsed *num);
internal F64 cv_f64_from_numeric(CV_NumericParsed *num);
//- Inlinee Lines Binary Annot Decoder
internal U64 cv_decode_inline_annot_u32(String8 data, U64 offset, U32 *out_value);
internal U64 cv_decode_inline_annot_s32(String8 data, U64 offset, S32 *out_value);
internal S32 cv_inline_annot_signed_from_unsigned_operand(U32 value);
internal CV_C13InlineSiteDecoder cv_c13_inline_site_decoder_init(U32 file_off, U32 first_source_ln, U32 parent_voff);
internal CV_C13InlineSiteDecoderStep cv_c13_inline_site_decoder_step(CV_C13InlineSiteDecoder *decoder, String8 binary_annots);
//- Symbol/Leaf Helpers
internal B32 cv_is_udt_name_anon(String8 name);
internal B32 cv_is_global_symbol(CV_SymKind kind);
internal B32 cv_is_typedef(CV_SymKind kind);
internal B32 cv_is_scope_symbol(CV_SymKind kind);
internal B32 cv_is_end_symbol(CV_SymKind kind);
internal B32 cv_is_udt(CV_LeafKind kind);
internal B32 cv_is_leaf_type_server(CV_LeafKind kind);
internal B32 cv_is_leaf_pch(CV_LeafKind kind);
internal CV_TypeIndexSource cv_type_index_source_from_leaf_kind(CV_LeafKind leaf_kind);
internal CV_TypeIndexInfoList cv_get_symbol_type_index_offsets(Arena *arena, CV_SymKind kind, String8 data);
internal CV_TypeIndexInfoList cv_get_leaf_type_index_offsets(Arena *arena, CV_LeafKind leaf_kind, String8 data);
internal CV_TypeIndexInfoList cv_get_inlinee_type_index_offsets(Arena *arena, String8 raw_data);
internal String8Array cv_get_data_around_type_indices(Arena *arena, CV_TypeIndexInfoList ti_list, String8 data);
internal U64 cv_name_offset_from_symbol(CV_SymKind kind, String8 data);
internal String8 cv_name_from_symbol(CV_SymKind kind, String8 data);
internal CV_UDTInfo cv_get_udt_info(CV_LeafKind kind, String8 data);
internal String8 cv_name_from_udt_info(CV_UDTInfo udt_info);
//- rjf: record range stream parsing
internal CV_RecRangeStream * cv_rec_range_stream_from_data(Arena *arena, String8 data, U64 align);
internal CV_RecRangeArray cv_rec_range_array_from_stream(Arena *arena, CV_RecRangeStream *stream);
//- rjf: sym stream parsing
internal CV_SymParsed * cv_sym_from_data(Arena *arena, String8 sym_data, U64 sym_align);
//- rjf: leaf stream parsing
internal CV_LeafParsed * cv_leaf_from_data(Arena *arena, String8 leaf_data, CV_TypeId first);
internal CV_C13Parsed * cv_c13_parsed_from_data(Arena *arena, String8 c13_data, String8 strtbl, COFF_SectionHeaderArray sections);
#endif // CODEVIEW_PARSE_H
File diff suppressed because it is too large Load Diff
-84
View File
@@ -1,84 +0,0 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef CODEVIEW_STRINGIZE_H
#define CODEVIEW_STRINGIZE_H
////////////////////////////////
//~ CodeView Stringize Helper Types
typedef struct CV_StringizeSymParams{
CV_Arch arch;
} CV_StringizeSymParams;
typedef struct CV_StringizeLeafParams{
U32 dummy;
} CV_StringizeLeafParams;
////////////////////////////////
//~ CodeView Common Stringize Functions
internal void cv_stringize_numeric(Arena *arena, String8List *out, CV_NumericParsed *num);
internal void cv_stringize_lvar_addr_range(Arena *arena, String8List *out,
CV_LvarAddrRange *range);
internal void cv_stringize_lvar_addr_gap(Arena *arena, String8List *out, CV_LvarAddrGap *gap);
internal void cv_stringize_lvar_addr_gap_list(Arena *arena, String8List *out,
void *first, void *opl);
internal String8 cv_string_from_basic_type(CV_BasicType basic_type);
internal String8 cv_string_from_c13_sub_section_kind(CV_C13SubSectionKind kind);
internal String8 cv_string_from_reg(CV_Arch arch, CV_Reg reg);
internal String8 cv_string_from_pointer_kind(CV_PointerKind ptr_kind);
internal String8 cv_string_from_pointer_mode(CV_PointerMode ptr_mode);
internal String8 cv_string_from_hfa_kind(CV_HFAKind hfa_kind);
internal String8 cv_string_from_mo_com_udt_kind(CV_MoComUDTKind mo_com_udt_kind);
////////////////////////////////
//~ CodeView Flags Stringize Functions
internal void cv_stringize_modifier_flags(Arena *arena, String8List *out,
U32 indent, CV_ModifierFlags flags);
internal void cv_stringize_type_props(Arena *arena, String8List *out,
U32 indent, CV_TypeProps props);
internal void cv_stringize_pointer_attribs(Arena *arena, String8List *out,
U32 indent, CV_PointerAttribs attribs);
internal void cv_stringize_local_flags(Arena *arena, String8List *out,
U32 indent, CV_LocalFlags flags);
////////////////////////////////
//~ CodeView Sym Stringize Functions
internal void cv_stringize_sym_parsed(Arena *arena, String8List *out, CV_SymParsed *sym);
internal void cv_stringize_sym_range(Arena *arena, String8List *out,
CV_RecRange *range, String8 data,
CV_StringizeSymParams *p);
internal void cv_stringize_sym_array(Arena *arena, String8List *out,
CV_RecRangeArray *ranges, String8 data,
CV_StringizeSymParams *p);
////////////////////////////////
//~ CodeView Leaf Stringize Functions
internal void cv_stringize_leaf_parsed(Arena *arena, String8List *out, CV_LeafParsed *leaf);
internal void cv_stringize_leaf_range(Arena *arena, String8List *out,
CV_RecRange *range, CV_TypeId itype, String8 data,
CV_StringizeLeafParams *p);
internal void cv_stringize_leaf_array(Arena *arena, String8List *out,
CV_RecRangeArray *ranges, CV_TypeId itype_first,
String8 data,
CV_StringizeLeafParams *p);
////////////////////////////////
//~ CodeView C13 Stringize Functions
internal void cv_stringize_c13_parsed(Arena *arena, String8List *out, CV_C13Parsed *c13);
internal String8 cv_string_from_inline_range_kind(CV_InlineRangeKind kind);
#endif // CODEVIEW_STRINGIZE_H
+220 -1631
View File
File diff suppressed because it is too large Load Diff
+401 -727
View File
File diff suppressed because it is too large Load Diff
+451
View File
@@ -0,0 +1,451 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
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_Machine_Unknown },
{ str8_lit_comp("X86"), COFF_Machine_X86 },
{ str8_lit_comp("Amd64"), COFF_Machine_X64 },
{ str8_lit_comp("X64"), COFF_Machine_X64 },
{ str8_lit_comp("Am33"), COFF_Machine_Am33 },
{ str8_lit_comp("Arm"), COFF_Machine_Arm },
{ str8_lit_comp("Arm64"), COFF_Machine_Arm64 },
{ str8_lit_comp("ArmNt"), COFF_Machine_ArmNt },
{ str8_lit_comp("Ebc"), COFF_Machine_Ebc },
{ str8_lit_comp("Ia64"), COFF_Machine_Ia64 },
{ str8_lit_comp("M32r"), COFF_Machine_M32R },
{ str8_lit_comp("Mips16"), COFF_Machine_Mips16 },
{ str8_lit_comp("MipsFpu"), COFF_Machine_MipsFpu },
{ str8_lit_comp("MipsFpu16"), COFF_Machine_MipsFpu16 },
{ str8_lit_comp("PowerPc"), COFF_Machine_PowerPc },
{ str8_lit_comp("PowerPcFp"), COFF_Machine_PowerPcFp },
{ str8_lit_comp("R4000"), COFF_Machine_R4000 },
{ str8_lit_comp("RiscV32"), COFF_Machine_RiscV32 },
{ str8_lit_comp("RiscV64"), COFF_Machine_RiscV64 },
{ str8_lit_comp("Sh3"), COFF_Machine_Sh3 },
{ str8_lit_comp("Sh3Dsp"), COFF_Machine_Sh3Dsp },
{ str8_lit_comp("Sh4"), COFF_Machine_Sh4 },
{ str8_lit_comp("Sh5"), COFF_Machine_Sh5 },
{ str8_lit_comp("Thumb"), COFF_Machine_Thumb },
{ str8_lit_comp("WceMipsV2"), COFF_Machine_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_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_Machine_X86: return coff_string_from_reloc_x86(x);
case COFF_Machine_X64: return coff_string_from_reloc_x64(x);
case COFF_Machine_Arm: return coff_string_from_reloc_arm(x);
case COFF_Machine_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_Machine_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;
}
+26
View File
@@ -0,0 +1,26 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef COFF_ENUM_H
#define COFF_ENUM_H
internal String8 coff_string_from_time_stamp(Arena *arena, COFF_TimeStamp time_stamp);
internal String8 coff_string_from_comdat_select_type(COFF_ComdatSelectType type);
internal String8 coff_string_from_machine_type(COFF_MachineType machine);
internal String8 coff_string_from_flags(Arena *arena, COFF_FileHeaderFlags flags);
internal String8 coff_string_from_section_flags(Arena *arena, COFF_SectionFlags flags);
internal String8 coff_string_from_import_header_type(COFF_ImportType type);
internal String8 coff_string_from_sym_dtype(COFF_SymDType x);
internal String8 coff_string_from_sym_type(COFF_SymType x);
internal String8 coff_string_from_sym_storage_class(COFF_SymStorageClass x);
internal String8 coff_string_from_weak_ext_type(COFF_WeakExtType x);
internal String8 coff_string_from_reloc_x86(COFF_Reloc_X86 x);
internal String8 coff_string_from_reloc_x64(COFF_Reloc_X64 x);
internal String8 coff_string_from_reloc_arm(COFF_Reloc_Arm x);
internal String8 coff_string_from_reloc_arm64(COFF_Reloc_Arm64 x);
internal String8 coff_string_from_reloc(COFF_MachineType machine, COFF_RelocType x);
internal COFF_MachineType coff_machine_from_string(String8 string);
internal COFF_ImportType coff_import_header_type_from_string(String8 name);
#endif // COFF_ENUM_H
+904
View File
@@ -0,0 +1,904 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
internal B32
coff_is_big_obj(String8 raw_coff)
{
B32 is_big_obj = 0;
if (raw_coff.size >= sizeof(COFF_BigObjHeader)) {
COFF_BigObjHeader *file_header32 = (COFF_BigObjHeader*)(raw_coff.str);
is_big_obj = file_header32->sig1 == COFF_Machine_Unknown &&
file_header32->sig2 == max_U16 &&
file_header32->version >= 2 &&
MemoryCompare(file_header32->magic, g_coff_big_header_magic, sizeof(file_header32->magic)) == 0;
}
return is_big_obj;
}
internal B32
coff_is_obj(String8 raw_coff)
{
B32 is_obj = 0;
if (raw_coff.size >= sizeof(COFF_FileHeader)) {
COFF_FileHeader *header = (COFF_FileHeader*)(raw_coff.str);
// validate machine
B32 is_machine_type_valid = 0;
switch (header->machine) {
case COFF_Machine_Unknown:
case COFF_Machine_X86: case COFF_Machine_X64:
case COFF_Machine_Am33: case COFF_Machine_Arm:
case COFF_Machine_Arm64: case COFF_Machine_ArmNt:
case COFF_Machine_Ebc: case COFF_Machine_Ia64:
case COFF_Machine_M32R: case COFF_Machine_Mips16:
case COFF_Machine_MipsFpu:case COFF_Machine_MipsFpu16:
case COFF_Machine_PowerPc:case COFF_Machine_PowerPcFp:
case COFF_Machine_R4000: case COFF_Machine_RiscV32:
case COFF_Machine_RiscV64:case COFF_Machine_RiscV128:
case COFF_Machine_Sh3: case COFF_Machine_Sh3Dsp:
case COFF_Machine_Sh4: case COFF_Machine_Sh5:
case COFF_Machine_Thumb: case COFF_Machine_WceMipsV2:
{
is_machine_type_valid = 1;
}break;
}
if (is_machine_type_valid) {
// validate section count
U64 section_count = header->section_count;
U64 section_hdr_opl_off = sizeof(*header) + section_count*sizeof(COFF_SectionHeader);
if (raw_coff.size >= section_hdr_opl_off) {
COFF_SectionHeader *section_hdrs = (COFF_SectionHeader*)(raw_coff.str + sizeof(*header));
COFF_SectionHeader *section_hdr_opl = section_hdrs + section_count;
// validate section ranges
B32 is_sect_range_valid = 1;
for (COFF_SectionHeader *sec_hdr = section_hdrs;
sec_hdr < section_hdr_opl;
sec_hdr += 1) {
if (!(sec_hdr->flags & COFF_SectionFlag_CntUninitializedData)) {
U64 min = sec_hdr->foff;
U64 max = min + sec_hdr->fsize;
if (sec_hdr->fsize > 0 && !(section_hdr_opl_off <= min && min <= max && max <= raw_coff.size)) {
is_sect_range_valid = 0;
break;
}
}
}
if (is_sect_range_valid) {
// validate symbol table
U64 symbol_table_off = header->symbol_table_foff;
U64 symbol_table_size = sizeof(COFF_Symbol16)*header->symbol_count;
U64 symbol_table_opl_off = symbol_table_off + symbol_table_size;
// don't validate symbol table when there is none
if (symbol_table_off == 0 && symbol_table_size == 0) {
symbol_table_off = section_hdr_opl_off;
symbol_table_opl_off = section_hdr_opl_off;
}
is_obj = (section_hdr_opl_off <= symbol_table_off &&
symbol_table_off <= symbol_table_opl_off &&
symbol_table_opl_off <= raw_coff.size);
}
}
}
}
return is_obj;
}
internal COFF_FileHeaderInfo
coff_file_header_info_from_data(String8 raw_coff)
{
COFF_FileHeaderInfo info = {0};
if (coff_is_big_obj(raw_coff)) {
COFF_BigObjHeader *header32 = (COFF_BigObjHeader*)raw_coff.str;
info.is_big_obj = 1;
info.machine = header32->machine;
info.header_size = sizeof(COFF_BigObjHeader);
info.section_array_off = sizeof(COFF_BigObjHeader);
info.section_count_no_null = header32->section_count;
info.string_table_off = header32->symbol_table_foff + sizeof(COFF_Symbol32) * header32->symbol_count;
info.symbol_size = sizeof(COFF_Symbol32);
info.symbol_off = header32->symbol_table_foff;
info.symbol_count = header32->symbol_count;
} else if (coff_is_obj(raw_coff)) {
COFF_FileHeader *header16 = (COFF_FileHeader*)raw_coff.str;
info.is_big_obj = 0;
info.machine = header16->machine;
info.header_size = sizeof(COFF_FileHeader);
info.section_array_off = sizeof(COFF_FileHeader);
info.section_count_no_null = header16->section_count;
info.string_table_off = header16->symbol_table_foff + sizeof(COFF_Symbol16) * header16->symbol_count;
info.symbol_size = sizeof(COFF_Symbol16);
info.symbol_off = header16->symbol_table_foff;
info.symbol_count = header16->symbol_count;
}
return info;
}
internal COFF_ParsedSymbol
coff_parse_symbol32(String8 raw_coff, U64 string_table_off, COFF_Symbol32 *sym32)
{
COFF_ParsedSymbol result = {0};
result.name = coff_read_symbol_name(raw_coff, string_table_off, &sym32->name);
result.value = sym32->value;
result.section_number = sym32->section_number;
result.type = sym32->type;
result.storage_class = sym32->storage_class;
result.aux_symbol_count = sym32->aux_symbol_count;
return result;
}
internal COFF_ParsedSymbol
coff_parse_symbol16(String8 raw_coff, U64 string_table_off, COFF_Symbol16 *sym16)
{
COFF_ParsedSymbol result = {0};
result.name = coff_read_symbol_name(raw_coff, string_table_off, &sym16->name);
result.value = sym16->value;
if (sym16->section_number == COFF_Symbol_DebugSection16) {
result.section_number = COFF_Symbol_DebugSection32;
} else if (sym16->section_number == COFF_Symbol_AbsSection16) {
result.section_number = COFF_Symbol_AbsSection32;
} else {
result.section_number = (U32)sym16->section_number;
}
result.type = sym16->type;
result.storage_class = sym16->storage_class;
result.aux_symbol_count = sym16->aux_symbol_count;
return result;
}
internal COFF_Symbol32Array
coff_symbol_array_from_data_16(Arena *arena, String8 raw_coff, U64 symbol_array_off, U64 symbol_count)
{
COFF_Symbol32Array result = {0};
result.count = symbol_count;
result.v = push_array_no_zero_aligned(arena, COFF_Symbol32, result.count, 8);
Rng1U64 sym16_arr_range = rng_1u64(symbol_array_off, symbol_array_off + sizeof(COFF_Symbol16) * symbol_count);
String8 raw_sym16_arr = str8_substr(raw_coff, sym16_arr_range);
COFF_Symbol16 *sym16_arr = (COFF_Symbol16 *)raw_sym16_arr.str;
for (U64 isymbol = 0, count = raw_sym16_arr.size / sizeof(COFF_Symbol16); isymbol < count; isymbol += 1) {
COFF_Symbol16 *sym16 = &sym16_arr[isymbol];
COFF_Symbol32 *sym32 = &result.v[isymbol];
sym32->name = sym16->name;
sym32->value = sym16->value;
if (sym16->section_number == COFF_Symbol_DebugSection16) {
sym32->section_number = COFF_Symbol_DebugSection32;
} else if (sym16->section_number == COFF_Symbol_AbsSection16) {
sym32->section_number = COFF_Symbol_AbsSection32;
} else {
sym32->section_number = (U32)sym16->section_number;
}
sym32->type.v = sym16->type.v;
sym32->storage_class = sym16->storage_class;
sym32->aux_symbol_count = sym16->aux_symbol_count;
// copy aux symbols
for (U64 iaux = isymbol+1, iaux_hi = Min(count, iaux+sym16->aux_symbol_count); iaux < iaux_hi; iaux += 1) {
COFF_Symbol16 *aux16 = sym16_arr + iaux;
COFF_Symbol32 *aux32 = result.v + iaux;
// 32bit COFF uses 16bit aux symbols
MemoryCopy(aux32, aux16, sizeof(COFF_Symbol16));
MemoryZero((U8 *)aux32 + sizeof(COFF_Symbol16), sizeof(COFF_Symbol32)-sizeof(COFF_Symbol16));
}
// take into account aux symbols
isymbol += sym32->aux_symbol_count;
}
return result;
}
internal COFF_Symbol32Array
coff_symbol_array_from_data_32(Arena *arena, String8 data, U64 symbol_array_off, U64 symbol_count)
{
COFF_Symbol32Array result;
result.count = symbol_count;
result.v = (COFF_Symbol32 *)(data.str + symbol_array_off);
return result;
}
internal COFF_Symbol32Array
coff_symbol_array_from_data(Arena *arena, String8 data, U64 symbol_array_off, U64 symbol_count, U64 symbol_size)
{
COFF_Symbol32Array result = {0};
switch (symbol_size) {
case sizeof(COFF_Symbol16): result = coff_symbol_array_from_data_16(arena, data, symbol_array_off, symbol_count); break;
case sizeof(COFF_Symbol32): result = coff_symbol_array_from_data_32(arena, data, symbol_array_off, symbol_count); break;
}
return result;
}
internal COFF_Symbol16Node *
coff_symbol16_list_push(Arena *arena, COFF_Symbol16List *list, COFF_Symbol16 symbol)
{
COFF_Symbol16Node *node = push_array(arena, COFF_Symbol16Node, 1);
node->next = 0;
node->data = symbol;
SLLQueuePush(list->first, list->last, node);
list->count += 1;
return node;
}
internal COFF_SymbolValueInterpType
coff_interp_symbol(U32 section_number, U32 value, COFF_SymStorageClass storage_class)
{
if (storage_class == COFF_SymStorageClass_Section && section_number == COFF_Symbol_UndefinedSection) {
return COFF_SymbolValueInterp_Undefined;
}
if (storage_class == COFF_SymStorageClass_External && value == 0 && section_number == COFF_Symbol_UndefinedSection) {
return COFF_SymbolValueInterp_Undefined;
}
if (storage_class == COFF_SymStorageClass_External && value != 0 && section_number == COFF_Symbol_UndefinedSection) {
return COFF_SymbolValueInterp_Common;
}
if (section_number == COFF_Symbol_AbsSection32) {
return COFF_SymbolValueInterp_Abs;
}
if (section_number == COFF_Symbol_DebugSection32) {
return COFF_SymbolValueInterp_Debug;
}
if (storage_class == COFF_SymStorageClass_WeakExternal) {
return COFF_SymbolValueInterp_Weak;
}
return COFF_SymbolValueInterp_Regular;
}
internal COFF_RelocNode *
coff_reloc_list_push(Arena *arena, COFF_RelocList *list, COFF_Reloc reloc)
{
COFF_RelocNode *node = push_array(arena, COFF_RelocNode, 1);
node->data = reloc;
SLLQueuePush(list->first, list->last, node);
++list->count;
return node;
}
internal COFF_RelocInfo
coff_reloc_info_from_section_header(String8 data, COFF_SectionHeader *header)
{
COFF_RelocInfo result = {0};
if (header->flags & COFF_SectionFlag_LnkNRelocOvfl && header->reloc_count == max_U16) {
COFF_Reloc counter;
U64 read_size = str8_deserial_read_struct(data, header->relocs_foff, &counter);
if (read_size == sizeof(counter) && counter.apply_off > 0) {
result.array_off = header->relocs_foff + sizeof(COFF_Reloc);
result.count = counter.apply_off - 1; // exclude counter entry
}
} else {
result.array_off = header->relocs_foff;
result.count = header->reloc_count;
}
return result;
}
internal String8
coff_resource_string_from_str16(Arena *arena, String16 string)
{
AssertAlways(string.size <= max_U16);
U16 size16 = (U16)string.size;
U16 *buffer = push_array_no_zero(arena, U16, size16 + 1);
MemoryCopy(buffer + 0, &size16, sizeof(size16));
MemoryCopy(buffer + 1, string.str, size16 * sizeof(string.str[0]));
return str8_array(buffer, size16 + 1);
}
internal String8
coff_resource_string_from_str8(Arena *arena, String8 string)
{
Temp scratch = scratch_begin(&arena, 1);
String16 string16 = str16_from_8(scratch.arena, string);
String8 result = coff_resource_string_from_str16(arena, string16);
scratch_end(scratch);
return result;
}
internal String8
coff_resource_number_from_u16(Arena *arena, U16 number)
{
U16 *buffer = push_array_no_zero(arena, U16, 2);
buffer[0] = max_U16;
buffer[1] = number;
return str8_array(buffer, 2);
}
internal COFF_ResourceID
coff_utf8_resource_id_from_utf16(Arena *arena, COFF_ResourceID16 *id_16)
{
COFF_ResourceID id = {0};
id.type = id_16->type;
switch (id_16->type) {
case COFF_ResourceIDType_Null: break;
case COFF_ResourceIDType_Number: {
id.u.number = id_16->u.number;
} break;
case COFF_ResourceIDType_String: {
id.u.string = str8_from_16(arena, id_16->u.string);
} break;
default: InvalidPath;
}
return id;
}
internal U64
coff_read_resource_id_utf16(String8 raw_res, U64 off, COFF_ResourceID16 *id_out)
{
U64 cursor = off;
U16 flag = 0;
str8_deserial_read_struct(raw_res, cursor, &flag);
if (flag == max_U16) {
id_out->type = COFF_ResourceIDType_Number;
cursor += sizeof(flag);
cursor += str8_deserial_read_struct(raw_res, cursor, &id_out->u.number);
} else {
id_out->type = COFF_ResourceIDType_String;
cursor += str8_deserial_read_windows_utf16_string16(raw_res, cursor, &id_out->u.string);
}
U64 read_size = cursor - off;
read_size = AlignPow2(read_size, COFF_ResourceAlign);
return read_size;
}
internal U64
coff_read_resource(Arena *arena, String8 raw_res, U64 off, COFF_ParsedResource *res_out)
{
String8 raw_header = str8_skip(raw_res, off);
U64 header_cursor = 0;
// prefix
COFF_ResourceHeaderPrefix prefix = {0};
header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &prefix);
Assert(prefix.header_size >= sizeof(COFF_ResourceHeaderPrefix));
raw_header = str8_prefix(raw_header, prefix.header_size);
// header
COFF_ResourceID16 type_16 = {0};
COFF_ResourceID16 name_16 = {0};
header_cursor += coff_read_resource_id_utf16(raw_header, header_cursor, &type_16);
header_cursor += coff_read_resource_id_utf16(raw_header, header_cursor, &name_16);
header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &res_out->data_version);
header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &res_out->memory_flags);
header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &res_out->language_id);
header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &res_out->version);
header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &res_out->characteristics);
Assert(prefix.header_size == header_cursor);
// convert utf-16 resource ids to utf-8
res_out->type = coff_utf8_resource_id_from_utf16(arena, &type_16);
res_out->name = coff_utf8_resource_id_from_utf16(arena, &name_16);
// read data
U64 data_read_size = str8_deserial_read_block(raw_res, off + prefix.header_size, prefix.data_size, &res_out->data);
Assert(prefix.data_size == data_read_size);
// compute read size
U64 read_size = Max(prefix.header_size, sizeof(prefix)) + AlignPow2(prefix.data_size, COFF_ResourceAlign);
return read_size;
}
internal COFF_ParsedResourceList
coff_resource_list_from_data(Arena *arena, String8 data)
{
COFF_ParsedResourceList list = {0};
U64 cursor;
for (cursor = 0 ; cursor < data.size; ) {
COFF_ParsedResourceNode *node = push_array(arena, COFF_ParsedResourceNode, 1);
cursor += coff_read_resource(arena, data, cursor, &node->data);
SLLQueuePush(list.first, list.last, node);
++list.count;
}
Assert(cursor == data.size);
return list;
}
internal String8
coff_write_resource_id(Arena *arena, COFF_ResourceID id)
{
String8 result = str8_zero();
switch (id.type) {
case COFF_ResourceIDType_Null: break;
case COFF_ResourceIDType_Number: {
result = coff_resource_number_from_u16(arena, id.u.number);
} break;
case COFF_ResourceIDType_String: {
result = coff_resource_string_from_str8(arena, id.u.string);
} break;
default: InvalidPath;
}
return result;
}
internal String8
coff_write_resource(Arena *arena,
COFF_ResourceID type,
COFF_ResourceID name,
U32 data_version,
COFF_ResourceMemoryFlags memory_flags,
U16 language_id,
U32 version,
U32 characteristics,
String8 data)
{
Temp scratch = scratch_begin(&arena, 1);
String8List list = {0};
COFF_ResourceHeaderPrefix *prefix = push_array(scratch.arena, COFF_ResourceHeaderPrefix, 1);
String8 packed_type = coff_write_resource_id(scratch.arena, type);
String8 packed_name = coff_write_resource_id(scratch.arena, name);
// prefix + header
str8_list_push(scratch.arena, &list, str8_struct(prefix));
str8_list_push(scratch.arena, &list, packed_type);
str8_list_push(scratch.arena, &list, packed_name);
str8_list_push(scratch.arena, &list, str8_struct(&data_version));
str8_list_push(scratch.arena, &list, str8_struct(&memory_flags));
str8_list_push(scratch.arena, &list, str8_struct(&language_id));
str8_list_push(scratch.arena, &list, str8_struct(&version));
str8_list_push(scratch.arena, &list, str8_struct(&characteristics));
prefix->data_size = safe_cast_u32(data.size);
prefix->header_size = safe_cast_u32(list.total_size);
// data
str8_list_push(scratch.arena, &list, data);
// magic
str8_list_push_front(scratch.arena, &list, str8_array_fixed(g_coff_res_magic));
// align
U64 align_size = AlignPow2(list.total_size, COFF_ResourceAlign) - list.total_size;
U8 *align = push_array(scratch.arena, U8, align_size);
str8_list_push(scratch.arena, &list, str8(align, align_size));
// join
String8 res = str8_list_join(arena, &list, 0);
scratch_end(scratch);
return res;
}
internal int
coff_resource_id_compar(void *raw_a, void *raw_b)
{
int cmp;
COFF_ResourceID *a = raw_b;
COFF_ResourceID *b = raw_b;
if (a->type == b->type) {
switch (a->type) {
case COFF_ResourceIDType_Null: cmp = 0; break;
case COFF_ResourceIDType_Number: cmp = a->u.number < b->u.number ? -1 : a->u.number > b->u.number ? +1 : 0; break;
case COFF_ResourceIDType_String: cmp = strncmp((char *)a->u.string.str, (char *)b->u.string.str, Min(a->u.string.size, b->u.string.size)); break;
default: InvalidPath; break;
}
} else {
cmp = a->type < b->type ? -1 : a->type > b->type ? +1 : 0;
}
return cmp;
}
internal B32
coff_is_import(String8 raw_archive_member)
{
B32 is_import = 0;
if (raw_archive_member.size >= sizeof(U16)*2) {
U16 *sig1 = (U16*)raw_archive_member.str;
U16 *sig2 = sig1 + 1;
is_import = *sig1 == COFF_Machine_Unknown && *sig2 == 0xffff;
}
return is_import;
}
internal COFF_DataType
coff_data_type_from_data(String8 raw_archive_member)
{
B32 is_big_obj = coff_is_big_obj(raw_archive_member);
if (is_big_obj) {
return COFF_DataType_BigObj;
}
B32 is_import = coff_is_import(raw_archive_member);
if (is_import) {
return COFF_DataType_Import;
}
return COFF_DataType_Obj;
}
internal B32
coff_is_regular_archive(String8 raw_archive)
{
B32 is_archive = 0;
U8 sig[sizeof(g_coff_archive_sig)];
if (str8_deserial_read_struct(raw_archive, 0, &sig) == sizeof(sig)) {
is_archive = MemoryCompare(&sig[0], &g_coff_archive_sig[0], sizeof(g_coff_archive_sig)) == 0;
}
return is_archive;
}
internal B32
coff_is_thin_archive(String8 raw_archive)
{
B32 is_archive = 0;
U8 sig[sizeof(g_coff_thin_archive_sig)];
if (str8_deserial_read_struct(raw_archive, 0, &sig) == sizeof(sig)) {
is_archive = MemoryCompare(&sig[0], &g_coff_thin_archive_sig[0], sizeof(g_coff_thin_archive_sig)) == 0;
}
return is_archive;
}
internal COFF_ArchiveType
coff_archive_type_from_data(String8 raw_archive)
{
if (coff_is_regular_archive(raw_archive)) {
return COFF_Archive_Regular;
} else if (coff_is_thin_archive(raw_archive)) {
return COFF_Archive_Thin;
}
return COFF_Archive_Null;
}
internal U64
coff_parse_archive_member_header(String8 raw_archive, U64 offset, COFF_ParsedArchiveMemberHeader *header_out)
{
COFF_ArchiveMemberHeader *header = str8_deserial_get_raw_ptr(raw_archive, offset, sizeof(*header));
if (header) {
String8 name = str8_skip_chop_whitespace(str8_cstring_capped(header->name, header->name + sizeof(header->name) ));
String8 date = str8_skip_chop_whitespace(str8_cstring_capped(header->date, header->date + sizeof(header->date) ));
String8 user_id = str8_skip_chop_whitespace(str8_cstring_capped(header->user_id, header->user_id + sizeof(header->user_id) ));
String8 group_id = str8_skip_chop_whitespace(str8_cstring_capped(header->group_id, header->group_id + sizeof(header->group_id)));
String8 mode = str8_skip_chop_whitespace(str8_cstring_capped(header->mode, header->mode + sizeof(header->mode) ));
String8 size = str8_skip_chop_whitespace(str8_cstring_capped(header->size, header->size + sizeof(header->size) ));
String8 end = str8_cstring_capped(header->end, header->end + sizeof(header->end));
U32 data_size = u32_from_str8(size, 10);
U64 data_off = offset + sizeof(COFF_ArchiveMemberHeader);
header_out->name = name;
header_out->time_stamp = u32_from_str8(date, 10);
header_out->user_id = u32_from_str8(user_id, 10);
header_out->group_id = u32_from_str8(group_id, 10);
header_out->mode = mode;
header_out->is_end_correct = str8_match_lit("`\n", end, 0);
header_out->data_range = rng_1u64(data_off, data_off + data_size);
return sizeof(*header);
}
return 0;
}
internal COFF_ArchiveFirstMember
coff_parse_first_archive_member(COFF_ArchiveMember *member)
{
Assert(str8_match_lit("/", member->header.name, 0));
U64 cursor = 0;
U32 symbol_count = 0;
cursor += str8_deserial_read_struct(member->data, cursor, &symbol_count);
symbol_count = from_be_u32(symbol_count);
Rng1U64 member_offsets_range = rng_1u64(cursor, cursor + symbol_count * sizeof(U32));
cursor += dim_1u64(member_offsets_range);
Rng1U64 string_table_range = rng_1u64(cursor, member->data.size);
cursor += dim_1u64(string_table_range);
String8 raw_member_offsets = str8_substr(member->data, member_offsets_range);
U32 *member_offsets = (U32 *)raw_member_offsets.str;
U64 member_offset_count = raw_member_offsets.size / sizeof(member_offsets[0]);
COFF_ArchiveFirstMember result = {0};
result.symbol_count = symbol_count;
result.member_offset_count = member_offset_count;
result.member_offsets = member_offsets;
result.string_table = str8_substr(member->data, string_table_range);
return result;
}
internal COFF_ArchiveSecondMember
coff_parse_second_archive_member(COFF_ArchiveMember *member)
{
COFF_ArchiveSecondMember result = {0};
if (str8_match_lit("/", member->header.name, 0)) {
U64 cursor = 0;
U32 member_count = 0;
cursor += str8_deserial_read_struct(member->data, cursor, &member_count);
Rng1U64 member_offsets_range = rng_1u64(cursor, cursor + member_count * sizeof(U32));
cursor += dim_1u64(member_offsets_range);
U32 symbol_count = 0;
cursor += str8_deserial_read_struct(member->data, cursor, &symbol_count);
Rng1U64 symbol_indices_range = rng_1u64(cursor, cursor + symbol_count * sizeof(U16));
cursor += dim_1u64(symbol_indices_range);
Rng1U64 string_table_range = rng_1u64(cursor, member->data.size);
String8 raw_member_offsets = str8_substr(member->data, member_offsets_range);
String8 raw_indices = str8_substr(member->data, symbol_indices_range);
U32 *member_offsets = (U32 *)raw_member_offsets.str;
U64 member_offset_count = raw_member_offsets.size / sizeof(member_offsets[0]);
U16 *symbol_indices = (U16 *)raw_indices.str;
U64 symbol_index_count = raw_indices.size / sizeof(symbol_indices[0]);
result.member_count = member_count;
result.symbol_count = symbol_count;
result.member_offsets = member_offsets;
result.member_offset_count = member_offset_count;
result.symbol_indices = symbol_indices;
result.symbol_index_count = symbol_index_count;
result.string_table = str8_substr(member->data, string_table_range);
}
return result;
}
internal String8
coff_parse_long_name(String8 long_names, String8 name)
{
String8 result = name;
if (name.size > 0 && name.str[0] == '/') {
String8 offset_str = str8(name.str + 1, name.size - 1);
U64 offset = u64_from_str8(offset_str, 10);
if (offset < long_names.size) {
U8 *ptr = long_names.str + offset;
U8 *opl = long_names.str + long_names.size;
for (; ptr < opl; ++ptr) {
if (*ptr == '\0' || *ptr == '\n') {
break;
}
}
result = str8_range(long_names.str + offset, ptr);
}
}
return result;
}
internal U64
coff_parse_import(String8 raw_archive_member, U64 offset, COFF_ParsedArchiveImportHeader *header_out)
{
COFF_ImportHeader *header = str8_deserial_get_raw_ptr(raw_archive_member, offset, sizeof(*header));
if (header) {
Rng1U64 data_range = rng_1u64(offset + sizeof(*header), offset + sizeof(*header) + header->data_size);
String8 raw_data = str8_substr(raw_archive_member, data_range);
U64 data_cursor = 0;
header_out->version = header->version;
header_out->machine = header->machine;
header_out->time_stamp = header->time_stamp;
header_out->data_size = header->data_size;
header_out->hint_or_ordinal = header->hint_or_ordinal;
header_out->type = COFF_ImportHeader_ExtractType(header->flags);
header_out->import_by = COFF_ImportHeader_ExtractImportBy(header->flags);
data_cursor += str8_deserial_read_cstr(raw_data, data_cursor, &header_out->func_name);
data_cursor += str8_deserial_read_cstr(raw_data, data_cursor, &header_out->dll_name);
Assert(header_out->func_name.size + header_out->dll_name.size + /* nulls */ 2 == header_out->data_size);
U64 read_size = sizeof(*header) + header->data_size;
return read_size;
}
return 0;
}
internal COFF_ArchiveMember
coff_archive_member_from_offset(String8 raw_archive, U64 offset)
{
COFF_ArchiveMember member = {0};
coff_regular_archive_member_iter_next(raw_archive, &offset, &member);
return member;
}
internal COFF_ArchiveMember
coff_archive_member_from_data(String8 raw_archive_member)
{
return coff_archive_member_from_offset(raw_archive_member, 0);
}
internal COFF_ParsedArchiveImportHeader
coff_archive_import_from_data(String8 raw_archive_member)
{
COFF_ParsedArchiveImportHeader header = {0};
coff_parse_import(raw_archive_member, 0, &header);
return header;
}
internal U64
coff_regular_archive_member_iter_init(String8 raw_archive)
{
U64 cursor = raw_archive.size;
if (coff_is_regular_archive(raw_archive)) {
cursor = sizeof(g_coff_archive_sig);
}
return cursor;
}
internal B32
coff_regular_archive_member_iter_next(String8 raw_archive, U64 *offset, COFF_ArchiveMember *member_out)
{
B32 is_parsed = 0;
member_out->header.is_end_correct = 0;
U64 header_size = coff_parse_archive_member_header(raw_archive, *offset, &member_out->header);
if (member_out->header.is_end_correct) {
member_out->offset = *offset;
member_out->data = str8_substr(raw_archive, member_out->header.data_range);
U64 read_size = AlignPow2(header_size + dim_1u64(member_out->header.data_range), COFF_Archive_MemberAlign);
*offset += read_size;
is_parsed = 1;
}
return is_parsed;
}
internal U64
coff_thin_archive_member_iter_init(String8 raw_archive)
{
U64 cursor = raw_archive.size;
if (coff_is_thin_archive(raw_archive)) {
cursor = sizeof(g_coff_thin_archive_sig);
}
return cursor;
}
internal B32
coff_thin_archive_member_iter_next(String8 raw_archive, U64 *offset, COFF_ArchiveMember *member_out)
{
B32 is_parsed = 0;
member_out->header.is_end_correct = 0;
U64 header_size = coff_parse_archive_member_header(raw_archive, *offset, &member_out->header);
if (member_out->header.is_end_correct) {
Rng1U64 data_in_archive_range = {0};
if (str8_match_lit("/", member_out->header.name, 0) || str8_match_lit("//", member_out->header.name, 0)) {
data_in_archive_range = member_out->header.data_range;
}
member_out->offset = *offset;
member_out->data = str8_substr(raw_archive, data_in_archive_range);
U64 read_size = AlignPow2(header_size + dim_1u64(data_in_archive_range), COFF_Archive_MemberAlign);
*offset += read_size;
is_parsed = 1;
}
return is_parsed;
}
internal void
coff_archive_member_list_push_node(COFF_ArchiveMemberList *list, COFF_ArchiveMemberNode *node)
{
SLLQueuePush(list->first, list->last, node);
list->count += 1;
}
internal COFF_ArchiveParse
coff_archive_parse_from_member_list(COFF_ArchiveMemberList member_list)
{
String8 error = str8_zero();
B32 has_second_header = 0;
B32 has_long_names = 0;
COFF_ArchiveMember first_header = {0};
COFF_ArchiveMember second_header = {0};
COFF_ArchiveMember long_names_member = {0};
COFF_ArchiveMemberNode *ptr = member_list.first;
if (ptr) {
if (str8_match_lit("/", ptr->data.header.name, 0)) {
if (ptr->data.header.is_end_correct) {
first_header = ptr->data;
ptr = ptr->next;
} else {
error = str8_lit("first header doesn't have correct end");
}
}
} else {
error = str8_lit("missing first header");
}
if (!error.size && ptr) {
if (str8_match_lit("/", ptr->data.header.name, 0)) {
if (ptr->data.header.is_end_correct) {
second_header = ptr->data;
ptr = ptr->next;
has_second_header = 1;
} else {
error = str8_lit("second header doesn't have correct end");
}
}
}
if (!error.size && ptr) {
if (str8_match_lit("//", ptr->data.header.name, 0)) {
if (ptr->data.header.is_end_correct) {
long_names_member = ptr->data;
ptr = ptr->next;
has_long_names;
} else {
error = str8_lit("long names header doesn't have correct end");
}
}
}
COFF_ArchiveParse parse = {0};
parse.has_second_header = has_second_header;
parse.has_long_names = has_long_names;
parse.first_member = coff_parse_first_archive_member(&first_header);
parse.second_member = coff_parse_second_archive_member(&second_header);
parse.long_names = long_names_member.data;
parse.error = error;
return parse;
}
internal COFF_ArchiveParse
coff_regular_archive_parse_from_data(String8 raw_archive)
{
COFF_ArchiveMemberList list = {0};
COFF_ArchiveMemberNode node_arr[3] = {0};
U64 cursor = coff_regular_archive_member_iter_init(raw_archive);
for (U64 i = 0; i < ArrayCount(node_arr); ++i) {
COFF_ArchiveMemberNode *node = &node_arr[i];
if (!coff_regular_archive_member_iter_next(raw_archive, &cursor, &node->data)) {
break;
}
coff_archive_member_list_push_node(&list, node);
}
return coff_archive_parse_from_member_list(list);
}
internal COFF_ArchiveParse
coff_thin_archive_parse_from_data(String8 raw_archive)
{
COFF_ArchiveMemberList list = {0};
COFF_ArchiveMemberNode node_arr[3] = {0};
U64 cursor = coff_thin_archive_member_iter_init(raw_archive);
for (U64 i = 0; i < ArrayCount(node_arr); i += 1) {
COFF_ArchiveMemberNode *node = &node_arr[i];
if (!coff_thin_archive_member_iter_next(raw_archive, &cursor, &node->data)) {
break;
}
coff_archive_member_list_push_node(&list, node);
}
return coff_archive_parse_from_member_list(list);
}
internal COFF_ArchiveParse
coff_archive_parse_from_data(String8 raw_archive)
{
COFF_ArchiveType type = coff_archive_type_from_data(raw_archive);
switch (type) {
case COFF_Archive_Null: break;
case COFF_Archive_Regular: return coff_regular_archive_parse_from_data(raw_archive);
case COFF_Archive_Thin: return coff_thin_archive_parse_from_data(raw_archive);
}
COFF_ArchiveParse null_parse = {0};
return null_parse;
}
+315
View File
@@ -0,0 +1,315 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef COFF_PARSE_H
#define COFF_PARSE_H
typedef struct COFF_FileHeaderInfo
{
B32 is_big_obj;
COFF_MachineType machine;
U64 header_size;
U64 section_array_off;
U64 section_count_no_null;
U64 string_table_off;
U64 symbol_size;
U64 symbol_off;
U64 symbol_count;
} COFF_FileHeaderInfo;
////////////////////////////////
typedef struct COFF_SectionHeaderArray
{
U64 count;
COFF_SectionHeader *v;
} COFF_SectionHeaderArray;
////////////////////////////////
typedef struct COFF_Symbol16Node
{
struct COFF_Symbol16Node *next;
COFF_Symbol16 data;
} COFF_Symbol16Node;
typedef struct COFF_Symbol16List
{
U64 count;
COFF_Symbol16Node *first;
COFF_Symbol16Node *last;
} COFF_Symbol16List;
typedef struct COFF_Symbol32Array
{
U64 count;
COFF_Symbol32 *v;
} COFF_Symbol32Array;
typedef struct COFF_ParsedSymbol
{
String8 name;
U32 value;
U32 section_number;
COFF_SymbolType type;
COFF_SymStorageClass storage_class;
U8 aux_symbol_count;
} COFF_ParsedSymbol;
typedef U32 COFF_SymbolValueInterpType;
enum
{
COFF_SymbolValueInterp_Regular, // symbol has section and offset.
COFF_SymbolValueInterp_Weak, // symbol is overridable.
COFF_SymbolValueInterp_Undefined, // symbol doesn't have a reference section.
COFF_SymbolValueInterp_Common, // symbol has no section but still has size.
COFF_SymbolValueInterp_Abs, // symbol has an absolute (non-relocatable) value and is not an address.
COFF_SymbolValueInterp_Debug // symbol is used to provide general type of debugging information.
};
////////////////////////////////
typedef struct COFF_RelocNode
{
struct COFF_RelocNode *next;
COFF_Reloc data;
} COFF_RelocNode;
typedef struct COFF_RelocList
{
U64 count;
COFF_RelocNode *first;
COFF_RelocNode *last;
} COFF_RelocList;
typedef struct COFF_RelocArray
{
U64 count;
COFF_Reloc *v;
} COFF_RelocArray;
typedef struct COFF_RelocInfo
{
U64 array_off;
U64 count;
} COFF_RelocInfo;
////////////////////////////////
typedef U32 COFF_ResourceIDType;
enum COFF_ResourceIDTypeEnum
{
COFF_ResourceIDType_Null,
COFF_ResourceIDType_Number,
COFF_ResourceIDType_String,
COFF_ResourceIDType_Count
};
typedef struct COFF_ResourceID16
{
COFF_ResourceIDType type;
union {
U16 number;
String16 string;
} u;
} COFF_ResourceID16;
typedef struct COFF_ResourceID
{
COFF_ResourceIDType type;
union {
U16 number;
String8 string;
} u;
} COFF_ResourceID;
typedef struct COFF_ParsedResource
{
COFF_ResourceID type;
COFF_ResourceID name;
U32 data_version;
COFF_ResourceMemoryFlags memory_flags;
U16 language_id;
U32 version;
U32 characteristics;
String8 data;
} COFF_ParsedResource;
typedef struct COFF_ParsedResourceNode
{
struct COFF_ParsedResourceNode *next;
COFF_ParsedResource data;
} COFF_ParsedResourceNode;
typedef struct COFF_ParsedResourceList
{
U64 count;
COFF_ParsedResourceNode *first;
COFF_ParsedResourceNode *last;
} COFF_ParsedResourceList;
////////////////////////////////
typedef enum
{
COFF_DataType_Null,
COFF_DataType_Obj,
COFF_DataType_BigObj,
COFF_DataType_Import
} COFF_DataType;
typedef enum
{
COFF_Archive_Null,
COFF_Archive_Regular,
COFF_Archive_Thin
} COFF_ArchiveType;
typedef struct COFF_ParsedArchiveMemberHeader
{
String8 name; // padded to 16 bytes with spaces
COFF_TimeStamp time_stamp;
U32 user_id; // unix artifact that does not have meaning on windows
U32 group_id; // unix artifact that does not have meaning on windows
String8 mode; // octal representation the members file mode
B32 is_end_correct; // set to true if found correct signature after header
Rng1U64 data_range;
} COFF_ParsedArchiveMemberHeader;
typedef struct COFF_ParsedArchiveImportHeader
{
B32 is_sig_correct;
U16 version;
COFF_MachineType machine;
COFF_TimeStamp time_stamp;
U32 data_size;
U16 hint_or_ordinal;
COFF_ImportType type;
COFF_ImportByType import_by;
String8 func_name;
String8 dll_name;
} COFF_ParsedArchiveImportHeader;
typedef struct COFF_ArchiveMember
{
COFF_ParsedArchiveMemberHeader header;
U64 offset;
String8 data;
} COFF_ArchiveMember;
typedef struct COFF_ArchiveFirstMember
{
U32 symbol_count;
U64 member_offset_count;
U32 *member_offsets;
String8 string_table;
} COFF_ArchiveFirstMember;
typedef struct COFF_ArchiveSecondMember
{
U32 member_count;
U32 symbol_count;
U64 member_offset_count;
U32 *member_offsets;
U64 symbol_index_count;
U16 *symbol_indices;
String8 string_table;
} COFF_ArchiveSecondMember;
typedef struct COFF_ArchiveMemberNode
{
struct COFF_ArchiveMemberNode *next;
COFF_ArchiveMember data;
} COFF_ArchiveMemberNode;
typedef struct COFF_ArchiveMemberList
{
U64 count;
COFF_ArchiveMemberNode *first;
COFF_ArchiveMemberNode *last;
} COFF_ArchiveMemberList;
typedef struct COFF_ArchiveParse
{
B32 has_second_header;
B32 has_long_names;
COFF_ArchiveFirstMember first_member;
COFF_ArchiveSecondMember second_member;
String8 long_names;
String8 error;
} COFF_ArchiveParse;
////////////////////////////////
// Obj Header
internal B32 coff_is_big_obj(String8 raw_coff);
internal B32 coff_is_obj (String8 raw_coff);
internal COFF_FileHeaderInfo coff_file_header_info_from_data(String8 raw_coff);
////////////////////////////////
// Symbol
internal COFF_ParsedSymbol coff_parse_symbol32(String8 raw_coff, U64 string_table_off, COFF_Symbol32 *sym32);
internal COFF_ParsedSymbol coff_parse_symbol16(String8 raw_coff, U64 string_table_off, COFF_Symbol16 *sym16);
internal COFF_Symbol32Array coff_symbol_array_from_data_16(Arena *arena, String8 data, U64 symbol_array_off, U64 symbol_count);
internal COFF_Symbol32Array coff_symbol_array_from_data_32(Arena *arena, String8 data, U64 symbol_array_off, U64 symbol_count);
internal COFF_Symbol32Array coff_symbol_array_from_data (Arena *arena, String8 data, U64 symbol_array_off, U64 symbol_count, U64 symbol_size);
internal COFF_Symbol16Node *coff_symbol16_list_push(Arena *arena, COFF_Symbol16List *list, COFF_Symbol16 symbol);
internal COFF_SymbolValueInterpType coff_interp_symbol(U32 section_number, U32 value, COFF_SymStorageClass storage_class);
////////////////////////////////
// Reloc
internal COFF_RelocInfo coff_reloc_info_from_section_header(String8 data, COFF_SectionHeader *header);
////////////////////////////////
// Resource
internal String8 coff_resource_string_from_str16 (Arena *arena, String16 string);
internal String8 coff_resource_string_from_str8 (Arena *arena, String8 string);
internal String8 coff_resource_number_from_u16 (Arena *arena, U16 number);
internal COFF_ResourceID coff_utf8_resource_id_from_utf16(Arena *arena, COFF_ResourceID16 *id_16);
internal U64 coff_read_resource_id_utf16 (String8 raw_res, U64 off, COFF_ResourceID16 *id_out);
internal U64 coff_read_resource (Arena *arena, String8 raw_res, U64 off, COFF_ParsedResource *res_out);
internal COFF_ParsedResourceList coff_resource_list_from_data(Arena *arena, String8 data);
internal String8 coff_write_resource_id(Arena *arena, COFF_ResourceID id);
internal String8 coff_write_resource (Arena *arena, COFF_ResourceID type, COFF_ResourceID name, U32 data_version, COFF_ResourceMemoryFlags memory_flags, U16 language_id, U32 version, U32 characteristics, String8 data);
internal int coff_resource_id_compar(void *raw_a, void *raw_b); // COFF_ResourceID
////////////////////////////////
// Archive
internal B32 coff_is_import (String8 raw_archive_member);
internal COFF_DataType coff_data_type_from_data (String8 raw_archive_member);
internal B32 coff_is_regular_archive (String8 raw_archive);
internal B32 coff_is_thin_archive (String8 raw_archive);
internal COFF_ArchiveType coff_archive_type_from_data(String8 raw_archive);
internal U64 coff_parse_archive_member_header(String8 raw_archive, U64 offset, COFF_ParsedArchiveMemberHeader *header_out);
internal COFF_ArchiveFirstMember coff_parse_first_archive_member (COFF_ArchiveMember *member);
internal COFF_ArchiveSecondMember coff_parse_second_archive_member(COFF_ArchiveMember *member);
internal String8 coff_parse_long_name (String8 long_names, String8 name);
internal U64 coff_parse_import (String8 raw_archive_member, U64 offset, COFF_ParsedArchiveImportHeader *header_out);
internal COFF_ArchiveMember coff_archive_member_from_offset(String8 raw_archive, U64 offset);
internal COFF_ArchiveMember coff_archive_member_from_data (String8 raw_archive_member);
internal COFF_ParsedArchiveImportHeader coff_archive_import_from_data (String8 raw_archive_member);
internal U64 coff_regular_archive_member_iter_init(String8 raw_archive);
internal B32 coff_regular_archive_member_iter_next(String8 raw_archive, U64 *offset, COFF_ArchiveMember *member_out);
internal U64 coff_thin_archive_member_iter_init(String8 raw_archive);
internal B32 coff_thin_archive_member_iter_next(String8 raw_archive, U64 *offset, COFF_ArchiveMember *member_out);
internal COFF_ArchiveParse coff_regular_archive_parse_from_member_list(COFF_ArchiveMemberList list);
internal COFF_ArchiveParse coff_thin_archive_parse_from_data (String8 raw_archive);
internal COFF_ArchiveParse coff_regular_archive_parse_from_data (String8 raw_archive);
internal COFF_ArchiveParse coff_archive_parse_from_data (String8 raw_archive);
#endif // COFF_PARSE_H
+9 -9
View File
@@ -3489,20 +3489,20 @@ ctrl_thread__module_open(CTRL_Handle process, CTRL_Handle module, Rng1U64 vaddr_
}
//- rjf: read COFF header
U64 coff_header_off = dos_header.coff_file_offset + sizeof(pe_magic);
COFF_Header coff_header = {0};
U64 file_header_off = dos_header.coff_file_offset + sizeof(pe_magic);
COFF_FileHeader file_header = {0};
if(is_valid)
{
if(!dmn_process_read_struct(process.dmn_handle, vaddr_range.min + coff_header_off, &coff_header))
if(!dmn_process_read_struct(process.dmn_handle, vaddr_range.min + file_header_off, &file_header))
{
is_valid = 0;
}
}
//- rjf: unpack range of optional extension header
U32 opt_ext_size = coff_header.optional_header_size;
Rng1U64 opt_ext_off_range = r1u64(coff_header_off + sizeof(coff_header),
coff_header_off + sizeof(coff_header) + opt_ext_size);
U32 opt_ext_size = file_header.optional_header_size;
Rng1U64 opt_ext_off_range = r1u64(file_header_off + sizeof(COFF_FileHeader),
file_header_off + sizeof(COFF_FileHeader) + opt_ext_size);
//- rjf: read optional header
U16 optional_magic = 0;
@@ -3569,10 +3569,10 @@ ctrl_thread__module_open(CTRL_Handle process, CTRL_Handle module, Rng1U64 vaddr_
PE_DataDirectory dir = {0};
dmn_process_read_struct(process.dmn_handle, vaddr_range.min + opt_ext_off_range.min + reported_data_dir_offset + sizeof(PE_DataDirectory)*PE_DataDirectoryIndex_TLS, &dir);
Rng1U64 tls_voff_range = r1u64((U64)dir.virt_off, (U64)dir.virt_off + (U64)dir.virt_size);
switch(coff_header.machine)
switch(file_header.machine)
{
default:{}break;
case COFF_MachineType_X86:
case COFF_Machine_X86:
{
PE_TLSHeader32 tls_header32 = {0};
dmn_process_read_struct(process.dmn_handle, vaddr_range.min + tls_voff_range.min, &tls_header32);
@@ -3583,7 +3583,7 @@ ctrl_thread__module_open(CTRL_Handle process, CTRL_Handle module, Rng1U64 vaddr_
tls_header.zero_fill_size = (U64)tls_header32.zero_fill_size;
tls_header.characteristics = (U64)tls_header32.characteristics;
}break;
case COFF_MachineType_X64:
case COFF_Machine_X64:
{
dmn_process_read_struct(process.dmn_handle, vaddr_range.min + tls_voff_range.min, &tls_header);
}break;
+11 -11
View File
@@ -469,9 +469,9 @@ dmn_w32_image_info_from_process_base_vaddr(HANDLE process, U64 base_vaddr)
}
// rjf: get COFF header
B32 got_coff_header = 0;
U64 coff_header_off = 0;
COFF_Header coff_header = {0};
B32 got_file_header = 0;
U64 file_header_off = 0;
COFF_FileHeader file_header = {0};
if(pe_offset > 0)
{
U64 pe_magic_off = base_vaddr + pe_offset;
@@ -479,28 +479,28 @@ dmn_w32_image_info_from_process_base_vaddr(HANDLE process, U64 base_vaddr)
dmn_w32_process_read_struct(process, pe_magic_off, &pe_magic);
if(pe_magic == PE_MAGIC)
{
coff_header_off = pe_magic_off + sizeof(pe_magic);
if(dmn_w32_process_read_struct(process, coff_header_off, &coff_header))
file_header_off = pe_magic_off + sizeof(pe_magic);
if(dmn_w32_process_read_struct(process, file_header_off, &file_header))
{
got_coff_header = 1;
got_file_header = 1;
}
}
}
// rjf: get arch and size
DMN_W32_ImageInfo result = zero_struct;
if(got_coff_header)
if(got_file_header)
{
U64 optional_size_off = 0;
Arch arch = Arch_Null;
switch(coff_header.machine)
switch(file_header.machine)
{
case COFF_MachineType_X86:
case COFF_Machine_X86:
{
arch = Arch_x86;
optional_size_off = OffsetOf(PE_OptionalHeader32, sizeof_image);
}break;
case COFF_MachineType_X64:
case COFF_Machine_X64:
{
arch = Arch_x64;
optional_size_off = OffsetOf(PE_OptionalHeader32Plus, sizeof_image);
@@ -510,7 +510,7 @@ dmn_w32_image_info_from_process_base_vaddr(HANDLE process, U64 base_vaddr)
}
if(arch != Arch_Null)
{
U64 optional_off = coff_header_off + sizeof(coff_header);
U64 optional_off = file_header_off + sizeof(COFF_FileHeader);
U32 size = 0;
if(dmn_w32_process_read_struct(process, optional_off+optional_size_off, &size) >= sizeof(size))
{
File diff suppressed because it is too large Load Diff
+266
View File
@@ -0,0 +1,266 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
internal DW_AttribClass
dw_attrib_class_from_attrib_kind_v2(DW_AttribKind k)
{
switch (k) {
#define X(_N,_C) case DW_Attrib_##_N: return _C;
DW_AttribKind_ClassFlags_V2_XList(X)
#undef X
}
return DW_AttribClass_Null;
}
internal DW_AttribClass
dw_attrib_class_from_attrib_kind_v3(DW_AttribKind k)
{
switch (k) {
#define X(_N,_C) case DW_Attrib_##_N: return _C;
DW_AttribKind_ClassFlags_V3_XList(X)
#undef X
}
return DW_AttribClass_Null;
}
internal DW_AttribClass
dw_attrib_class_from_attrib_kind_v4(DW_AttribKind k)
{
switch (k) {
#define X(_N,_C) case DW_Attrib_##_N: return _C;
DW_AttribKind_ClassFlags_V4_XList(X)
#undef X
}
return DW_AttribClass_Null;
}
internal DW_AttribClass
dw_attrib_class_from_attrib_kind_v5(DW_AttribKind k)
{
switch (k) {
#define X(_N,_C) case DW_Attrib_##_N: return _C;
DW_AttribKind_ClassFlags_V5_XList(X)
#undef X
}
return DW_AttribClass_Null;
}
internal DW_AttribClass
dw_attrib_class_from_attrib_kind_gnu(DW_AttribKind k)
{
switch (k) {
#define X(_N,_C) case DW_Attrib_##_N: return _C;
DW_AttribKind_ClassFlags_GNU_XList(X)
#undef X
}
return DW_AttribClass_Null;
}
internal DW_AttribClass
dw_attrib_class_from_attrib_kind_llvm(DW_AttribKind k)
{
switch (k) {
#define X(_N,_C) case DW_Attrib_##_N: return _C;
DW_AttribKind_ClassFlags_LLVM_XList(X)
#undef X
}
return DW_AttribClass_Null;
}
internal DW_AttribClass
dw_attrib_class_from_attrib_kind_apple(DW_AttribKind k)
{
switch (k) {
#define X(_N,_C) case DW_Attrib_##_N: return _C;
DW_AttribKind_ClassFlags_APPLE_XList(X)
#undef X
}
return DW_AttribClass_Null;
}
internal DW_AttribClass
dw_attrib_class_from_attrib_kind_mips(DW_AttribKind k)
{
switch (k) {
#define X(_N,_C) case DW_Attrib_##_N: return _C;
DW_AttribKind_ClassFlags_MIPS_XList(X)
#undef X
}
return DW_AttribClass_Null;
}
internal DW_AttribClass
dw_attrib_class_from_attrib_kind(DW_Version ver, DW_Ext ext, DW_AttribKind k)
{
DW_AttribClass result = DW_AttribClass_Null;
while (ext) {
U64 z = 64-clz64(ext);
if (z == 0) {
break;
}
U64 flag = 1 << (z-1);
ext &= ~flag;
switch (flag) {
case DW_Ext_Null: break;
case DW_Ext_GNU: result = dw_attrib_class_from_attrib_kind_gnu(k); break;
case DW_Ext_LLVM: result = dw_attrib_class_from_attrib_kind_llvm(k); break;
case DW_Ext_APPLE: result = dw_attrib_class_from_attrib_kind_apple(k); break;
case DW_Ext_MIPS: result = dw_attrib_class_from_attrib_kind_mips(k); break;
default: InvalidPath; break;
}
if (result != DW_AttribClass_Null) {
break;
}
}
if (result == DW_AttribClass_Null) {
switch (ver) {
case DW_Version_Null: break;
case DW_Version_1: AssertAlways(!"DWARF V1 is not supported"); break;
case DW_Version_2: result = dw_attrib_class_from_attrib_kind_v2(k); break;
case DW_Version_3: result = dw_attrib_class_from_attrib_kind_v3(k); break;
case DW_Version_4: result = dw_attrib_class_from_attrib_kind_v4(k); break;
case DW_Version_5: result = dw_attrib_class_from_attrib_kind_v5(k); break;
default: InvalidPath; break;
}
}
return result;
}
internal DW_AttribClass
dw_attrib_class_from_form_kind(DW_Version ver, DW_FormKind k)
{
#define X(_N,_C) case DW_Form_##_N: return _C;
switch (ver) {
case DW_Version_5: {
switch (k) {
DW_Form_AttribClass_V5_XList(X)
}
} break;
case DW_Version_4: {
switch (k) {
DW_Form_AttribClass_V4_XList(X)
}
} break;
case DW_Version_3: {
switch (k) {
DW_Form_AttribClass_V2_XList(X)
}
} break;
case DW_Version_2: {
switch (k) {
DW_Form_AttribClass_V2_XList(X)
}
} break;
case DW_Version_1: {
} break;
case DW_Version_Null: break;
}
#undef X
return DW_AttribClass_Null;
}
internal B32
dw_are_attrib_class_and_form_kind_compatible(DW_Version ver, DW_AttribClass attrib_class, DW_FormKind form_kind)
{
DW_AttribClass compat_flags = dw_attrib_class_from_form_kind(ver, form_kind);
B32 are_compat = (attrib_class & compat_flags) != 0;
return are_compat;
}
internal String8
dw_name_string_from_section_kind(DW_SectionKind k)
{
switch (k) {
#define X(_N,_L,_M,_D) case DW_Section_##_N: return str8_lit(_L);
DW_SectionKind_XList(X)
#undef X
}
return str8_zero();
}
internal String8
dw_mach_name_string_from_section_kind(DW_SectionKind k)
{
switch (k) {
#define X(_N,_L,_M,_D) case DW_Section_##_N: return str8_lit(_M);
DW_SectionKind_XList(X)
#undef X
}
return str8_zero();
}
internal String8
dw_dwo_name_string_from_section_kind(DW_SectionKind k)
{
switch (k) {
#define X(_N,_L,_M,_D) case DW_Section_##_N: return str8_lit(_D);
DW_SectionKind_XList(X)
#undef X
}
return str8_zero();
}
internal U64
dw_offset_size_from_mode(DW_Mode mode)
{
U64 result = 0;
switch (mode) {
case DW_Mode_Null: break;
case DW_Mode_32Bit: result = 4; break;
case DW_Mode_64Bit: result = 8; break;
default: InvalidPath; break;
}
return result;
}
internal DW_AttribClass
dw_pick_attrib_value_class(DW_Version ver, DW_Ext ext, DW_Language lang, B32 relaxed, DW_AttribKind attrib_kind, DW_FormKind form_kind)
{
// NOTE(rjf): DWARF's spec specifies two mappings:
// (DW_AttribKind) => List(DW_AttribClass)
// (DW_FormKind) => List(DW_AttribClass)
//
// This function's purpose is to find the overlapping class between an
// DW_AttribKind and DW_FormKind.
DW_AttribClass attrib_class = dw_attrib_class_from_attrib_kind(ver, ext, attrib_kind);
DW_AttribClass form_class = dw_attrib_class_from_form_kind(ver, form_kind);
if(relaxed)
{
if(attrib_class == DW_AttribClass_Null || form_class == DW_AttribClass_Null)
{
attrib_class = dw_attrib_class_from_attrib_kind(DW_Version_Last, ext, attrib_kind);
form_class = dw_attrib_class_from_form_kind(DW_Version_Last, form_kind);
}
}
DW_AttribClass result = DW_AttribClass_Null;
if(attrib_class != DW_AttribClass_Null && form_class != DW_AttribClass_Null)
{
result = DW_AttribClass_Undefined;
for(U32 i = 0; i < 32; ++i)
{
U32 n = 1u << i;
if((attrib_class & n) != 0 && (form_class & n) != 0)
{
result = ((DW_AttribClass) n);
break;
}
}
}
if (attrib_kind != DW_Attrib_Null && form_kind != DW_Form_Null) {
//Assert(result != DW_AttribClass_Null && result != DW_AttribClass_Undefined);
}
return result;
}
+1688
View File
File diff suppressed because it is too large Load Diff
+225
View File
@@ -0,0 +1,225 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
internal String8
dw_string_from_expr_op(Arena *arena, DW_Version ver, DW_Ext ext, DW_ExprOp op)
{
String8 result = {0};
#define X(_N,...) case DW_ExprOp_##_N: result = str8_lit(Stringify(_N)); goto exit;
switch (ext) {
case DW_Ext_Null: break;
case DW_Ext_LLVM: break;
case DW_Ext_APPLE: break;
case DW_Ext_MIPS: break;
case DW_Ext_GNU: DW_Expr_GNU_XList(X); break;
}
switch (ver) {
case DW_Version_5: {
switch (op) {
DW_Expr_V5_XList(X)
}
} // fall-through
case DW_Version_4: {
switch (op) {
DW_Expr_V4_XList(X)
}
} // fall-through
case DW_Version_3: {
switch (op) {
DW_Expr_V3_XList(X)
}
} // fall-through
case DW_Version_2:
case DW_Version_1:
case DW_Version_Null:
break;
}
#undef X
result = push_str8f(arena, "%x", op);
exit:;
return result;
}
internal String8
dw_string_from_tag_kind(Arena *arena, DW_TagKind kind)
{
switch (kind) {
#define X(_N,_ID) case DW_Tag_##_N: return str8_lit(Stringify(_N));
DW_Tag_V3_XList(X)
DW_Tag_V5_XList(X)
DW_Tag_GNU_XList(X)
#undef X
}
return push_str8f(arena, "%llx", kind);
}
internal String8
dw_string_from_attrib_kind(Arena *arena, DW_Version ver, DW_Ext ext, DW_AttribKind kind)
{
#define X(_N,...) case DW_Attrib_##_N: return str8_lit(Stringify(_N));
while (ext) {
U64 z = 64-clz64(ext);
if (z == 0) {
break;
}
U64 flag = 1 << (z-1);
ext &= ~flag;
switch (flag) {
case DW_Ext_Null: break;
case DW_Ext_GNU: switch (kind) { DW_AttribKind_GNU_XList(X) } break;
case DW_Ext_LLVM: switch (kind) { DW_AttribKind_LLVM_XList(X) } break;
case DW_Ext_APPLE: switch (kind) { DW_AttribKind_APPLE_XList(X) } break;
case DW_Ext_MIPS: switch (kind) { DW_AttribKind_MIPS_XList(X) } break;
default: InvalidPath; break;
}
}
switch (ver) {
case DW_Version_5: {
switch (kind) {
DW_AttribKind_V5_XList(X)
}
} // fall-through
case DW_Version_4: {
switch (kind) {
DW_AttribKind_V4_XList(X)
}
} // fall-through
case DW_Version_3: {
switch (kind) {
DW_AttribKind_V3_XList(X)
}
} // fall-through
case DW_Version_2: {
switch (kind) {
DW_AttribKind_V2_XList(X)
}
} // fall-through
case DW_Version_1: {
} // fall-through
case DW_Version_Null: break;
}
#undef X
return str8_zero();
}
internal String8
dw_string_from_form_kind(Arena *arena, DW_Version ver, DW_FormKind kind)
{
#define X(_N,...) case DW_Form_##_N: return str8_lit(Stringify(_N));
switch (ver) {
case DW_Version_5: {
switch (kind) {
DW_Form_V5_XList(X)
}
} // fall-through
case DW_Version_4: {
switch (kind) {
DW_Form_V4_XList(X)
}
} // fall-through
case DW_Version_3:
case DW_Version_2: {
switch (kind) {
DW_Form_V2_XList(X)
}
} // fall-through
case DW_Version_Null: break;
}
#undef X
String8 result = push_str8f(arena, "%x", kind);
return result;
}
internal String8
dw_string_from_language(Arena *arena, DW_Language kind)
{
switch (kind) {
#define X(_N,_ID) case DW_Language_##_N: return str8_lit(Stringify(_N));
DW_Language_XList(X)
#undef X
}
return push_str8f(arena, "%x", kind);
}
internal String8
dw_string_from_std_opcode(Arena *arena, DW_StdOpcode kind)
{
switch (kind) {
#define X(_N,_ID) case DW_StdOpcode_##_N: return str8_lit(Stringify(_N));
DW_StdOpcode_XList(X)
#undef X
}
return push_str8f(arena, "%x", kind);
}
internal String8
dw_string_from_ext_opcode(Arena *arena, DW_ExtOpcode kind)
{
switch (kind) {
#define X(_N,_ID) case DW_ExtOpcode_##_N: return str8_lit(Stringify(_N));
DW_ExtOpcode_XList(X)
#undef X
default: InvalidPath; break;
}
return push_str8f(arena, "%x", kind);
}
internal String8
dw_string_from_loc_list_entry_kind(Arena *arena, DW_LocListEntryKind kind)
{
NotImplemented;
return str8_zero();
}
internal String8
dw_string_from_section_kind(Arena *arena, DW_SectionKind kind)
{
NotImplemented;
return str8_zero();
}
internal String8
dw_string_from_rng_list_entry_kind(Arena *arena, DW_RngListEntryKind kind)
{
NotImplemented;
return str8_zero();
}
internal String8
dw_string_from_register(Arena *arena, Arch arch, U64 reg_id)
{
String8 reg_str = str8_zero();
switch (arch) {
case Arch_Null: break;
case Arch_x86: {
switch (reg_id) {
#define X(_N, _ID, ...) case DW_Reg_x86_##_N: reg_str = str8_lit(Stringify(_ID)); break;
DW_Regs_X86_XList(X)
#undef X
}
} break;
case Arch_x64: {
switch (reg_id) {
#define X(_N, _ID, ...) case DW_Reg_x64_##_N: reg_str = str8_lit(Stringify(_ID)); break;
DW_Regs_X64_XList(X)
#undef X
}
} break;
case Arch_arm32: NotImplemented; break;
case Arch_arm64: NotImplemented; break;
default: InvalidPath; break;
}
if (reg_str.size == 0) {
reg_str = push_str8f(arena, "%#llx", reg_id);
}
return reg_str;
}
+15
View File
@@ -0,0 +1,15 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef DWARF_ENUM_H
#define DWARF_ENUM_H
internal String8 dw_string_from_expr_op(Arena *arena, DW_Version ver, DW_Ext ext, DW_ExprOp op);
internal String8 dw_string_from_tag_kind(Arena *arena, DW_TagKind kind);
internal String8 dw_string_from_attrib_kind(Arena *arena, DW_Version ver, DW_Ext ext, DW_AttribKind kind);
internal String8 dw_string_from_form_kind(Arena *arena, DW_Version ver, DW_FormKind kind);
//internal String8 dw_string_from_register(Arena *arena, Arch arch, U64 reg_id);
#endif // DWARF_ENUM_H
File diff suppressed because it is too large Load Diff
+301
View File
@@ -0,0 +1,301 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef DWARF_EXPR_H
#define DWARF_EXPR_H
////////////////////////////////
//~ Dwarf Register Layout
typedef struct DW_RegsX64
{
union {
struct {
U64 rax;
U64 rdx;
U64 rcx;
U64 rbx;
U64 rsi;
U64 rdi;
U64 rbp;
U64 rsp;
U64 r8;
U64 r9;
U64 r10;
U64 r11;
U64 r12;
U64 r13;
U64 r14;
U64 r15;
U64 rip;
};
U64 r[17];
};
} DW_RegsX64;
////////////////////////////////
//~ Dwarf Expression Eval Types
#define DW_READ_MEMORY_SIG(name) U64 name(U64 addr, U64 size, void *out, void *ud)
typedef DW_READ_MEMORY_SIG(DW_ReadMemorySig);
//- machine configuration types
typedef String8 DW_ExprResolveCallFunc(void *call_user_ptr, U64 p);
typedef struct DW_ExprMachineCallConfig
{
void *user_ptr;
DW_ExprResolveCallFunc *func;
} DW_ExprMachineCallConfig;
typedef struct DW_ExprMachineConfig
{
U64 max_step_count; // (read only in the eval functions)
DW_ReadMemorySig *read_memory;
void *read_memory_ud;
DW_RegsX64 *regs;
U64 *text_section_base;
U64 *frame_base;
U64 *object_address;
U64 *tls_address;
U64 *cfa;
DW_ExprMachineCallConfig call;
} DW_ExprMachineConfig;
//- detail analysis types
typedef U32 DW_ExprFlags;
enum
{
DW_ExprFlag_UsesTextBase = (1 << 0),
DW_ExprFlag_UsesMemory = (1 << 1),
DW_ExprFlag_UsesRegisters = (1 << 2),
DW_ExprFlag_UsesFrameBase = (1 << 3),
DW_ExprFlag_UsesObjectAddress = (1 << 4),
DW_ExprFlag_UsesTLSAddress = (1 << 5),
DW_ExprFlag_UsesCFA = (1 << 6),
DW_ExprFlag_UsesCallResolution = (1 << 7),
DW_ExprFlag_UsesComposite = (1 << 8),
DW_ExprFlag_NotSupported = (1 << 16),
DW_ExprFlag_BadData = (1 << 17),
DW_ExprFlag_NonLinearFlow = (1 << 18)
};
typedef struct DW_ExprAnalysis
{
DW_ExprFlags flags;
} DW_ExprAnalysis;
typedef struct DW_ExprAnalysisTask
{
struct DW_ExprAnalysisTask *next;
U64 p;
String8 data;
} DW_ExprAnalysisTask;
//- location types
typedef enum DW_SimpleLocKind
{
DW_SimpleLocKind_Address,
DW_SimpleLocKind_Register,
DW_SimpleLocKind_Value,
DW_SimpleLocKind_ValueLong,
DW_SimpleLocKind_Empty,
DW_SimpleLocKind_Fail,
} DW_SimpleLocKind;
typedef enum DW_LocFailKind
{
// Interpreting Fail Kinds
//
// BadData: the evaluator detected that the dwarf expression operation is incorrectly formed
// NotSupported: the evaluator does not support a dwarf feature that was found in the dwarf expression
// TimeOut: the evaluator hit the maximum step count
// TooComplicated: used by analyzer when it the expression uses features outside of the analyzer's scope
// Missing*: the dwarf machine config was missing necessary information to finish the evaluation
DW_LocFailKind_BadData,
DW_LocFailKind_NotSupported,
DW_LocFailKind_TimeOut,
DW_LocFailKind_TooComplicated,
DW_LocFailKind_MissingTextBase,
DW_LocFailKind_MissingMemory,
DW_LocFailKind_MissingRegisters,
DW_LocFailKind_MissingFrameBase,
DW_LocFailKind_MissingObjectAddress,
DW_LocFailKind_MissingTLSAddress,
DW_LocFailKind_MissingCFA,
DW_LocFailKind_MissingCallResolution,
DW_LocFailKind_MissingArenaForComposite,
} DW_LocFailKind;
typedef struct DW_SimpleLoc
{
DW_SimpleLocKind kind;
union {
U64 addr;
U64 reg_idx;
U64 val;
String8 val_long;
struct {
DW_LocFailKind fail_kind;
U64 fail_data;
};
};
} DW_SimpleLoc;
typedef struct DW_Piece
{
// Hint for Interpreting Pieces
//
// src = decode(loc, is_bit_loc, bit_size);
// dst |= (src >> bit_off) << bit_cursor;
// bit_cursor += bit_size;
struct DW_Piece *next;
DW_SimpleLoc loc;
U64 bit_size;
U64 bit_off;
B32 is_bit_loc;
} DW_Piece;
typedef struct DW_Location
{
// Interpreting a Dwarf Location
//
// CASE (any number of pieces, fail in the non-piece):
// this is how errors are reported, error information is in the non-piece
// the 'fail' location kind should never show up in a piece
// if there are any pieces they can be treated as correct information that
// was successfully decoded before the error was encountered
//
// CASE (no pieces, empty non-piece):
// the data is completely optimized out and unrecoverable
//
// CASE (no pieces, non-empty non-piece):
// the size of the data is not known by the location, but something in the
// surrounding context of the location (eg type info) should know the size
//
// CASE (one-or-more pieces, empty non-piece):
// the data is described by the pieces
//
// CASE (one-or-more pieces, non-empty non-fail non-piece):
// this is supposed to be impossible; the non-piece either carries an error
// or *all* of the location information about the data, there should never
// be a mix of piece-based location and non-piece-based location data.
DW_Piece *first_piece;
DW_Piece *last_piece;
U64 count;
DW_SimpleLoc non_piece_loc;
} DW_Location;
//- full evaluator state types
typedef struct DW_ExprStackNode
{
struct DW_ExprStackNode *next;
U64 val;
} DW_ExprStackNode;
typedef struct DW_ExprStack
{
DW_ExprStackNode *stack;
DW_ExprStackNode *free_nodes;
U64 count;
} DW_ExprStack;
typedef struct DW_ExprCall
{
struct DW_ExprCall *next;
void *ptr;
U64 size;
U64 cursor;
} DW_ExprCall;
typedef struct DW_ExprCallStack
{
DW_ExprCall *stack;
DW_ExprCall *free_calls;
U64 depth;
} DW_ExprCallStack;
////////////////////////////////
//~ Dwarf Expression Analysis & Eval Functions
//- analyzers
// This analyzer provides the most simplified dwarf expression
// decoding. If the expression consists of a single op that can be interpreted
// as a valid dwarf expression, then it represents that expression as a simple
// location.
//
// If there is a single 'piece' op that is represeted here as an empty simple
// location, losing whatever additional size information from the piece.
//
// If there is an op that requires the machine configuration data the analyzer
// fails with "too complicated" - unless the required configuration data is the
// text section base which this analyzer treats as a non-optional parameter and
// always decodes successfully.
//
// If the expression contains more than one op than the analyzer fails with
// "too complicated".
internal DW_SimpleLoc dw_expr__analyze_fast(void *base, Rng1U64 range, U64 text_section_base);
// This analyzer does a one-pass scan through the expression to
// help a caller determine what to expect before doing a full evaluation which
// has to maintain value stacks, perform more checks, and execute any loops
// that may appear in the expression, etc.
//
// For each piece of data that can be equipped to a machine config there is a
// 'Uses' flag in the analysis. A user can use these flags to determine what to
// prepare and equip before a full eval. This can be a lot more efficient than
// always preparing everything, or iteratively equipping and retrying after
// each failure.
//
// The analysis can also catch some cases of bad data and unsupported features.
// These flags are useful for short circuit style optimizations, but they are
// not definitive, some bad data can only be caught by the full evaluator.
// Sometimes the full evaluator might miss bad data that this analyzer will see
// if control flow in the evaluator completely skips the bad data. A forgiving
// interpretation of dwarf expression data would only rely on the results of
// the full evaluator. A more strict interpretation would consider it an error
// if either this analyzer or the evaluator finds bad data.
//
// The analyzer also determines if there is any possibility for non-linear
// flow. Jumps, branches, and call ops all create non-linear flow. An
// expression that doesn't have non-linear flow is trivially gauranteed to
// terminate and therefore a good candidate for conversion to a human readable
// expression.
//
// The call config is optional (may be null). If is provided the analysis
// includes features seen in all of the expressions that might be reached by
// call ops from the initial expression.
internal DW_ExprAnalysis dw_expr__analyze_details(void *base, Rng1U64 range, DW_ExprMachineCallConfig *call_config);
//- full eval
internal DW_Location dw_expr__eval(Arena *arena_optional, void *base, Rng1U64 range, DW_ExprMachineConfig *config);
//- dw expr val stack
internal DW_ExprStack dw_expr__stack_make(Arena *arena);
internal void dw_expr__stack_push(Arena *arena, DW_ExprStack *stack, U64 x);
internal U64 dw_expr__stack_pop(DW_ExprStack *stack);
internal U64 dw_expr__stack_pick(DW_ExprStack *stack, U64 idx);
internal B32 dw_expr__stack_is_empty(DW_ExprStack *stack);
//- dw expr call stack
internal DW_ExprCall* dw_expr__call_top(DW_ExprCallStack *stack);
internal void dw_expr__call_push(Arena *arena, DW_ExprCallStack *stack, void *ptr, U64 size);
internal void dw_expr__call_pop(DW_ExprCallStack *stack);
//- analysis tasks
internal DW_ExprAnalysisTask* dw_expr__analysis_task_from_p(DW_ExprAnalysisTask *first, U64 p);
#endif //DWARF_EXPR_H
+42
View File
@@ -0,0 +1,42 @@
--- DWARF NOTES ---------------------------------------------------------------
DWARF V4 Spec: http://www.dwarfstd.org/doc/DWARF4.pdf
DWARF V5 Spec: http://www.dwarfstd.org/doc/DWARF5.pdf
-------------------------------------------------------------------------------
$ (2021/04/30) On .debug_pubtypes, .debug_pubnames, and .debug_names:
.debug_pubtypes and .debug_pubnames are tables that map from a string (the name
of a type or function respectively) to an offset into .debug_info, which is the
offset of the Debug Information Entry (DIE, in DWARF terminology) of the info
associated with the string. THESE TWO SECTIONS ARE OPTIONAL. They don't show up
in every DWARF-holding file, and so they cannot be relied upon as acceleration
structures. But we're going to support parsing them, to make things a bit nicer
in cases where they are present. DWARF doesn't have much in the way of acceler-
ation structures built in, so our rationale is that we should take anything we
can get to make the format a bit more in some subset of the possible cases.
.debug_names is a DWARF V5 section that is intended to replace .debug_pubtypes
and .debug_pubnames. However, even in cases when DWARF V5 is produced at the
time of writing this, we have not found .debug_names sections being produced.
We did not exhaustively test all compilers and configurations, but it seems
that it is not well-supported at all by major compilers, and there's a very low
probability that a user will have that section, so our current thinking is
that there's no point in supporting it right now.
-------------------------------------------------------------------------------
$ (2021/04/30) On producing DWARF V5 with Clang:
https://lists.llvm.org/pipermail/llvm-dev/2018-August/125068.html
By default it looks like (at the time of writing this) that Clang, by default,
will produce DWARF V4. To produce DWARF V5, however, you can use the -gdwarf-5
option. Even when that option is used, it seems that some features of V5 are
not used (for example, .debug_names).
The above link also says that this will produce .debug_names, but it doesn't as
of Clang 10.
-------------------------------------------------------------------------------
File diff suppressed because it is too large Load Diff
+494
View File
@@ -0,0 +1,494 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef DWARF_PARSE_H
#define DWARF_PARSE_H
// NOTE(rjf): Some rules about the spaces of offsets and ranges:
//
// - Every stored/passed offset is relative to the base of its section.
// - Every stored/passed range has endpoints relative to the base of their section.
// - Upon calling a syms_based_range_* function, these offsets need to be
// converted into range-relative.
////////////////////////////////
//~ rjf: Constants
#define DWARF_VOID_TYPE_ID 0xffffffffffffffffull
////////////////////////////////
//~ rjf: Files + External Debug References
typedef struct DW_ExtDebugRef DW_ExtDebugRef;
struct DW_ExtDebugRef
{
// NOTE(rjf): .dwo => an external DWARF V5 .dwo file
String8 dwo_path;
U64 dwo_id;
};
////////////////////////////////
//~ rjf: Abbrev Table
typedef struct DW_AbbrevTableEntry DW_AbbrevTableEntry;
struct DW_AbbrevTableEntry
{
U64 id;
U64 off;
};
typedef struct DW_AbbrevTable DW_AbbrevTable;
struct DW_AbbrevTable
{
U64 count;
DW_AbbrevTableEntry *entries;
};
////////////////////////////////
//~ Sections
typedef struct DW_Section DW_Section;
struct DW_Section
{
String8 name;
String8 data;
DW_Mode mode;
B32 is_dwo;
};
typedef struct DW_SectionArray DW_SectionArray;
struct DW_SectionArray
{
DW_Section v[DW_Section_Count];
};
////////////////////////////////
//~ rjf: Basic Line Info
typedef struct DW_LineFile DW_LineFile;
struct DW_LineFile
{
String8 file_name;
U64 dir_idx;
U64 modify_time;
U64 md5_digest[2];
U64 file_size;
};
typedef struct DW_LineVMFileNode DW_LineVMFileNode;
struct DW_LineVMFileNode
{
DW_LineVMFileNode *next;
DW_LineFile file;
};
typedef struct DW_LineVMFileList DW_LineVMFileList;
struct DW_LineVMFileList
{
U64 node_count;
DW_LineVMFileNode *first;
DW_LineVMFileNode *last;
};
typedef struct DW_LineVMFileArray DW_LineVMFileArray;
struct DW_LineVMFileArray
{
U64 count;
DW_LineFile *v;
};
////////////////////////////////
//~ rjf: Abbrevs
typedef enum DW_AbbrevKind
{
DW_Abbrev_Null,
DW_Abbrev_Tag,
DW_Abbrev_Attrib,
DW_Abbrev_AttribSequenceEnd,
DW_Abbrev_DIEBegin,
DW_Abbrev_DIEEnd,
}
DW_AbbrevKind;
typedef U32 DW_AbbrevFlags;
enum{
DW_AbbrevFlag_HasImplicitConst = (1<<0),
DW_AbbrevFlag_HasChildren = (1<<1),
};
typedef struct DW_Abbrev DW_Abbrev;
struct DW_Abbrev
{
DW_AbbrevKind kind;
Rng1U64 abbrev_range;
U64 sub_kind;
U64 id;
U64 const_value;
DW_AbbrevFlags flags;
};
////////////////////////////////
//~ rjf: Attribs
typedef struct DW_AttribValueResolveParams DW_AttribValueResolveParams;
struct DW_AttribValueResolveParams
{
DW_Version version;
DW_Language language;
U64 addr_size; // NOTE(rjf): size in bytes of containing compilation unit's addresses
U64 containing_unit_info_off; // NOTE(rjf): containing compilation unit's offset into the .debug_info section
U64 debug_addrs_base; // NOTE(rjf): containing compilation unit's offset into the .debug_addrs section (DWARF V5 ONLY)
U64 debug_rnglists_base; // NOTE(rjf): containing compilation unit's offset into the .debug_rnglists section (DWARF V5 ONLY)
U64 debug_str_offs_base; // NOTE(rjf): containing compilation unit's offset into the .debug_str_offsets section (DWARF V5 ONLY)
U64 debug_loclists_base; // NOTE(rjf): containing compilation unit's offset into the .debug_loclists section (DWARF V5 ONLY)
};
typedef struct DW_AttribValue DW_AttribValue;
struct DW_AttribValue
{
DW_SectionKind section;
U64 v[2];
};
typedef struct DW_Attrib DW_Attrib;
struct DW_Attrib
{
U64 info_off;
U64 abbrev_id;
DW_AttribKind attrib_kind;
DW_FormKind form_kind;
DW_AttribClass value_class;
DW_AttribValue form_value;
};
typedef struct DW_AttribArray DW_AttribArray;
struct DW_AttribArray
{
DW_Attrib *v;
U64 count;
};
typedef struct DW_AttribNode DW_AttribNode;
struct DW_AttribNode
{
DW_AttribNode *next;
DW_Attrib attrib;
};
typedef struct DW_AttribList DW_AttribList;
struct DW_AttribList
{
DW_AttribNode *first;
DW_AttribNode *last;
U64 count;
};
typedef struct DW_AttribListParseResult DW_AttribListParseResult;
struct DW_AttribListParseResult
{
DW_AttribList attribs;
U64 max_info_off;
U64 max_abbrev_off;
};
////////////////////////////////
//~ rjf: Compilation Units + Accelerators
typedef struct DW_CompRoot DW_CompRoot;
struct DW_CompRoot
{
// NOTE(rjf): Header Data
U64 size;
DW_CompUnitKind kind;
DW_Version version;
U64 address_size;
U64 abbrev_off;
U64 info_off;
Rng1U64 tags_info_range;
DW_AbbrevTable abbrev_table;
// NOTE(rjf): [parsed from DWARF attributes] Offsets For More Info (DWARF V5 ONLY)
U64 rnglist_base; // NOTE(rjf): Offset into the .debug_rnglists section where this comp unit's data is.
U64 loclist_base; // NOTE(rjf): Offset into the .debug_loclists section where this comp unit's data is.
U64 addrs_base; // NOTE(rjf): Offset into the .debug_addr section where this comp unit's data is.
U64 stroffs_base; // NOTE(rjf): Offset into the .debug_str_offsets section where this comp unit's data is.
// NOTE(rjf): [parsed from DWARF attributes] General Info
String8 name;
String8 producer;
String8 compile_dir;
String8 external_dwo_name;
U64 dwo_id;
DW_Language language;
U64 name_case;
B32 use_utf8;
U64 line_off;
U64 low_pc;
U64 high_pc;
DW_AttribValue ranges_attrib_value;
U64 base_addr;
};
////////////////////////////////
//~ rjf: Tags
typedef struct DW_Tag DW_Tag;
struct DW_Tag
{
DW_Tag *next_sibling;
DW_Tag *first_child;
DW_Tag *last_child;
DW_Tag *parent;
Rng1U64 info_range;
Rng1U64 abbrev_range;
B32 has_children;
U64 abbrev_id;
DW_TagKind kind;
U64 attribs_info_off;
U64 attribs_abbrev_off;
DW_AttribList attribs;
};
typedef U32 DW_TagStubFlags;
enum
{
DW_TagStubFlag_HasObjectPointerArg = (1<<0),
DW_TagStubFlag_HasLocation = (1<<1),
DW_TagStubFlag_HasExternal = (1<<2),
DW_TagStubFlag_HasSpecification = (1<<3),
};
typedef struct DW_TagStub DW_TagStub;
struct DW_TagStub
{
U64 info_off;
DW_TagKind kind;
DW_TagStubFlags flags;
U64 children_info_off;
U64 attribs_info_off;
U64 attribs_abbrev_off;
// NOTE(rjf): DW_Attrib_Specification is tacked onto definitions that
// are filling out more info about a "prototype". That attribute is a reference
// that points back at the declaration tag. The declaration tag has the
// DW_Attrib_Declaration attribute, which is sort of like the reverse
// of that, except there's no reference. So what we're doing here is just storing
// a reference on both, that point back to each other, so it's always easy to
// get from decl => spec, or from spec => decl.
//SYMS_SymbolID ref;
// NOTE(rjf): DW_Attrib_AbstractOrigin is tacked onto some definitions
// that are used to specify information more specific to inlining, while wanting
// to refer to an "abstract" function DIE, that is not specific to any inline
// sites. The DWARF generator will not duplicate information across these, so
// we will occasionally need to look at an abstract origin to get abstract
// information, like name/linkage-name/etc.
//SYMS_SymbolID abstract_origin;
U64 _unused_;
};
typedef struct DW_TagStubNode DW_TagStubNode;
struct DW_TagStubNode
{
DW_TagStubNode *next;
DW_TagStub stub;
};
typedef struct DW_TagStubList DW_TagStubList;
struct DW_TagStubList
{
DW_TagStubNode *first;
DW_TagStubNode *last;
U64 count;
};
////////////////////////////////
//~ rjf: Line Info VM Types
typedef struct DW_LineVMHeader DW_LineVMHeader;
struct DW_LineVMHeader
{
U64 unit_length;
U64 unit_opl;
DW_Version version;
U8 address_size; // Duplicates size from the compilation unit but is needed to support stripped exe that just have .debug_line and .debug_line_str.
U8 segment_selector_size;
U64 header_length;
U64 program_off;
U8 min_inst_len;
U8 max_ops_for_inst;
U8 default_is_stmt;
S8 line_base;
U8 line_range;
U8 opcode_base;
U64 num_opcode_lens;
U8 *opcode_lens;
String8Array dir_table;
DW_LineVMFileArray file_table;
};
typedef struct DW_LineVMState DW_LineVMState;
struct DW_LineVMState
{
U64 address; // Address of a machine instruction.
U32 op_index; // This is used by the VLIW instructions to indicate index of operation inside the instruction.
// Line table doesn't contain full path to a file, instead
// DWARF encodes path as two indices. First index will point into a directory
// table, and second points into a file name table.
U32 file_index;
U32 line;
U32 column;
B32 is_stmt; // Indicates that "address" points to place suitable for a breakpoint.
B32 basic_block; // Indicates that the "address" is inside a basic block.
// Indicates that "address" points to place where function starts.
// Usually prologue is the place where compiler emits instructions to
// prepare stack for a function.
B32 prologue_end;
B32 epilogue_begin; // NOTE(nick): Indicates that "address" points to section where function exits and unwinds stack.
U64 isa; // NOTE(nick): Instruction set that is used.
U64 discriminator; // NOTE(nick): Arbitrary id that indicates to which block these instructions belong.
B32 end_sequence; // NOTE(nick): Indicates that "address" points to the first instruction in the instruction block that follows.
// NOTE(rjf): it looks like LTO might sometimes zero out high PC and low PCs, causing a
// swath of line info to map to a range starting at 0. This causes overlapping ranges
// which we do not want to report. So this B32 will turn on emission.
B32 busted_seq;
};
typedef struct DW_Line DW_Line;
struct DW_Line
{
U64 file_index;
U32 line;
U32 column;
U64 voff;
};
typedef struct DW_LineNode DW_LineNode;
struct DW_LineNode
{
DW_LineNode *next;
DW_Line v;
};
typedef struct DW_LineSeqNode DW_LineSeqNode;
struct DW_LineSeqNode
{
DW_LineSeqNode *next;
U64 count;
DW_LineNode *first;
DW_LineNode *last;
};
typedef struct DW_LineTableParseResult DW_LineTableParseResult;
struct DW_LineTableParseResult
{
U64 seq_count;
DW_LineSeqNode *first_seq;
DW_LineSeqNode *last_seq;
};
////////////////////////////////
//~ rjf: .debug_pubnames and .debug_pubtypes
typedef struct DW_PubStringsBucket DW_PubStringsBucket;
struct DW_PubStringsBucket
{
DW_PubStringsBucket *next;
String8 string;
U64 info_off;
U64 cu_info_off;
};
typedef struct DW_PubStringsTable DW_PubStringsTable;
struct DW_PubStringsTable
{
U64 size;
DW_PubStringsBucket **buckets;
};
////////////////////////////////
//~ rjf: Basic Helpers
internal U64 dw_hash_from_string(String8 string);
////////////////////////////////
//~ Specific Based Range Helpers
#define dw_based_range_read_struct(base, range, offset, out) dw_based_range_read(base, range, offset, sizeof(*out), out)
internal U64 dw_based_range_read(void *base, Rng1U64 range, U64 offset, U64 size, void *out);
internal String8 dw_based_range_read_string(void *base, Rng1U64 range, U64 offset);
internal void* dw_based_range_ptr(void *base, Rng1U64 range, U64 offset);
internal void* dw_based_range_ptr_size(void *base, Rng1U64 range, U64 offset, U64 size);
internal U64 dw_based_range_read_uleb128(void *base, Rng1U64 range, U64 offset, U64 *out_value);
internal U64 dw_based_range_read_sleb128(void *base, Rng1U64 range, U64 offset, S64 *out_value);
internal U64 dw_based_range_read_length(void *base, Rng1U64 range, U64 offset, U64 *out_value);
internal U64 dw_based_range_read_abbrev_tag(void *base, Rng1U64 range, U64 offset, DW_Abbrev *out_abbrev);
internal U64 dw_based_range_read_abbrev_attrib_info(void *base, Rng1U64 range, U64 offset, DW_Abbrev *out_abbrev);
internal U64 dw_based_range_read_attrib_form_value(void *base, Rng1U64 range, U64 offset, DW_Mode mode, U64 address_size, DW_FormKind form_kind, U64 implicit_const, DW_AttribValue *form_value_out);
internal DW_Mode dw_mode_from_sec(DW_SectionArray *sections, DW_SectionKind kind);
internal B32 dw_sec_is_present(DW_SectionArray *sections, DW_SectionKind kind);
internal void* dw_base_from_sec(DW_SectionArray *sections, DW_SectionKind kind);
internal Rng1U64 dw_range_from_sec(DW_SectionArray *sections, DW_SectionKind kind);
////////////////////////////////
//~ rjf: Abbrev Table
internal DW_AbbrevTable dw_make_abbrev_table(Arena *arena, DW_SectionArray *sections, U64 start_abbrev_off);
internal U64 dw_abbrev_offset_from_abbrev_id(DW_AbbrevTable table, U64 abbrev_id);
////////////////////////////////
//~ rjf: Miscellaneous DWARF Section Parsing
//- rjf: .debug_ranges (DWARF V4)
internal Rng1U64List dw_v4_range_list_from_range_offset(Arena *arena, DW_SectionArray *sections, U64 addr_size, U64 comp_unit_base_addr, U64 range_off);
//- rjf: .debug_pubtypes + .debug_pubnames (DWARF V4)
internal DW_PubStringsTable dw_v4_pub_strings_table_from_section_kind(Arena *arena, DW_SectionArray *sections, DW_SectionKind section_kind);
//- rjf: .debug_str_offsets (DWARF V5)
internal U64 dw_v5_offset_from_offs_section_base_index(DW_SectionArray *sections, DW_SectionKind section, U64 base, U64 index);
//- rjf: .debug_addr (DWARF V5)
internal U64 dw_v5_addr_from_addrs_section_base_index(DW_SectionArray *sections, DW_SectionKind section, U64 base, U64 index);
//- rjf: .debug_rnglists parsing (DWARF V5)
internal U64 dw_v5_sec_offset_from_rnglist_or_loclist_section_base_index(DW_SectionArray *sections, DW_SectionKind section_kind, U64 base, U64 index);
internal Rng1U64List dw_v5_range_list_from_rnglist_offset(Arena *arena, DW_SectionArray *sections, DW_SectionKind section, U64 addr_size, U64 addr_section_base, U64 offset);
////////////////////////////////
//~ rjf: Attrib Value Parsing
internal DW_AttribValueResolveParams dw_attrib_value_resolve_params_from_comp_root(DW_CompRoot *root);
internal DW_AttribValue dw_attrib_value_from_form_value(DW_SectionArray *sections, DW_AttribValueResolveParams resolve_params, DW_FormKind form_kind, DW_AttribClass value_class, DW_AttribValue form_value);
internal String8 dw_string_from_attrib_value(DW_SectionArray *sections, DW_AttribValue value);
internal Rng1U64List dw_range_list_from_high_low_pc_and_ranges_attrib_value(Arena *arena, DW_SectionArray *sections, U64 address_size, U64 comp_unit_base_addr, U64 addr_section_base, U64 low_pc, U64 high_pc, DW_AttribValue ranges_value);
////////////////////////////////
//~ rjf: Tag Parsing
internal DW_AttribListParseResult dw_parse_attrib_list_from_info_abbrev_offsets(Arena *arena, DW_SectionArray *sections, DW_Version ver, DW_Ext ext, DW_Language lang, U64 address_size, U64 info_off, U64 abbrev_off, B32 relaxed);
internal DW_Tag* dw_tag_from_info_offset(Arena *arena, DW_SectionArray *sections, DW_AbbrevTable abbrev_table, DW_Version ver, DW_Ext ext, DW_Language lang, U64 address_size, U64 info_offset, B32 relaxed);
internal DW_TagStub dw_stub_from_tag(DW_SectionArray *sections, DW_AttribValueResolveParams resolve_params, DW_Tag *tag);
//- rjf: line info
internal void dw_line_vm_reset(DW_LineVMState *state, B32 default_is_stmt);
internal void dw_line_vm_advance(DW_LineVMState *state, U64 advance, U64 min_inst_len, U64 max_ops_for_inst);
internal DW_LineSeqNode* dw_push_line_seq(Arena* arena, DW_LineTableParseResult *parsed_tbl);
internal DW_LineNode* dw_push_line(Arena *arena, DW_LineTableParseResult *tbl, DW_LineVMState *vm_state, B32 start_of_sequence);
internal DW_LineTableParseResult dw_parsed_line_table_from_comp_root(Arena *arena, DW_SectionArray *sections, DW_CompRoot *root);
internal U64 dw_read_line_file(void *line_base, Rng1U64 line_rng, U64 line_off, DW_Mode mode, DW_SectionArray *sections, DW_AttribValueResolveParams resolve_params, U8 address_size, U64 format_count, Rng1U64 *formats, DW_LineFile *line_file_out);
internal U64 dw_read_line_vm_header(Arena *arena, void *line_base, Rng1U64 line_rng, U64 line_off, DW_Mode mode, DW_SectionArray *sections, DW_AttribValueResolveParams resolve_params, String8 compile_dir, String8 unit_name, DW_LineVMHeader *header_out);
#endif // DWARF_PARSE_H
File diff suppressed because it is too large Load Diff
+224
View File
@@ -0,0 +1,224 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef DWARF_UNWIND_H
#define DWARF_UNWIND_H
typedef struct DW_UnwindResult
{
B32 is_invalid;
B32 missed_read;
U64 missed_read_addr;
U64 stack_pointer;
} DW_UnwindResult;
// EH: Exception Frames
typedef U8 DW_EhPtrEnc;
enum
{
DW_EhPtrEnc_TypeMask = 0x0F,
DW_EhPtrEnc_Ptr = 0x00, // Pointer sized unsigned value
DW_EhPtrEnc_ULEB128 = 0x01, // Unsigned LE base-128 value
DW_EhPtrEnc_UData2 = 0x02, // Unsigned 16-bit value
DW_EhPtrEnc_UData4 = 0x03, // Unsigned 32-bit value
DW_EhPtrEnc_UData8 = 0x04, // Unsigned 64-bit value
DW_EhPtrEnc_Signed = 0x08, // Signed pointer
DW_EhPtrEnc_SLEB128 = 0x09, // Signed LE base-128 value
DW_EhPtrEnc_SData2 = 0x0A, // Signed 16-bit value
DW_EhPtrEnc_SData4 = 0x0B, // Signed 32-bit value
DW_EhPtrEnc_SData8 = 0x0C, // Signed 64-bit value
};
enum
{
DW_EhPtrEnc_ModifyMask = 0x70,
DW_EhPtrEnc_PcRel = 0x10, // Value is relative to the current program counter.
DW_EhPtrEnc_TextRel = 0x20, // Value is relative to the .text section.
DW_EhPtrEnc_DataRel = 0x30, // Value is relative to the .got or .eh_frame_hdr section.
DW_EhPtrEnc_FuncRel = 0x40, // Value is relative to the function.
DW_EhPtrEnc_Aligned = 0x50, // Value is aligned to an address unit sized boundary.
};
enum
{
DW_EhPtrEnc_Indirect = 0x80, // This flag indicates that value is stored in virtual memory.
DW_EhPtrEnc_Omit = 0xFF,
};
typedef struct DW_EhPtrCtx
{
U64 raw_base_vaddr; // address where pointer is being read
U64 text_vaddr; // base address of section with instructions (used for encoding pointer on SH and IA64)
U64 data_vaddr; // base address of data section (used for encoding pointer on x86-64)
U64 func_vaddr; // base address of function where IP is located
} DW_EhPtrCtx;
// CIE: Common Information Entry
typedef struct DW_CIEUnpacked
{
U8 version;
DW_EhPtrEnc lsda_encoding;
DW_EhPtrEnc addr_encoding;
B32 has_augmentation_size;
U64 augmentation_size;
String8 augmentation;
U64 code_align_factor;
S64 data_align_factor;
U64 ret_addr_reg;
U64 handler_ip;
Rng1U64 cfi_range;
} DW_CIEUnpacked;
typedef struct DW_CIEUnpackedNode
{
struct DW_CIEUnpackedNode *next;
DW_CIEUnpacked cie;
U64 offset;
} DW_CIEUnpackedNode;
// FDE: Frame Description Entry
typedef struct DW_FDEUnpacked
{
Rng1U64 ip_voff_range;
U64 lsda_ip;
Rng1U64 cfi_range;
} DW_FDEUnpacked;
// CFI: Call Frame Information
typedef struct DW_CFIRecords
{
B32 valid;
DW_CIEUnpacked cie;
DW_FDEUnpacked fde;
} DW_CFIRecords;
typedef enum DW_CFICFARule{
DW_CFI_CFA_Rule_RegOff,
DW_CFI_CFA_Rule_Expr,
} DW_CFICFARule;
typedef struct DW_CFICFACell
{
DW_CFICFARule rule;
union {
struct {
U64 reg_idx;
S64 offset;
};
Rng1U64 expr;
};
} DW_CFICFACell;
typedef enum DW_CFIRegisterRule
{
DW_CFIRegisterRule_SameValue,
DW_CFIRegisterRule_Undefined,
DW_CFIRegisterRule_Offset,
DW_CFIRegisterRule_ValOffset,
DW_CFIRegisterRule_Register,
DW_CFIRegisterRule_Expression,
DW_CFIRegisterRule_ValExpression,
} DW_CFIRegisterRule;
typedef struct DW_CFICell
{
DW_CFIRegisterRule rule;
union {
S64 n;
Rng1U64 expr;
};
} DW_CFICell;
typedef struct DW_CFIRow
{
struct DW_CFIRow *next;
DW_CFICell *cells;
DW_CFICFACell cfa_cell;
} DW_CFIRow;
typedef struct DW_CFIMachine
{
U64 cells_per_row;
DW_CIEUnpacked *cie;
DW_EhPtrCtx *ptr_ctx;
DW_CFIRow *initial_row;
U64 fde_ip;
} DW_CFIMachine;
typedef U8 DW_CFADecode;
enum
{
DW_CFADecode_Nop = 0x0,
// 1,2,4,8 reserved for literal byte sizes
DW_CFADecode_Address = 0x9,
DW_CFADecode_ULEB128 = 0xA,
DW_CFADecode_SLEB128 = 0xB,
};
typedef U16 DW_CFAControlBits;
enum
{
DW_CFAControlBits_Dec1Mask = 0x00F,
DW_CFAControlBits_Dec2Mask = 0x0F0,
DW_CFAControlBits_IsReg0 = 0x100,
DW_CFAControlBits_IsReg1 = 0x200,
DW_CFAControlBits_IsReg2 = 0x400,
DW_CFAControlBits_NewRow = 0x800,
};
global read_only DW_CFAControlBits dw_unwind__cfa_control_bits_kind1[DW_CFA_OplKind1 + 1];
global read_only DW_CFAControlBits dw_unwind__cfa_control_bits_kind2[DW_CFA_OplKind2 + 1];
// register codes for unwinding match the DW_RegX64 register codes
#define DW_UNWIND_X64__REG_SLOT_COUNT 17
////////////////////////////////
// x64 Unwind Function
internal DW_UnwindResult
dw_unwind_x64(String8 raw_text,
String8 raw_eh_frame,
String8 raw_eh_frame_header,
Rng1U64 text_vrange,
Rng1U64 eh_frame_vrange,
Rng1U64 eh_frame_header_vrange,
U64 default_image_base,
U64 image_base,
U64 stack_pointer,
DW_RegsX64 *regs,
DW_ReadMemorySig *read_memory,
void *read_memory_ud);
internal DW_UnwindResult dw_unwind_x64__apply_frame_rules(String8 raw_eh_frame, DW_CFIRow *row, U64 text_base_vaddr, DW_ReadMemorySig *read_memory, void *read_memory_ud, U64 stack_pointer, DW_RegsX64 *regs);
////////////////////////////////
// x64 Unwind Helper Functions
internal void dw_unwind_init_x64(void);
internal U64 dw_unwind_parse_pointer_x64(void *base, Rng1U64 range, DW_EhPtrCtx *ptr_ctx, DW_EhPtrEnc ptr_enc, U64 off, U64 *ptr_out);
//- eh_frame parsing
internal void dw_unwind_parse_cie_x64(void *base,Rng1U64 range,DW_EhPtrCtx *ptr_ctx, U64 off, DW_CIEUnpacked *cie_out);
internal void dw_unwind_parse_fde_x64(void *base,Rng1U64 range,DW_EhPtrCtx *ptr_ctx, DW_CIEUnpacked *parent_cie, U64 off, DW_FDEUnpacked *fde_out);
internal DW_CFIRecords dw_unwind_eh_frame_cfi_from_ip_slow_x64(String8 raw_eh_frame, DW_EhPtrCtx *ptr_ctx, U64 ip_voff);
internal DW_CFIRecords dw_unwind_eh_frame_hdr_from_ip_fast_x64(String8 raw_eh_frame, String8 raw_eh_frame_hdr, DW_EhPtrCtx *ptr_ctx, U64 ip_voff);
//- cfi machine
internal DW_CFIMachine dw_unwind_make_machine_x64(U64 cells_per_row, DW_CIEUnpacked *cie, DW_EhPtrCtx *ptr_ctx);
internal void dw_unwind_machine_equip_initial_row_x64(DW_CFIMachine *machine, DW_CFIRow *initial_row);
internal void dw_unwind_machine_equip_fde_ip_x64(DW_CFIMachine *machine, U64 fde_ip);
internal DW_CFIRow* dw_unwind_row_alloc_x64(Arena *arena, U64 cells_per_row);
internal void dw_unwind_row_zero_x64(DW_CFIRow *row, U64 cells_per_row);
internal void dw_unwind_row_copy_x64(DW_CFIRow *dst, DW_CFIRow *src, U64 cells_per_row);
internal B32 dw_unwind_machine_run_to_ip_x64(void *base, Rng1U64 range, DW_CFIMachine *machine, U64 target_ip, DW_CFIRow *row_out);
#endif // DWARF_UNWIND_H
+9
View File
@@ -1968,6 +1968,15 @@ rdim_bake_string_map_loose_push_symbol_slice(RDIM_Arena *arena, RDIM_BakeStringM
}
}
RDI_PROC void
rdim_bake_string_map_loose_push_inline_site_slice(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_InlineSite *v, RDI_U64 count)
{
for(RDI_U64 idx = 0; idx < count; idx += 1)
{
rdim_bake_string_map_loose_insert(arena, top, map, 4, v[idx].name);
}
}
RDI_PROC void
rdim_bake_string_map_loose_push_scope_slice(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_Scope *v, RDI_U64 count)
{
+2
View File
@@ -1471,6 +1471,8 @@ RDI_PROC void rdim_bake_string_map_loose_push_unit_slice(RDIM_Arena *arena, RDIM
RDI_PROC void rdim_bake_string_map_loose_push_type_slice(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_Type *v, RDI_U64 count);
RDI_PROC void rdim_bake_string_map_loose_push_udt_slice(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_UDT *v, RDI_U64 count);
RDI_PROC void rdim_bake_string_map_loose_push_symbol_slice(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_Symbol *v, RDI_U64 count);
RDI_PROC void rdim_bake_string_map_loose_push_inline_site_slice(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_InlineSite *v, RDI_U64 count);
RDI_PROC void rdim_bake_string_map_loose_push_scope_slice(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_Scope *v, RDI_U64 count);
//- rjf: list-granularity bake string gathering passes
+6
View File
@@ -63,6 +63,12 @@ u32_array_sort(U64 count, U32 *v)
radsort(v, count, u32_is_before);
}
internal void
u64_array_sort(U64 count, U64 *v)
{
radsort(v, count, u64_is_before);
}
internal void
u32_pair_radix_sort(U64 count, PairU32 *arr)
{
+1
View File
@@ -31,6 +31,7 @@ internal U64Array u64_array_from_list(Arena *arena, U64List *list);
internal U64Array u64_array_remove_duplicates(Arena *arena, U64Array in);
internal void u32_array_sort(U64 count, U32 *v);
internal void u64_array_sort(U64 count, U64 *v);
internal B32 u32_array_compare(U32Array a, U32Array b);
internal U64 sum_array_u64(U64 count, U64 *v);
+25 -190
View File
@@ -1677,7 +1677,7 @@ cv_c13_line_array_from_data(Arena *arena, String8 c13_data, U64 sec_base, CV_C13
{
CV_C13Line line = raw_lines[line_idx];
result.voffs[line_idx] = sec_base + parsed_lines.sec_off_lo + line.off;
result.line_nums[line_idx] = CV_C13LineFlags_ExtractLineNumber(line.flags);
result.line_nums[line_idx] = CV_C13LineFlags_Extract_LineNumber(line.flags);
}
// emit voff ender
@@ -1985,198 +1985,33 @@ cv_c13_parse_inline_binary_annots(Arena *arena,
struct SourceFile *file_last = 0;
U64 file_count = 0;
CV_InlineRangeKind range_kind = 0; (void)range_kind;
U32 code_length = 0;
U32 code_offset = 0;
U32 file_off = inlinee_parsed->file_off;
S32 ln = (S32)inlinee_parsed->first_source_ln;
S32 cn = 1;
U64 code_offset_lo = 0;
B32 code_offset_changed = 0;
B32 code_offset_lo_changed = 0;
B32 code_length_changed = 0;
B32 ln_changed = 1;
B32 file_off_changed = 0;
for (U64 cursor = 0, keep_running = 1; cursor < binary_annots.size && keep_running; ) {
U32 op = CV_InlineBinaryAnnotation_Null;
cursor += cv_decode_inline_annot_u32(binary_annots, cursor, &op);
switch (op) {
case CV_InlineBinaryAnnotation_Null: {
keep_running = 0;
// this is last run, append range with left over code bytes
code_length = code_offset - code_offset_lo;
code_length_changed = 1;
}break;
case CV_InlineBinaryAnnotation_CodeOffset: {
cursor += cv_decode_inline_annot_u32(binary_annots, cursor, &code_offset);
code_offset_changed = 1;
}break;
case CV_InlineBinaryAnnotation_ChangeCodeOffsetBase: {
AssertAlways(!"TODO: test case");
// U32 delta = 0;
// cursor += cv_decode_inline_annot_u32(binary_annots, cursor, &delta);
// code_offset_base = code_offset;
// code_offset_end = code_offset + delta;
// code_offset += delta;
}break;
case CV_InlineBinaryAnnotation_ChangeCodeOffset: {
U32 delta = 0;
cursor += cv_decode_inline_annot_u32(binary_annots, cursor, &delta);
code_offset += delta;
if (!code_offset_lo_changed) {
code_offset_lo = code_offset;
code_offset_lo_changed = 1;
}
code_offset_changed = 1;
}break;
case CV_InlineBinaryAnnotation_ChangeCodeLength: {
code_length = 0;
cursor += cv_decode_inline_annot_u32(binary_annots, cursor, &code_length);
code_length_changed = 1;
}break;
case CV_InlineBinaryAnnotation_ChangeFile: {
U32 old_file_off = file_off;
cursor += cv_decode_inline_annot_u32(binary_annots, cursor, &file_off);
file_off_changed = old_file_off != file_off;
// Compiler isn't obligated to terminate code sequence before chaning files,
// so we have to always force emit code range on file change.
code_length_changed = file_off_changed;
}break;
case CV_InlineBinaryAnnotation_ChangeLineOffset: {
S32 delta = 0;
cursor += cv_decode_inline_annot_s32(binary_annots, cursor, &delta);
ln += delta;
ln_changed = 1;
}break;
case CV_InlineBinaryAnnotation_ChangeLineEndDelta: {
AssertAlways(!"TODO: test case");
// S32 end_delta = 1;
// cursor += cv_decode_inline_annot_s32(binary_annots, cursor, &end_delta);
// ln += end_delta;
}break;
case CV_InlineBinaryAnnotation_ChangeRangeKind: {
AssertAlways(!"TODO: test case");
// cursor += cv_decode_inline_annot_u32(binary_annots, cursor, &range_kind);
}break;
case CV_InlineBinaryAnnotation_ChangeColumnStart: {
AssertAlways(!"TODO: test case");
// S32 delta;
// cursor += cv_decode_inline_annot_s32(binary_annots, cursor, &delta);
// cn += delta;
}break;
case CV_InlineBinaryAnnotation_ChangeColumnEndDelta: {
AssertAlways(!"TODO: test case");
// S32 end_delta;
// cursor += cv_decode_inline_annot_s32(binary_annots, cursor, &end_delta);
// cn += end_delta;
}break;
case CV_InlineBinaryAnnotation_ChangeCodeOffsetAndLineOffset: {
U32 code_offset_and_line_offset = 0;
cursor += cv_decode_inline_annot_u32(binary_annots, cursor, &code_offset_and_line_offset);
S32 line_delta = cv_inline_annot_signed_from_unsigned_operand(code_offset_and_line_offset >> 4);
U32 code_delta = (code_offset_and_line_offset & 0xf);
code_offset += code_delta;
ln += line_delta;
if (!code_offset_lo_changed) {
code_offset_lo = code_offset;
code_offset_lo_changed = 1;
}
code_offset_changed = 1;
ln_changed = 1;
}break;
case CV_InlineBinaryAnnotation_ChangeCodeLengthAndCodeOffset: {
U32 offset_delta = 0;
cursor += cv_decode_inline_annot_u32(binary_annots, cursor, &code_length);
cursor += cv_decode_inline_annot_u32(binary_annots, cursor, &offset_delta);
code_offset += offset_delta;
if (!code_offset_lo_changed) {
code_offset_lo = code_offset;
code_offset_lo_changed = 1;
}
code_offset_changed = 1;
code_length_changed = 1;
}break;
case CV_InlineBinaryAnnotation_ChangeColumnEnd: {
AssertAlways(!"TODO: test case");
// U32 column_end = 0;
// cursor += cv_decode_inline_annot_u32(binary_annots, cursor, &column_end);
}break;
CV_C13InlineSiteDecoder decoder = cv_c13_inline_site_decoder_init(inlinee_parsed->file_off, inlinee_parsed->first_source_ln, parent_voff);
for (;;) {
CV_C13InlineSiteDecoderStep step = cv_c13_inline_site_decoder_step(&decoder, binary_annots);
if (step.flags == 0) {
break;
}
U64 line_code_offset = code_offset;
if (code_length_changed) {
// compute upper bound of the range
U64 code_offset_hi = code_offset + code_length;
// can last code range be extended to cover current sequence too?
if (code_ranges.last != 0 && code_ranges.last->v.max == parent_voff + code_offset_lo) {
code_ranges.last->v.max = parent_voff + code_offset_hi;
} else {
// append range
rng1u64_list_push(arena, &code_ranges, rng_1u64(parent_voff + code_offset_lo, parent_voff + code_offset_hi));
// update last code range in file
if (file_last) {
file_last->last_code_range = code_ranges.last->v;
}
}
// update low offset for next range
code_offset_lo = code_offset_hi;
// advance code offset
code_offset += code_length;
// reset state
code_offset_lo_changed = 0;
code_length_changed = 0;
code_length = 0;
if (step.flags & CV_C13InlineSiteDecoderStepFlag_EmitRange) {
rng1u64_list_push(arena, &code_ranges, step.range);
}
if (file_off_changed || (file_first == 0)) {
// append file
if (step.flags & CV_C13InlineSiteDecoderStepFlag_ExtendLastRange) {
if (code_ranges.last) {
code_ranges.last->v = step.range;
}
}
if (step.flags & CV_C13InlineSiteDecoderStepFlag_EmitFile) {
struct SourceFile *file = push_array(scratch.arena, struct SourceFile, 1);
file->checksum_off = file_off;
file->checksum_off = step.file_off;
SLLQueuePush(file_first, file_last, file);
++file_count;
// update last code range in file
if (code_ranges.last) {
file->last_code_range = code_ranges.last->v;
}
// reset state
file_off_changed = 0;
}
if (code_offset_changed && ln_changed) {
if (file_last->line_last == 0 || file_last->line_last->ln != (U64)ln) {
// append line
struct SourceLine *line = push_array(scratch.arena, struct SourceLine, 1);
line->voff = parent_voff + line_code_offset;
line->ln = (U64)ln;
line->cn = (U64)cn;
SLLQueuePush(file_last->line_first, file_last->line_last, line);
++file_last->line_count;
}
// reset state
code_offset_changed = 0;
ln_changed = 0;
if (step.flags & CV_C13InlineSiteDecoderStepFlag_EmitLine) {
struct SourceLine *line = push_array(scratch.arena, struct SourceLine, 1);
line->voff = step.line_voff;
line->ln = step.ln;
line->cn = step.cn;
SLLQueuePush(file_last->line_first, file_last->line_last, line);
++file_last->line_count;
}
}
@@ -2209,9 +2044,9 @@ cv_c13_parse_inline_binary_annots(Arena *arena,
// fill out result
CV_InlineBinaryAnnotsParsed result = {0};
result.lines_count = file_count;
result.lines = lines;
result.code_ranges = code_ranges;
result.lines_count = file_count;
result.lines = lines;
result.code_ranges = code_ranges;
scratch_end(scratch);
return result;
-16
View File
@@ -3,24 +3,8 @@
#pragma once
////////////////////////////////
// Aligns
#define CV_LeafAlign 4
#define CV_SymbolAlign 1
#define CV_C13SubSectionAlign 4
#define CV_FileCheckSumsAlign 4
////////////////////////////////
//- Symbol and Leaf Headers
#define CV_LeafSize_Max max_U16
typedef U16 CV_LeafSize;
#define CV_SymSize_Max max_U16
typedef U16 CV_SymSize;
typedef struct CV_LeafHeader
{
CV_LeafSize size;
+34
View File
@@ -256,6 +256,19 @@ keys_from_hash_table_u32(Arena *arena, HashTable *ht)
return result;
}
internal U64 *
keys_from_hash_table_u64(Arena *arena, HashTable *ht)
{
U64 *result = push_array_no_zero(arena, U64, ht->count);
for (U64 bucket_idx = 0, cursor = 0; bucket_idx < ht->cap; ++bucket_idx) {
for (BucketNode *n = ht->buckets[bucket_idx].first; n != 0; n = n->next) {
Assert(cursor < ht->count);
result[cursor++] = n->v.key_u64;
}
}
return result;
}
internal KeyValuePair *
key_value_pairs_from_hash_table(Arena *arena, HashTable *ht)
{
@@ -281,3 +294,24 @@ sort_key_value_pairs_as_u64(KeyValuePair *pairs, U64 count)
radsort(pairs, count, key_value_pair_is_before_u64);
}
internal U64Array
remove_duplicates_u64_array(Arena *arena, U64Array arr)
{
Temp scratch = scratch_begin(&arena, 1);
HashTable *ht = hash_table_init(scratch.arena, ((U64)(F64)arr.count * 0.5));
for (U64 i = 0; i < arr.count; ++i) {
KeyValuePair *is_present = hash_table_search_u64(ht, arr.v[i]);
if (!is_present) {
hash_table_push_u64_raw(scratch.arena, ht, arr.v[i], 0);
}
}
U64Array result = {0};
result.count = ht->count;
result.v = keys_from_hash_table_u64(arena, ht);
scratch_end(scratch);
return result;
}
+5
View File
@@ -76,7 +76,12 @@ internal B32 hash_table_search_path_u64(HashTable *ht, String8 key, U64 *value_o
//- key-value helpers
internal U32 * keys_from_hash_table_u32(Arena *arena, HashTable *ht);
internal U64 * keys_from_hash_table_u64(Arena *arena, HashTable *ht);
internal KeyValuePair * key_value_pairs_from_hash_table(Arena *arena, HashTable *ht);
internal void sort_key_value_pairs_as_u32(KeyValuePair *pairs, U64 count);
internal void sort_key_value_pairs_as_u64(KeyValuePair *pairs, U64 count);
////////////////////////////////
internal U64Array remove_duplicates_u64_array(Arena *arena, U64Array arr);
+168 -125
View File
@@ -35,8 +35,12 @@
#include "os/os_inc.h"
#include "path/path.h"
#include "coff/coff.h"
#include "coff/coff_enum.h"
#include "coff/coff_parse.h"
#include "pe/pe.h"
#include "codeview/codeview.h"
#include "codeview/codeview_parse.h"
#include "codeview/codeview_enum.h"
#include "msf/msf.h"
#include "msf/msf_parse.h"
#include "pdb/pdb.h"
@@ -46,8 +50,13 @@
#include "os/os_inc.c"
#include "path/path.c"
#include "coff/coff.c"
#include "coff/coff_enum.c"
#include "coff/coff_parse.c"
#include "pe/pe.c"
#include "codeview/codeview.c"
#include "codeview/codeview_enum.c"
#include "codeview/codeview_parse.c"
#include "msf/msf.c"
#include "msf/msf_parse.c"
#include "pdb/pdb.c"
#include "msvc_crt/msvc_crt.c"
@@ -110,7 +119,6 @@
#include "lnk_config.h"
#include "lnk_chunk.h"
#include "lnk_reloc.h"
#include "lnk_directive.h"
#include "lnk_symbol_table.h"
#include "lnk_section_table.h"
#include "lnk_obj.h"
@@ -128,7 +136,6 @@
#include "lnk_config.c"
#include "lnk_chunk.c"
#include "lnk_reloc.c"
#include "lnk_directive.c"
#include "lnk_symbol_table.c"
#include "lnk_section_table.c"
#include "lnk_obj.c"
@@ -386,8 +393,8 @@ lnk_res_string_id_is_before(void *raw_a, void *raw_b)
{
PE_Resource *a = raw_a;
PE_Resource *b = raw_b;
Assert(a->id.type == COFF_ResourceIDType_STRING);
Assert(b->id.type == COFF_ResourceIDType_STRING);
Assert(a->id.type == COFF_ResourceIDType_String);
Assert(b->id.type == COFF_ResourceIDType_String);
int is_before = str8_is_before_case_sensitive(&a->id.u.string, &b->id.u.string);
return is_before;
}
@@ -397,8 +404,8 @@ lnk_res_number_id_is_before(void *raw_a, void *raw_b)
{
PE_Resource *a = raw_a;
PE_Resource *b = raw_b;
Assert(a->id.type == COFF_ResourceIDType_NUMBER);
Assert(b->id.type == COFF_ResourceIDType_NUMBER);
Assert(a->id.type == COFF_ResourceIDType_Number);
Assert(b->id.type == COFF_ResourceIDType_Number);
int is_before = u16_is_before(&a->id.u.number, &b->id.u.number);
return is_before;
}
@@ -421,7 +428,7 @@ lnk_serialize_pe_resource_tree(LNK_SectionTable *st, LNK_SymbolTable *symtab, PE
dir_data_chunk->sort_idx = str8_lit("c");
PE_Resource root_wrapper = {0};
root_wrapper.id.type = COFF_ResourceIDType_NUMBER;
root_wrapper.id.type = COFF_ResourceIDType_Number;
root_wrapper.id.u.number = 0;
root_wrapper.kind = PE_ResDataKind_DIR;
root_wrapper.u.dir = root_dir;
@@ -455,11 +462,11 @@ lnk_serialize_pe_resource_tree(LNK_SectionTable *st, LNK_SymbolTable *symtab, PE
stack->coff_entry_chunk = lnk_section_push_chunk_data(dir_sect, stack->coff_entry_array_chunk, str8_struct(entry), str8_zero());
switch (res->id.type) {
case COFF_ResourceIDType_NUMBER: {
case COFF_ResourceIDType_Number: {
entry->name.id = res->id.u.number;
} break;
case COFF_ResourceIDType_STRING: {
case COFF_ResourceIDType_String: {
// TODO: we can make string table smaller by reusing offsets for same strings
// not sure why high bit has to be turned on here since number id and string id entries are
@@ -475,7 +482,7 @@ lnk_serialize_pe_resource_tree(LNK_SectionTable *st, LNK_SymbolTable *symtab, PE
lnk_section_push_reloc(dir_sect, stack->coff_entry_chunk, LNK_Reloc_SECT_REL, OffsetOf(COFF_ResourceDirEntry, name.offset), name_symbol);
} break;
case COFF_ResourceIDType_NULL: break;
case COFF_ResourceIDType_Null: break;
default: InvalidPath;
}
@@ -494,14 +501,14 @@ lnk_serialize_pe_resource_tree(LNK_SectionTable *st, LNK_SymbolTable *symtab, PE
// push sub directory chunk layout
LNK_Chunk *dir_node_chunk = lnk_section_push_chunk_list(dir_sect, dir_tree_chunk, str8_zero());
dir_node_chunk->align = COFF_RES_ALIGN;
dir_node_chunk->align = COFF_ResourceAlign;
LNK_Chunk *dir_header_chunk = lnk_section_push_chunk_data(dir_sect, dir_node_chunk, str8_struct(dir_header), str8_zero());
LNK_Chunk *entry_array_chunk = lnk_section_push_chunk_list(dir_sect, dir_node_chunk, str8_zero());
lnk_chunk_set_debugf(dir_sect->arena, dir_header_chunk, "DIR_HEADER_CHUNK");
lnk_chunk_set_debugf(dir_sect->arena, entry_array_chunk, "DIR_ENTRY_ARRAY_CHUNK");
// push symbols to patch coff entry
LNK_Symbol *flag_symbol = lnk_make_defined_symbol_va(symtab->arena->v[0], flag_name, LNK_DefinedSymbolVisibility_Internal, 0, COFF_RESOURCE_SUB_DIR_FLAG);
LNK_Symbol *flag_symbol = lnk_make_defined_symbol_va(symtab->arena->v[0], flag_name, LNK_DefinedSymbolVisibility_Internal, 0, COFF_Resource_SubDirFlag);
LNK_Symbol *offset_symbol = lnk_make_defined_symbol_chunk(symtab->arena->v[0], offset_name, LNK_DefinedSymbolVisibility_Internal, 0, dir_header_chunk, 0, 0, 0);
lnk_symbol_table_push(symtab, flag_symbol); // set high bit to indicate directory
lnk_symbol_table_push(symtab, offset_symbol); // write offset for this directory
@@ -537,8 +544,8 @@ lnk_serialize_pe_resource_tree(LNK_SectionTable *st, LNK_SymbolTable *symtab, PE
LNK_Chunk *resource_data_chunk = lnk_section_push_chunk_data(data_sect, data_sect->root, res->u.coff_res.data, str8_zero());
// windows errors out on unaligned data
coff_resource_data_entry_chunk->align = COFF_RES_ALIGN;
resource_data_chunk->align = COFF_RES_ALIGN;
coff_resource_data_entry_chunk->align = COFF_ResourceAlign;
resource_data_chunk->align = COFF_ResourceAlign;
// relocate data
String8 resource_data_symbol_name = push_str8f(symtab->arena->v[0], "$R%06X", total_res_count);
@@ -720,8 +727,8 @@ lnk_make_res_obj(TP_Context *tp,
COFF_Symbol16 coff_feat00 = {0};
MemoryCopyStr8(&coff_feat00.name, str8_lit("@feat.00"));
coff_feat00.value = MSCRT_FeatFlag_HAS_SAFE_SEH|MSCRT_FeatFlag_UNKNOWN_4;
coff_feat00.section_number = COFF_SYMBOL_ABS_SECTION_16;
coff_feat00.storage_class = COFF_SymStorageClass_STATIC;
coff_feat00.section_number = COFF_Symbol_AbsSection16;
coff_feat00.storage_class = COFF_SymStorageClass_Static;
coff_symbol16_list_push(scratch.arena, &coff_symbol_list, coff_feat00);
// emit coff symbols for section definitions
@@ -744,7 +751,7 @@ lnk_make_res_obj(TP_Context *tp,
coff_sect_symbol.value = 0;
coff_sect_symbol.section_number = sect->isect;
coff_sect_symbol.aux_symbol_count = 1;
coff_sect_symbol.storage_class = COFF_SymStorageClass_STATIC;
coff_sect_symbol.storage_class = COFF_SymStorageClass_Static;
Assert(sect->isect <= max_U16);
COFF_SymbolSecDef secdef = {0};
@@ -765,7 +772,7 @@ lnk_make_res_obj(TP_Context *tp,
LNK_RelocList reloc_list = {0};
LNK_RelocList res_data_reloc_list = {0};
for (LNK_Reloc *reloc = sect->reloc_list.first; reloc != 0; reloc = reloc->next) {
B32 is_reloc_symbol = str8_match(str8_lit("$R"), reloc->symbol->name, StringMatchFlag_RightSideSloppy);
B32 is_reloc_symbol = str8_match_lit("$R", reloc->symbol->name, StringMatchFlag_RightSideSloppy);
LNK_Reloc *dst;
if (is_reloc_symbol) {
dst = lnk_reloc_list_push(sect->arena, &res_data_reloc_list);
@@ -800,7 +807,7 @@ lnk_make_res_obj(TP_Context *tp,
MemoryCopyStr8(&coff_symbol.name, symbol_name);
coff_symbol.value = symbol_offset;
coff_symbol.section_number = symbol_sect->isect;
coff_symbol.storage_class = COFF_SymStorageClass_STATIC;
coff_symbol.storage_class = COFF_SymStorageClass_Static;
coff_symbol16_list_push(scratch.arena, &coff_symbol_list, coff_symbol);
// push coff reloc
@@ -838,7 +845,7 @@ lnk_make_res_obj(TP_Context *tp,
}
}
LNK_Section *misc_sect = lnk_section_table_push(st, str8_lit(".misc"), COFF_SectionFlag_LNK_INFO|COFF_SectionFlag_LNK_REMOVE);
LNK_Section *misc_sect = lnk_section_table_push(st, str8_lit(".misc"), COFF_SectionFlag_LnkInfo|COFF_SectionFlag_LnkRemove);
misc_sect->emit_header = 0;
// serialize coff symbol list
@@ -858,27 +865,27 @@ lnk_make_res_obj(TP_Context *tp,
// build obj header
{
// init header
COFF_Header *coff_header = push_array(header_sect->arena, COFF_Header, 1);
coff_header->machine = machine;
coff_header->section_count = 0; // relocated
coff_header->time_stamp = time_stamp;
coff_header->symbol_table_foff = 0; // relocated
coff_header->symbol_count = 0; // relocated
coff_header->optional_header_size = 0; // no PE header in obj
coff_header->flags = COFF_Flag_32BIT_MACHINE;
COFF_FileHeader *file_header = push_array(header_sect->arena, COFF_FileHeader, 1);
file_header->machine = machine;
file_header->section_count = 0; // relocated
file_header->time_stamp = time_stamp;
file_header->symbol_table_foff = 0; // relocated
file_header->symbol_count = 0; // relocated
file_header->optional_header_size = 0; // no PE header in obj
file_header->flags = COFF_FileHeaderFlag_32BitMachine;
// push coff header chunk
String8 coff_header_data = str8_struct(coff_header);
LNK_Chunk *coff_header_chunk = lnk_section_push_chunk_data(header_sect, header_sect->root, coff_header_data, str8_zero());
String8 file_header_data = str8_struct(file_header);
LNK_Chunk *file_header_chunk = lnk_section_push_chunk_data(header_sect, header_sect->root, file_header_data, str8_zero());
// relocate coff header fields
lnk_section_push_reloc_undefined(header_sect, coff_header_chunk, LNK_Reloc_ADDR_32, OffsetOf(COFF_Header, section_count), str8_lit(LNK_COFF_SECT_HEADER_COUNT_SYMBOL_NAME), LNK_SymbolScopeFlag_Internal);
lnk_section_push_reloc(header_sect, coff_header_chunk, LNK_Reloc_FILE_OFF_32, OffsetOf(COFF_Header, symbol_table_foff), coff_symbol_table_symbol);
lnk_section_push_reloc(header_sect, coff_header_chunk, LNK_Reloc_ADDR_32, OffsetOf(COFF_Header, symbol_count), coff_symbol_count_symbol);
lnk_section_push_reloc_undefined(header_sect, file_header_chunk, LNK_Reloc_ADDR_32, OffsetOf(COFF_FileHeader, section_count), str8_lit(LNK_COFF_SECT_HEADER_COUNT_SYMBOL_NAME), LNK_SymbolScopeFlag_Internal);
lnk_section_push_reloc(header_sect, file_header_chunk, LNK_Reloc_FILE_OFF_32, OffsetOf(COFF_FileHeader, symbol_table_foff), coff_symbol_table_symbol);
lnk_section_push_reloc(header_sect, file_header_chunk, LNK_Reloc_ADDR_32, OffsetOf(COFF_FileHeader, symbol_count), coff_symbol_count_symbol);
// push coff header symbol
LNK_Symbol *coff_header_symbol = lnk_make_defined_symbol_chunk(symtab->arena->v[0], str8_lit(LNK_COFF_HEADER_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, coff_header_chunk, 0, 0, 0);
lnk_symbol_table_push(symtab, coff_header_symbol);
LNK_Symbol *file_header_symbol = lnk_make_defined_symbol_chunk(symtab->arena->v[0], str8_lit(LNK_COFF_FILE_HEADER_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, file_header_chunk, 0, 0, 0);
lnk_symbol_table_push(symtab, file_header_symbol);
}
// build section headers
@@ -918,7 +925,7 @@ lnk_make_res_obj(TP_Context *tp,
}
// patch file fields
if (~sect->flags & COFF_SectionFlag_CNT_UNINITIALIZED_DATA) {
if (~sect->flags & COFF_SectionFlag_CntUninitializedData) {
LNK_Symbol *sect_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScopeFlag_Internal, sect->name);
lnk_section_push_reloc(header_sect, coff_sect_header_chunk, LNK_Reloc_CHUNK_SIZE_FILE_32, OffsetOf(COFF_SectionHeader, fsize), sect_symbol);
lnk_section_push_reloc(header_sect, coff_sect_header_chunk, LNK_Reloc_FILE_OFF_32, OffsetOf(COFF_SectionHeader, foff), sect_symbol);
@@ -1029,13 +1036,13 @@ lnk_make_linker_coff_obj(TP_Context *tp,
header_sect->emit_header = 0;
{
COFF_Header *coff_header = push_array(header_sect->arena, COFF_Header, 1);
coff_header->machine = machine;
coff_header->section_count = 0;
coff_header->time_stamp = time_stamp;
COFF_FileHeader *file_header = push_array(header_sect->arena, COFF_FileHeader, 1);
file_header->machine = machine;
file_header->section_count = 0;
file_header->time_stamp = time_stamp;
LNK_Chunk *coff_header_chunk = lnk_section_push_chunk_raw(header_sect, header_sect->root, coff_header, sizeof(*coff_header), str8_zero());
lnk_section_push_reloc_undefined(header_sect, coff_header_chunk, LNK_Reloc_ADDR_32, OffsetOf(COFF_Header, section_count), str8_lit(LNK_COFF_SECT_HEADER_COUNT_SYMBOL_NAME), LNK_SymbolScopeFlag_Internal);
LNK_Chunk *file_header_chunk = lnk_section_push_chunk_raw(header_sect, header_sect->root, file_header, sizeof(*file_header), str8_zero());
lnk_section_push_reloc_undefined(header_sect, file_header_chunk, LNK_Reloc_ADDR_32, OffsetOf(COFF_FileHeader, section_count), str8_lit(LNK_COFF_SECT_HEADER_COUNT_SYMBOL_NAME), LNK_SymbolScopeFlag_Internal);
}
{
@@ -1134,7 +1141,7 @@ lnk_make_linker_coff_obj(TP_Context *tp,
}
// emit relocs for file fields
if (~sect->flags & COFF_SectionFlag_CNT_UNINITIALIZED_DATA) {
if (~sect->flags & COFF_SectionFlag_CntUninitializedData) {
LNK_Symbol *sect_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScopeFlag_Internal, sect->name);
lnk_section_push_reloc(header_sect, coff_sect_header_chunk, LNK_Reloc_CHUNK_SIZE_FILE_32, OffsetOf(COFF_SectionHeader, fsize), sect_symbol);
lnk_section_push_reloc(header_sect, coff_sect_header_chunk, LNK_Reloc_FILE_OFF_32, OffsetOf(COFF_SectionHeader, foff), sect_symbol);
@@ -1227,12 +1234,13 @@ lnk_push_input_from_lazy(Arena *arena, PathStyle path_style, LNK_LazySymbol *laz
COFF_DataType member_type = coff_data_type_from_data(member_info.data);
switch (member_type) {
case COFF_DataType_IMPORT: {
case COFF_DataType_Null: break;
case COFF_DataType_Import: {
LNK_InputImport *input = lnk_input_import_list_push(arena, input_import_list);
input->import_header = coff_archive_import_from_data(member_info.data);
} break;
case COFF_DataType_BIG_OBJ:
case COFF_DataType_OBJ: {
case COFF_DataType_BigObj:
case COFF_DataType_Obj: {
String8 obj_path = coff_parse_long_name(lazy->lib->long_names, member_info.header.name);
// obj path in thin archive has slash appended which screws up
@@ -1274,12 +1282,12 @@ lnk_push_linker_symbols(LNK_SymbolTable *symtab, COFF_MachineType machine)
// passing it around as a function argument.
//
// 100h: lea rax, [rip + ffffff00h] ; -100h
LNK_Symbol *image_base = lnk_symbol_table_push_defined_chunk(symtab, str8_lit("__ImageBase"), LNK_DefinedSymbolVisibility_Extern, 0, g_null_chunk_ptr, 0, COFF_ComdatSelectType_ANY, 0);
LNK_Symbol *image_base = lnk_symbol_table_push_defined_chunk(symtab, str8_lit("__ImageBase"), LNK_DefinedSymbolVisibility_Extern, 0, g_null_chunk_ptr, 0, COFF_ComdatSelect_Any, 0);
{ // load config symbols
if (machine == COFF_MachineType_X86) {
lnk_symbol_table_push_defined_chunk(symtab, str8_lit(LNK_SAFE_SE_HANDLER_TABLE_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Extern, 0, g_null_chunk_ptr, 0, COFF_ComdatSelectType_NODUPLICATES, 0);
lnk_symbol_table_push_defined_chunk(symtab, str8_lit(LNK_SAFE_SE_HANDLER_COUNT_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Extern, 0, g_null_chunk_ptr, 0, COFF_ComdatSelectType_NODUPLICATES, 0);
if (machine == COFF_Machine_X86) {
lnk_symbol_table_push_defined_chunk(symtab, str8_lit(LNK_SAFE_SE_HANDLER_TABLE_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Extern, 0, g_null_chunk_ptr, 0, COFF_ComdatSelect_NoDuplicates, 0);
lnk_symbol_table_push_defined_chunk(symtab, str8_lit(LNK_SAFE_SE_HANDLER_COUNT_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Extern, 0, g_null_chunk_ptr, 0, COFF_ComdatSelect_NoDuplicates, 0);
}
// TODO: investigate IMAGE_ENCLAVE_CONFIG 32/64
@@ -1404,7 +1412,7 @@ lnk_build_debug_rdi(LNK_SectionTable *st,
{
ProfBeginFunction();
LNK_Section *rdi_sect = lnk_section_table_push(st, str8_lit(".raddbg"), COFF_SectionFlag_CNT_INITIALIZED_DATA|COFF_SectionFlag_MEM_READ);
LNK_Section *rdi_sect = lnk_section_table_push(st, str8_lit(".raddbg"), COFF_SectionFlag_CntInitializedData|COFF_SectionFlag_MemRead);
// push chunks
String8 debug_rdi = pe_make_debug_header_rdi(rdi_sect->arena, guid, rdi_path);
@@ -1483,7 +1491,7 @@ lnk_build_guard_tables(TP_Context *tp,
if (lnk_chunk_is_discarded(chunk)) {
continue;
}
if (~chunk->flags & COFF_SectionFlag_CNT_CODE) {
if (~chunk->flags & COFF_SectionFlag_CntCode) {
continue;
}
Assert(chunk->type == LNK_Chunk_Leaf);
@@ -1503,7 +1511,7 @@ lnk_build_guard_tables(TP_Context *tp,
if (symbol_chunk->type != LNK_Chunk_Leaf) {
continue;
}
if (~symbol_chunk->flags & COFF_SectionFlag_CNT_CODE) {
if (~symbol_chunk->flags & COFF_SectionFlag_CntCode) {
continue;
}
lnk_symbol_list_push(scratch.arena, &guard_symbol_list_table[GUARD_FIDS], symbol);
@@ -1598,7 +1606,7 @@ lnk_build_guard_tables(TP_Context *tp,
}
// TODO: emit table for SEH on X86
if (machine == COFF_MachineType_X86) {
if (machine == COFF_Machine_X86) {
lnk_not_implemented("__safe_se_handler_table");
lnk_not_implemented("__safe_se_handler_count");
}
@@ -1821,11 +1829,20 @@ lnk_base_reloc_page_is_before(void *raw_a, void *raw_b)
return a->voff < b->voff;
}
int
lnk_base_reloc_page_compar(const void *raw_a, const void *raw_b)
{
const LNK_BaseRelocPage *a = raw_a;
const LNK_BaseRelocPage *b = raw_b;
return u64_compar(&a->voff, &b->voff);
}
internal void
lnk_base_reloc_page_array_sort(LNK_BaseRelocPageArray arr)
{
ProfBeginFunction();
radsort(arr.v, arr.count, lnk_base_reloc_page_is_before);
//radsort(arr.v, arr.count, lnk_base_reloc_page_is_before);
qsort(arr.v, arr.count, sizeof(arr.v[0]), lnk_base_reloc_page_compar);
ProfEnd();
}
@@ -1924,7 +1941,7 @@ lnk_build_base_relocs(TP_Context *tp,
ProfBegin("Page List -> Array");
LNK_BaseRelocPageArray page_arr = lnk_base_reloc_page_array_from_list(base_reloc_sect->arena, *main_page_list);
ProfEnd();
ProfBegin("Sort Pages on VOFF");
lnk_base_reloc_page_array_sort(page_arr);
ProfEnd();
@@ -2064,7 +2081,7 @@ internal LNK_Chunk *
lnk_build_coff_file_header(LNK_SymbolTable *symtab, LNK_Section *header_sect, LNK_Chunk *parent,
COFF_MachineType machine, COFF_TimeStamp time_stamp, PE_ImageFileCharacteristics file_characteristics)
{
COFF_Header *file_header = push_array_no_zero(header_sect->arena, COFF_Header, 1);
COFF_FileHeader *file_header = push_array_no_zero(header_sect->arena, COFF_FileHeader, 1);
file_header->machine = machine;
file_header->time_stamp = time_stamp;
file_header->symbol_table_foff = 0;
@@ -2074,16 +2091,16 @@ lnk_build_coff_file_header(LNK_SymbolTable *symtab, LNK_Section *header_sect, LN
file_header->flags = file_characteristics;
LNK_Chunk *file_header_chunk = lnk_section_push_chunk_raw(header_sect, parent, file_header, sizeof(*file_header), str8_zero());
lnk_chunk_set_debugf(header_sect->arena, file_header_chunk, LNK_COFF_HEADER_SYMBOL_NAME);
lnk_chunk_set_debugf(header_sect->arena, file_header_chunk, LNK_COFF_FILE_HEADER_SYMBOL_NAME);
lnk_symbol_table_push_defined_chunk(symtab, str8_lit(LNK_COFF_HEADER_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, file_header_chunk, 0, 0, 0);
lnk_symbol_table_push_defined_chunk(symtab, str8_lit(LNK_COFF_FILE_HEADER_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, file_header_chunk, 0, 0, 0);
// :section_count
lnk_section_push_reloc_undefined(header_sect, file_header_chunk, LNK_Reloc_ADDR_16, OffsetOf(COFF_Header, section_count), str8_lit(LNK_COFF_SECT_HEADER_COUNT_SYMBOL_NAME), LNK_SymbolScopeFlag_Internal);
lnk_section_push_reloc_undefined(header_sect, file_header_chunk, LNK_Reloc_ADDR_16, OffsetOf(COFF_FileHeader, section_count), str8_lit(LNK_COFF_SECT_HEADER_COUNT_SYMBOL_NAME), LNK_SymbolScopeFlag_Internal);
// :optional_header_size
lnk_section_push_reloc_undefined(header_sect, file_header_chunk, LNK_Reloc_CHUNK_SIZE_FILE_16, OffsetOf(COFF_Header, optional_header_size), str8_lit(LNK_PE_OPT_HEADER_SYMBOL_NAME), LNK_SymbolScopeFlag_Internal);
lnk_section_push_reloc_undefined(header_sect, file_header_chunk, LNK_Reloc_CHUNK_SIZE_FILE_16, OffsetOf(COFF_Header, optional_header_size), str8_lit(LNK_PE_DIRECTORY_ARRAY_SYMBOL_NAME), LNK_SymbolScopeFlag_Internal);
lnk_section_push_reloc_undefined(header_sect, file_header_chunk, LNK_Reloc_CHUNK_SIZE_FILE_16, OffsetOf(COFF_FileHeader, optional_header_size), str8_lit(LNK_PE_OPT_HEADER_SYMBOL_NAME), LNK_SymbolScopeFlag_Internal);
lnk_section_push_reloc_undefined(header_sect, file_header_chunk, LNK_Reloc_CHUNK_SIZE_FILE_16, OffsetOf(COFF_FileHeader, optional_header_size), str8_lit(LNK_PE_DIRECTORY_ARRAY_SYMBOL_NAME), LNK_SymbolScopeFlag_Internal);
return file_header_chunk;
}
@@ -2159,17 +2176,17 @@ lnk_build_pe_optional_header_x64(LNK_SymbolTable *symtab,
continue;
}
// :sizeof_uninited_data
if (sect->flags & COFF_SectionFlag_CNT_UNINITIALIZED_DATA) {
if (sect->flags & COFF_SectionFlag_CntUninitializedData) {
lnk_section_push_reloc_undefined(header_sect, opt_header_chunk, LNK_Reloc_CHUNK_SIZE_VIRT_32, OffsetOf(PE_OptionalHeader32Plus, sizeof_uninited_data), sect->name, LNK_SymbolScopeFlag_Internal);
}
// :sizeof_inited_data
if (sect->flags & COFF_SectionFlag_CNT_INITIALIZED_DATA) {
if (sect->flags & COFF_SectionFlag_CntInitializedData) {
lnk_section_push_reloc_undefined(header_sect, opt_header_chunk, LNK_Reloc_CHUNK_SIZE_FILE_32, OffsetOf(PE_OptionalHeader32Plus, sizeof_inited_data), sect->name, LNK_SymbolScopeFlag_Internal);
}
// :sizeof_code
if (sect->flags & COFF_SectionFlag_CNT_CODE) {
if (sect->flags & COFF_SectionFlag_CntCode) {
lnk_section_push_reloc_undefined(header_sect, opt_header_chunk, LNK_Reloc_CHUNK_SIZE_FILE_32, OffsetOf(PE_OptionalHeader32Plus, sizeof_code), sect->name, LNK_SymbolScopeFlag_Internal);
}
@@ -2188,7 +2205,7 @@ lnk_build_pe_optional_header_x64(LNK_SymbolTable *symtab,
lnk_section_push_reloc(header_sect, opt_header_chunk, LNK_Reloc_FILE_ALIGN_32, OffsetOf(PE_OptionalHeader32Plus, sizeof_headers), &g_null_symbol);
// :check_sum
lnk_symbol_table_push_defined_chunk(symtab, str8_lit(LNK_PE_CHECKSUM_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, opt_header_chunk, OffsetOf(PE_OptionalHeader32Plus, check_sum), COFF_ComdatSelectType_NODUPLICATES, 0);
lnk_symbol_table_push_defined_chunk(symtab, str8_lit(LNK_PE_CHECKSUM_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, opt_header_chunk, OffsetOf(PE_OptionalHeader32Plus, check_sum), COFF_ComdatSelect_NoDuplicates, 0);
// :data_dir_count
lnk_section_push_reloc_undefined(header_sect, opt_header_chunk, LNK_Reloc_ADDR_32, OffsetOf(PE_OptionalHeader32Plus, data_dir_count), str8_lit(LNK_PE_DIRECTORY_COUNT_SYMBOL_NAME), LNK_SymbolScopeFlag_Internal);
@@ -2258,11 +2275,11 @@ lnk_build_coff_section_table(LNK_SymbolTable *symtab, LNK_Section *header_sect,
}
// push COFF header array chunk
LNK_Chunk *coff_header_array_chunk = lnk_section_push_chunk_list(header_sect, parent_chunk, str8_zero());
lnk_chunk_set_debugf(header_sect->arena, coff_header_array_chunk, LNK_COFF_SECT_HEADER_ARRAY_SYMBOL_NAME);
LNK_Chunk *COFF_FileHeader_array_chunk = lnk_section_push_chunk_list(header_sect, parent_chunk, str8_zero());
lnk_chunk_set_debugf(header_sect->arena, COFF_FileHeader_array_chunk, LNK_COFF_SECT_HEADER_ARRAY_SYMBOL_NAME);
// define symbol for COFF header array
lnk_symbol_table_push_defined_chunk(symtab, str8_lit(LNK_COFF_SECT_HEADER_ARRAY_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, coff_header_array_chunk, 0, 0, 0);
lnk_symbol_table_push_defined_chunk(symtab, str8_lit(LNK_COFF_SECT_HEADER_ARRAY_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, COFF_FileHeader_array_chunk, 0, 0, 0);
// push headers
for (LNK_Section *sect = &sect_arr.v[0], *sect_opl = sect + sect_arr.count; sect < sect_opl; sect += 1) {
@@ -2272,38 +2289,38 @@ lnk_build_coff_section_table(LNK_SymbolTable *symtab, LNK_Section *header_sect,
if (!sect->has_layout) {
continue;
}
COFF_SectionHeader *coff_header = push_array_no_zero(header_sect->arena, COFF_SectionHeader, 1);
COFF_SectionHeader *COFF_FileHeader = push_array_no_zero(header_sect->arena, COFF_SectionHeader, 1);
// TODO: for objs we can store long name in string table and write here /offset
if (sect->name.size > sizeof(coff_header->name)) {
if (sect->name.size > sizeof(COFF_FileHeader->name)) {
lnk_error(LNK_Warning_LongSectionName, "not enough space in COFF section header to store entire name \"%S\"", sect->name);
}
MemorySet(&coff_header->name[0], 0, sizeof(coff_header->name));
MemoryCopy(&coff_header->name[0], sect->name.str, Min(sect->name.size, sizeof(coff_header->name)));
coff_header->vsize = 0; // :vsize
coff_header->voff = 0; // :voff
coff_header->fsize = 0; // :fsize
coff_header->foff = 0; // :foff
coff_header->relocs_foff = 0; // :relocs_foff
coff_header->lines_foff = 0; // obsolete
coff_header->reloc_count = 0; // :reloc_count
coff_header->line_count = 0; // obsolete
coff_header->flags = sect->flags;
MemorySet(&COFF_FileHeader->name[0], 0, sizeof(COFF_FileHeader->name));
MemoryCopy(&COFF_FileHeader->name[0], sect->name.str, Min(sect->name.size, sizeof(COFF_FileHeader->name)));
COFF_FileHeader->vsize = 0; // :vsize
COFF_FileHeader->voff = 0; // :voff
COFF_FileHeader->fsize = 0; // :fsize
COFF_FileHeader->foff = 0; // :foff
COFF_FileHeader->relocs_foff = 0; // :relocs_foff
COFF_FileHeader->lines_foff = 0; // obsolete
COFF_FileHeader->reloc_count = 0; // :reloc_count
COFF_FileHeader->line_count = 0; // obsolete
COFF_FileHeader->flags = sect->flags;
// push chunk
LNK_Chunk *coff_header_chunk = lnk_section_push_chunk_raw(header_sect, coff_header_array_chunk, coff_header, sizeof(*coff_header), str8_zero());
LNK_Chunk *COFF_FileHeader_chunk = lnk_section_push_chunk_raw(header_sect, COFF_FileHeader_array_chunk, COFF_FileHeader, sizeof(*COFF_FileHeader), str8_zero());
// :vsize
lnk_section_push_reloc_undefined(header_sect, coff_header_chunk, LNK_Reloc_CHUNK_SIZE_VIRT_32, OffsetOf(COFF_SectionHeader, vsize), sect->name, LNK_SymbolScopeFlag_Internal);
lnk_section_push_reloc_undefined(header_sect, COFF_FileHeader_chunk, LNK_Reloc_CHUNK_SIZE_VIRT_32, OffsetOf(COFF_SectionHeader, vsize), sect->name, LNK_SymbolScopeFlag_Internal);
// :voff
lnk_section_push_reloc_undefined(header_sect, coff_header_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(COFF_SectionHeader, voff), sect->name, LNK_SymbolScopeFlag_Internal);
lnk_section_push_reloc_undefined(header_sect, COFF_FileHeader_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(COFF_SectionHeader, voff), sect->name, LNK_SymbolScopeFlag_Internal);
if (~sect->flags & COFF_SectionFlag_CNT_UNINITIALIZED_DATA) {
if (~sect->flags & COFF_SectionFlag_CntUninitializedData) {
// :fsize
lnk_section_push_reloc_undefined(header_sect, coff_header_chunk, LNK_Reloc_CHUNK_SIZE_FILE_32, OffsetOf(COFF_SectionHeader, fsize), sect->name, LNK_SymbolScopeFlag_Internal);
lnk_section_push_reloc_undefined(header_sect, COFF_FileHeader_chunk, LNK_Reloc_CHUNK_SIZE_FILE_32, OffsetOf(COFF_SectionHeader, fsize), sect->name, LNK_SymbolScopeFlag_Internal);
// :foff
lnk_section_push_reloc_undefined(header_sect, coff_header_chunk, LNK_Reloc_FILE_OFF_32, OffsetOf(COFF_SectionHeader, foff), sect->name, LNK_SymbolScopeFlag_Internal);
lnk_section_push_reloc_undefined(header_sect, COFF_FileHeader_chunk, LNK_Reloc_FILE_OFF_32, OffsetOf(COFF_SectionHeader, foff), sect->name, LNK_SymbolScopeFlag_Internal);
}
// TODO: :reloc_off
@@ -2311,10 +2328,10 @@ lnk_build_coff_section_table(LNK_SymbolTable *symtab, LNK_Section *header_sect,
}
// push symbol for section header count
U64 header_count = coff_header_array_chunk->u.list->count;
U64 header_count = COFF_FileHeader_array_chunk->u.list->count;
lnk_symbol_table_push_defined_va(symtab, str8_lit(LNK_COFF_SECT_HEADER_COUNT_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, header_count);
return coff_header_array_chunk;
return COFF_FileHeader_array_chunk;
}
internal LNK_Chunk *
@@ -2357,7 +2374,7 @@ lnk_build_win32_image_header(LNK_SymbolTable *symtab,
lnk_build_pe_magic(symtab, header_sect, pe_magic_chunk);
lnk_build_coff_file_header(symtab, header_sect, coff_file_header_chunk, config->machine, config->time_stamp, config->file_characteristics);
switch (config->machine) {
case COFF_MachineType_X64: {
case COFF_Machine_X64: {
lnk_build_pe_optional_header_x64(symtab,
header_sect,
pe_optional_chunk,
@@ -2441,16 +2458,16 @@ THREAD_POOL_TASK_FUNC(lnk_weak_symbol_finder)
LNK_Symbol *lazy = 0;
switch (weak->lookup_type) {
case COFF_WeakExtType_NOLIBRARY: {
case COFF_WeakExt_NoLibrary: {
// NOLIBRARY means weak symbol should be resolved in case where strong definition pulls in lib member.
} break;
case COFF_WeakExtType_SEARCH_LIBRARY: {
case COFF_WeakExt_SearchLibrary: {
lazy = lnk_symbol_table_search(task->symtab, LNK_SymbolScopeFlag_Lib, symbol->name);
} break;
case COFF_WeakExtType_SEARCH_ALIAS: {
case COFF_WeakExt_SearchAlias: {
lazy = lnk_symbol_table_search(task->symtab, LNK_SymbolScopeFlag_Lib, symbol->name);
if (!lazy) {
if (str8_match(str8_lit(".weak."), symbol->name, StringMatchFlag_RightSideSloppy)) {
if (str8_match_lit(".weak.", symbol->name, StringMatchFlag_RightSideSloppy)) {
// TODO: Clang and MingGW encode extra info in alias
//
// __attribute__((weak,alias("foo"))) void bar(void);
@@ -2890,7 +2907,7 @@ lnk_init_merge_directive_list(Arena *arena, LNK_ObjList obj_list)
// collect merge directives from objs
for (LNK_ObjNode *obj_node = obj_list.first; obj_node != 0; obj_node = obj_node->next) {
LNK_Obj *obj = &obj_node->data;
for (LNK_Directive *dir = obj->directive_info.v[LNK_Directive_Merge].first; dir != 0; dir = dir->next) {
for (LNK_Directive *dir = obj->directive_info.v[LNK_CmdSwitch_Merge].first; dir != 0; dir = dir->next) {
for (String8Node *value_node = dir->value_list.first; value_node != 0; value_node = value_node->next) {
LNK_MergeDirective merge_dir;
if (lnk_parse_merge_directive(value_node->string, &merge_dir)) { lnk_merge_directive_list_push(arena, &result, merge_dir);
@@ -2950,9 +2967,9 @@ lnk_log_size_breakdown(LNK_SectionTable *st, LNK_SymbolTable *symtab)
LNK_Section *sect = &sect_node->data;
if (sect->has_layout) {
U64 sect_size = lnk_file_size_from_chunk_ref(sect_id_map, sect->root->ref);
if (sect->flags & COFF_SectionFlag_CNT_CODE) {
if (sect->flags & COFF_SectionFlag_CntCode) {
code_size += sect_size;
} else if (sect->flags & COFF_SectionFlag_CNT_INITIALIZED_DATA) {
} else if (sect->flags & COFF_SectionFlag_CntInitializedData) {
data_size += sect_size;
}
}
@@ -2960,21 +2977,21 @@ lnk_log_size_breakdown(LNK_SectionTable *st, LNK_SymbolTable *symtab)
LNK_Symbol *dos_header_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScopeFlag_Internal, str8_lit(LNK_DOS_HEADER_SYMBOL_NAME));
LNK_Symbol *dos_program_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScopeFlag_Internal, str8_lit(LNK_DOS_PROGRAM_SYMBOL_NAME));
LNK_Symbol *coff_header_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScopeFlag_Internal, str8_lit(LNK_COFF_HEADER_SYMBOL_NAME));
LNK_Symbol *COFF_FileHeader_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScopeFlag_Internal, str8_lit(LNK_COFF_FILE_HEADER_SYMBOL_NAME));
LNK_Symbol *coff_section_header_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScopeFlag_Internal, str8_lit(LNK_COFF_SECT_HEADER_ARRAY_SYMBOL_NAME));
LNK_Symbol *pe_opt_header_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScopeFlag_Internal, str8_lit(LNK_PE_OPT_HEADER_SYMBOL_NAME));
LNK_Symbol *pe_directories_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScopeFlag_Internal, str8_lit(LNK_PE_DIRECTORY_ARRAY_SYMBOL_NAME));
LNK_Chunk *dos_header_chunk = dos_header_symbol->u.defined.u.chunk;
LNK_Chunk *dos_program_chunk = dos_program_symbol->u.defined.u.chunk;
LNK_Chunk *coff_header_chunk = coff_header_symbol->u.defined.u.chunk;
LNK_Chunk *COFF_FileHeader_chunk = COFF_FileHeader_symbol->u.defined.u.chunk;
LNK_Chunk *coff_section_header_chunk = coff_section_header_symbol->u.defined.u.chunk;
LNK_Chunk *pe_opt_header_chunk = pe_opt_header_symbol->u.defined.u.chunk;
LNK_Chunk *pe_directories_chunk = pe_directories_symbol->u.defined.u.chunk;
U64 dos_header_size = lnk_file_size_from_chunk_ref(sect_id_map, dos_header_chunk->ref);
U64 dos_program_size = lnk_file_size_from_chunk_ref(sect_id_map, dos_program_chunk->ref);
U64 coff_header_size = lnk_file_size_from_chunk_ref(sect_id_map, coff_header_chunk->ref);
U64 COFF_FileHeader_size = lnk_file_size_from_chunk_ref(sect_id_map, COFF_FileHeader_chunk->ref);
U64 coff_section_header_size = lnk_file_size_from_chunk_ref(sect_id_map, coff_section_header_chunk->ref);
U64 pe_opt_header_size = lnk_file_size_from_chunk_ref(sect_id_map, pe_opt_header_chunk->ref);
U64 pe_directories_size = lnk_file_size_from_chunk_ref(sect_id_map, pe_directories_chunk->ref);
@@ -2983,7 +3000,7 @@ lnk_log_size_breakdown(LNK_SectionTable *st, LNK_SymbolTable *symtab)
str8_list_pushf(scratch.arena, &output_list, "--- Image Size Breakdown -------------------------------------------------------");
str8_list_pushf(scratch.arena, &output_list, " DOS Header: %M", dos_header_size);
str8_list_pushf(scratch.arena, &output_list, " DOS Program Stub: %M", dos_program_size);
str8_list_pushf(scratch.arena, &output_list, " COFF Header: %M", coff_header_size);
str8_list_pushf(scratch.arena, &output_list, " COFF Header: %M", COFF_FileHeader_size);
str8_list_pushf(scratch.arena, &output_list, " COFF Section Headers: %M", coff_section_header_size);
str8_list_pushf(scratch.arena, &output_list, " PE Header: %M", pe_opt_header_size);
str8_list_pushf(scratch.arena, &output_list, " Directories: %M", pe_directories_size);
@@ -3173,7 +3190,7 @@ lnk_run(int argc, char **argv)
LNK_Config *config = lnk_build_config(scratch.arena, argc, argv);
TP_Context *tp = tp_alloc(scratch.arena, config->worker_count);
TP_Context *tp = tp_alloc(scratch.arena, config->worker_count, config->max_worker_count, config->shared_thread_pool_name);
TP_Arena *tp_arena = tp_arena_alloc(tp);
#if PROFILE_TELEMETRY
@@ -3335,13 +3352,13 @@ lnk_run(int argc, char **argv)
// redirect user entry to appropriate CRT entry
if (entry_point_symbol) {
config->entry_point_name = entry_point_symbol->name;
if (str8_match(config->entry_point_name, str8_lit("wmain"), 0)) {
if (str8_match_lit("wmain", config->entry_point_name, 0)) {
config->entry_point_name = str8_lit("wmainCRTStartup");
} else if (str8_match(config->entry_point_name, str8_lit("main"), 0)) {
} else if (str8_match_lit("main", config->entry_point_name, 0)) {
config->entry_point_name = str8_lit("mainCRTStartup");
} else if (str8_match(config->entry_point_name, str8_lit("WinMain"), 0)) {
} else if (str8_match_lit("WinMain", config->entry_point_name, 0)) {
config->entry_point_name = str8_lit("WinMainCRTStartup");
} else if (str8_match(config->entry_point_name, str8_lit("wWinMain"), 0)) {
} else if (str8_match_lit("wWinMain", config->entry_point_name, 0)) {
config->entry_point_name = str8_lit("wWinMainCRTStartup");
}
}
@@ -3389,8 +3406,8 @@ lnk_run(int argc, char **argv)
String8 delay_helper_name = str8_zero();
switch (config->machine) {
case COFF_MachineType_X86: delay_helper_name = str8_cstring(LNK_DELAY_LOAD_HELPER2_X86_SYMBOL_NAME); break;
case COFF_MachineType_X64: delay_helper_name = str8_cstring(LNK_DELAY_LOAD_HELPER2_SYMBOL_NAME); break;
case COFF_Machine_X86: delay_helper_name = str8_cstring(LNK_DELAY_LOAD_HELPER2_X86_SYMBOL_NAME); break;
case COFF_Machine_X64: delay_helper_name = str8_cstring(LNK_DELAY_LOAD_HELPER2_SYMBOL_NAME); break;
default: NotImplemented;
}
@@ -3424,7 +3441,7 @@ lnk_run(int argc, char **argv)
for (String8Node *from_node = alt_name_list.from_list.first, *to_node = alt_name_list.to_list.first;
from_node != 0;
from_node = from_node->next, to_node = to_node->next) {
LNK_Symbol *weak = lnk_symbol_table_push_weak(symtab, from_node->string, COFF_WeakExtType_SEARCH_ALIAS, to_node->string);
LNK_Symbol *weak = lnk_symbol_table_push_weak(symtab, from_node->string, COFF_WeakExt_SearchAlias, to_node->string);
lnk_symbol_list_push(scratch.arena, &input_weak_list, weak);
}
ProfEnd();
@@ -3444,12 +3461,12 @@ lnk_run(int argc, char **argv)
case State_InputImports: {
ProfBegin("Input Imports");
for (LNK_InputImport *input = input_import_list.first; input != 0; input = input->next) {
COFF_ImportHeader *import_header = &input->import_header;
COFF_ParsedArchiveImportHeader *import_header = &input->import_header;
KeyValuePair *is_delayed = hash_table_search_path(delay_load_dll_ht, import_header->dll_name);
if (is_delayed) {
if (!imptab_delayed) {
Assert(config->machine != COFF_MachineType_UNKNOWN);
Assert(config->machine != COFF_Machine_Unknown);
B32 is_unloadable = !!(config->flags & LNK_ConfigFlag_DelayUnload);
B32 is_bindable = !!(config->flags & LNK_ConfigFlag_DelayBind);
imptab_delayed = lnk_import_table_alloc_delayed(st, symtab, config->machine, is_unloadable, is_bindable);
@@ -3464,7 +3481,7 @@ lnk_run(int argc, char **argv)
}
} else {
if (!imptab_static) {
Assert(config->machine != COFF_MachineType_UNKNOWN);
Assert(config->machine != COFF_Machine_Unknown);
imptab_static = lnk_import_table_alloc_static(st, symtab, config->machine);
}
LNK_ImportDLL *dll = lnk_import_table_search_dll(imptab_static, import_header->dll_name);
@@ -3546,12 +3563,14 @@ lnk_run(int argc, char **argv)
LNK_Obj *obj = &obj_node_arr.v[obj_idx].data;
// derive machine from obj
if (config->machine == COFF_MachineType_UNKNOWN) {
if (config->machine == COFF_Machine_Unknown) {
config->machine = obj->machine;
} else if (config->machine != COFF_Machine_X64) {
lnk_error_with_loc(LNK_Error_UnsupportedMachine, obj->path, obj->lib_path, "%S machine is supported", coff_string_from_machine_type(obj->machine));
} else {
// is obj machine compatible?
if (config->machine != obj->machine &&
obj->machine != COFF_MachineType_UNKNOWN) { // obj with unknown machine type is compatible with any other machine type
obj->machine != COFF_Machine_Unknown) { // obj with unknown machine type is compatible with any other machine type
lnk_error_obj(LNK_Error_IncompatibleObj, obj,
"conflicting machine types expected %S but got %S",
coff_string_from_machine_type(config->machine),
@@ -3564,11 +3583,26 @@ lnk_run(int argc, char **argv)
ProfBegin("Collect Directives");
for (U64 i = 0; i < obj_node_arr.count; ++i) {
LNK_Obj *obj = &obj_node_arr.v[i].data;
str8_list_concat_in_place(&include_symbol_list, &obj->include_symbol_list);
lnk_alt_name_list_concat_in_place(&alt_name_list, &obj->alt_name_list);
for (LNK_Directive *dir = obj->directive_info.v[LNK_Directive_DisallowLib].first; dir != 0; dir = dir->next) {
for (LNK_Directive *dir = obj->directive_info.v[LNK_CmdSwitch_DisallowLib].first; dir != 0; dir = dir->next) {
str8_list_concat_in_place(&input_disallow_lib_list, &dir->value_list);
}
for (LNK_Directive *dir = obj->directive_info.v[LNK_CmdSwitch_Entry].first; dir != 0; dir = dir->next) {
lnk_apply_cmd_option_to_config(scratch.arena, config, dir->id, dir->value_list, obj->path, obj->lib_path);
}
for (LNK_Directive *dir = obj->directive_info.v[LNK_CmdSwitch_SubSystem].first; dir != 0; dir = dir->next) {
lnk_apply_cmd_option_to_config(scratch.arena, config, dir->id, dir->value_list, obj->path, obj->lib_path);
}
for (LNK_Directive *dir = obj->directive_info.v[LNK_CmdSwitch_Stack].first; dir != 0; dir = dir->next) {
lnk_apply_cmd_option_to_config(scratch.arena, config, dir->id, dir->value_list, obj->path, obj->lib_path);
}
}
ProfEnd();
@@ -3614,7 +3648,7 @@ lnk_run(int argc, char **argv)
}
for (U64 input_source = 0; input_source < ArrayCount(input_libs); ++input_source) {
ProfBeginV("Source %S", lnk_string_from_input_source(input_source));
ProfBeginV("Input Source %S", lnk_string_from_input_source(input_source));
Temp temp = temp_begin(scratch.arena);
LNK_InputLibList input_lib_list = input_libs[input_source];
@@ -3696,6 +3730,7 @@ lnk_run(int argc, char **argv)
}
temp_end(temp);
ProfEnd();
}
// reset input libs
@@ -3881,8 +3916,16 @@ lnk_run(int argc, char **argv)
} break;
case State_BuildExportTable: {
ProfBegin("Build Export Table");
// push exports from command line
for (LNK_ExportParse *exp_parse = config->export_symbol_list.first; exp_parse != 0; exp_parse = exp_parse->next) {
lnk_export_table_push_export(exptab, symtab, exp_parse);
}
// push exports from obj directives
lnk_collect_exports_from_obj_directives(exptab, obj_list, symtab);
// build export table section
lnk_build_edata(exptab, st, symtab, config->image_name, config->machine);
ProfEnd();
@@ -3949,18 +3992,18 @@ lnk_run(int argc, char **argv)
if (pdata_symbol) {
String8 pdata = lnk_data_from_chunk_ref_no_pad(sect_id_map, image_data, pdata_symbol->u.defined.u.chunk->ref);
switch (config->machine) {
case COFF_MachineType_X86:
case COFF_MachineType_X64: {
case COFF_Machine_X86:
case COFF_Machine_X64: {
U64 count = pdata.size / sizeof(PE_IntelPdata);
radsort((PE_IntelPdata *)pdata.str, count, lnk_pdata_is_before_x8664);
} break;
case COFF_MachineType_ARM64:
case COFF_MachineType_ARM: {
case COFF_Machine_Arm64:
case COFF_Machine_Arm: {
AssertAlways(!"TOOD: ARM");
} break;
case COFF_MachineType_MIPSFPU:
case COFF_MachineType_MIPS16:
case COFF_MachineType_MIPSFPU16: {
case COFF_Machine_MipsFpu:
case COFF_Machine_Mips16:
case COFF_Machine_MipsFpu16: {
AssertAlways(!"TODO: MIPS");
} break;
}
+8 -8
View File
@@ -49,7 +49,7 @@
#define LNK_DOS_HEADER_SYMBOL_NAME "DOS_HEADER"
#define LNK_DOS_PROGRAM_SYMBOL_NAME "DOS_PROGRAM"
#define LNK_PE_MAGIC_SYMBOL_NAME "PE_MAGIC"
#define LNK_COFF_HEADER_SYMBOL_NAME "COFF_HEADER"
#define LNK_COFF_FILE_HEADER_SYMBOL_NAME "COFF_FILE_HEADER"
#define LNK_PE_DIRECTORY_ARRAY_SYMBOL_NAME "PE_DIRECTORY_ARRAY"
#define LNK_PE_DIRECTORY_COUNT_SYMBOL_NAME "PE_DIRECTORY_COUNT"
#define LNK_PE_OPT_HEADER_SYMBOL_NAME "PE_OPTIONAL_HEADER"
@@ -82,10 +82,10 @@
#define LNK_DELAY_LOAD_HELPER2_SYMBOL_NAME "__delayLoadHelper2"
#define LNK_DELAY_LOAD_HELPER2_X86_SYMBOL_NAME "___delayLoadHelper2@8"
#define LNK_TEXT_SECTION_FLAGS (COFF_SectionFlag_CNT_CODE|COFF_SectionFlag_MEM_EXECUTE|COFF_SectionFlag_MEM_READ)
#define LNK_DATA_SECTION_FLAGS (COFF_SectionFlag_CNT_INITIALIZED_DATA|COFF_SectionFlag_MEM_READ|COFF_SectionFlag_MEM_WRITE)
#define LNK_RDATA_SECTION_FLAGS (COFF_SectionFlag_CNT_INITIALIZED_DATA|COFF_SectionFlag_MEM_READ)
#define LNK_BSS_SECTION_FLAGS (COFF_SectionFlag_CNT_UNINITIALIZED_DATA|COFF_SectionFlag_MEM_READ|COFF_SectionFlag_MEM_WRITE)
#define LNK_TEXT_SECTION_FLAGS (COFF_SectionFlag_CntCode|COFF_SectionFlag_MemExecute|COFF_SectionFlag_MemRead)
#define LNK_DATA_SECTION_FLAGS (COFF_SectionFlag_CntInitializedData|COFF_SectionFlag_MemRead|COFF_SectionFlag_MemWrite)
#define LNK_RDATA_SECTION_FLAGS (COFF_SectionFlag_CntInitializedData|COFF_SectionFlag_MemRead)
#define LNK_BSS_SECTION_FLAGS (COFF_SectionFlag_CntUninitializedData|COFF_SectionFlag_MemRead|COFF_SectionFlag_MemWrite)
#define LNK_IDATA_SECTION_FLAGS LNK_DATA_SECTION_FLAGS
#define LNK_DEBUG_DIR_SECTION_FLAGS LNK_DATA_SECTION_FLAGS
#define LNK_RSRC_SECTION_FLAGS LNK_DATA_SECTION_FLAGS
@@ -96,8 +96,8 @@
#define LNK_GIATS_SECTION_FLAGS LNK_RDATA_SECTION_FLAGS
#define LNK_GLJMP_SECTION_FLAGS LNK_RDATA_SECTION_FLAGS
#define LNK_GEHCONT_SECTION_FLAGS LNK_RDATA_SECTION_FLAGS
#define LNK_RELOC_SECTION_FLAGS (LNK_RDATA_SECTION_FLAGS | COFF_SectionFlag_MEM_DISCARDABLE)
#define LNK_DEBUG_SECTION_FLAGS (LNK_RDATA_SECTION_FLAGS | COFF_SectionFlag_MEM_DISCARDABLE)
#define LNK_RELOC_SECTION_FLAGS (LNK_RDATA_SECTION_FLAGS | COFF_SectionFlag_MemDiscardable)
#define LNK_DEBUG_SECTION_FLAGS (LNK_RDATA_SECTION_FLAGS | COFF_SectionFlag_MemDiscardable)
////////////////////////////////
@@ -114,7 +114,7 @@ typedef String8List LNK_InputLibList;
typedef struct LNK_InputImport
{
COFF_ImportHeader import_header;
COFF_ParsedArchiveImportHeader import_header;
struct LNK_InputImport *next;
} LNK_InputImport;
+10 -3
View File
@@ -302,13 +302,20 @@ lnk_merge_chunks(Arena *arena, LNK_ChunkManager *dst_cman, LNK_Chunk *dst, LNK_C
return src_node;
}
internal
LNK_CHUNK_VISITOR_SIG(lnk_set_associate_on_chunks)
{
chunk->associate = (LNK_Chunk *)ud;
return 0;
}
internal void
lnk_chunk_associate(Arena *arena, LNK_Chunk *head, LNK_Chunk *chunk)
lnk_chunk_associate(LNK_Chunk *head, LNK_Chunk *chunk)
{
// for simplicity we don't support multiple associations,
// but it's possible to craft symbol table with multiple associations
Assert(!chunk->associate);
chunk->associate = head;
AssertAlways(!chunk->associate);
lnk_visit_chunks(0, chunk, lnk_set_associate_on_chunks, head);
}
internal B32
+1 -1
View File
@@ -175,7 +175,7 @@ internal LNK_Chunk * lnk_chunk_push_leaf(Arena *arena, LNK_ChunkManager *
internal LNK_Chunk * lnk_chunk_push_list(Arena *arena, LNK_ChunkManager *cman, LNK_Chunk *parent, String8 sort_index);
internal LNK_ChunkNode * lnk_chunk_deep_copy(Arena *arena, LNK_Chunk *chunk);
internal LNK_ChunkNode * lnk_merge_chunks(Arena *arena, LNK_ChunkManager *dst_cman, LNK_Chunk *dst, LNK_Chunk *src, U64 *id_map_out, U64 id_map_max);
internal void lnk_chunk_associate(Arena *arena, LNK_Chunk *head, LNK_Chunk *associate);
internal void lnk_chunk_associate(LNK_Chunk *head, LNK_Chunk *associate);
internal B32 lnk_chunk_is_discarded(LNK_Chunk *chunk);
internal U64 lnk_chunk_get_size(LNK_Chunk *chunk);
internal U64 lnk_chunk_list_get_node_count(LNK_Chunk *chunk);
+3 -3
View File
@@ -135,8 +135,8 @@ lnk_cmd_line_parse_windows_rules(Arena *arena, String8List arg_list)
for (String8Node *arg_node = arg_list.first; arg_node != 0; arg_node = arg_node->next) {
String8 arg = arg_node->string;
B32 is_option = str8_match(str8_lit("/"), arg, StringMatchFlag_RightSideSloppy) ||
str8_match(str8_lit("-"), arg, StringMatchFlag_RightSideSloppy);
B32 is_option = str8_match_lit("/", arg, StringMatchFlag_RightSideSloppy) ||
str8_match_lit("-", arg, StringMatchFlag_RightSideSloppy);
if (is_option) {
U64 param_start_pos = str8_find_needle(arg, 0, str8_lit(":"), 0);
String8 option_name = str8_chop(arg, arg.size - param_start_pos);
@@ -195,7 +195,7 @@ lnk_unwrap_rsp(Arena *arena, String8List arg_list)
String8List result = {0};
for (String8Node *curr = arg_list.first; curr != 0; curr = curr->next) {
B32 is_rsp = str8_match(str8_lit("@"), curr->string, StringMatchFlag_RightSideSloppy);
B32 is_rsp = str8_match_lit("@", curr->string, StringMatchFlag_RightSideSloppy);
if (is_rsp) {
// remove "@"
String8 name = str8_skip(curr->string, 1);
+1180 -1050
View File
File diff suppressed because it is too large Load Diff
+86 -28
View File
@@ -7,7 +7,6 @@ typedef enum
{
LNK_CmdSwitch_Null,
LNK_CmdSwitch_NotImplemented,
LNK_CmdSwitch_Deprecated,
LNK_CmdSwitch_Align,
LNK_CmdSwitch_AllowBind,
@@ -21,7 +20,9 @@ typedef enum
LNK_CmdSwitch_DelayLoad,
LNK_CmdSwitch_Dll,
LNK_CmdSwitch_DynamicBase,
LNK_CmdSwitch_Dump,
LNK_CmdSwitch_Entry,
LNK_CmdSwitch_Export,
LNK_CmdSwitch_FastFail,
LNK_CmdSwitch_FileAlign,
LNK_CmdSwitch_Fixed,
@@ -33,6 +34,7 @@ typedef enum
LNK_CmdSwitch_Include,
LNK_CmdSwitch_Incremental,
LNK_CmdSwitch_LargeAddressAware,
LNK_CmdSwitch_Lib,
LNK_CmdSwitch_LibPath,
LNK_CmdSwitch_Machine,
LNK_CmdSwitch_Manifest,
@@ -40,6 +42,7 @@ typedef enum
LNK_CmdSwitch_ManifestFile,
LNK_CmdSwitch_ManifestInput,
LNK_CmdSwitch_ManifestUac,
LNK_CmdSwitch_Merge,
LNK_CmdSwitch_Natvis,
LNK_CmdSwitch_NoDefaultLib,
LNK_CmdSwitch_NoExp,
@@ -73,18 +76,22 @@ typedef enum
LNK_CmdSwitch_DependentLoadFlag,
LNK_CmdSwitch_Driver,
LNK_CmdSwitch_DisallowLib,
LNK_CmdSwitch_EditAndContinue,
LNK_CmdSwitch_EmitVolatileMetadata,
LNK_CmdSwitch_ErrorReport,
LNK_CmdSwitch_Export,
LNK_CmdSwitch_ExportAdmin,
LNK_CmdSwitch_FastGenProfile,
LNK_CmdSwitch_FailIfMismatch,
LNK_CmdSwitch_Force,
LNK_CmdSwitch_Guard,
LNK_CmdSwitch_GuardSym,
LNK_CmdSwitch_GenProfile,
LNK_CmdSwitch_IdlOut,
LNK_CmdSwitch_IgnoreIdl,
LNK_CmdSwitch_Ilk,
LNK_CmdSwitch_IntegrityCheck,
LNK_CmdSwitch_InferAsanLibs,
LNK_CmdSwitch_InferAsanLibsNo,
LNK_CmdSwitch_Kernel,
LNK_CmdSwitch_KeyContainer,
LNK_CmdSwitch_KeyFile,
@@ -94,7 +101,6 @@ typedef enum
LNK_CmdSwitch_LtcgOut,
LNK_CmdSwitch_Map,
LNK_CmdSwitch_MapInfo,
LNK_CmdSwitch_Merge,
LNK_CmdSwitch_Midl,
LNK_CmdSwitch_NoAssembly,
LNK_CmdSwitch_NoEntry,
@@ -108,6 +114,7 @@ typedef enum
LNK_CmdSwitch_Stub,
LNK_CmdSwitch_SwapRun,
LNK_CmdSwitch_TlbId,
LNK_CmdSwitch_ThrowingNew,
LNK_CmdSwitch_UserProfile,
LNK_CmdSwitch_Verbose,
LNK_CmdSwitch_Version,
@@ -129,7 +136,6 @@ typedef enum
LNK_CmdSwitch_Rad_EnvLib,
LNK_CmdSwitch_Rad_Exe,
LNK_CmdSwitch_Rad_Guid,
LNK_CmdSwitch_Rad_IdleWorkers,
LNK_CmdSwitch_Rad_LargePages,
LNK_CmdSwitch_Rad_LinkVer,
LNK_CmdSwitch_Rad_Log,
@@ -142,6 +148,8 @@ typedef enum
LNK_CmdSwitch_Rad_PdbHashTypeNameMap,
LNK_CmdSwitch_Rad_PdbHashTypeNameLength,
LNK_CmdSwitch_Rad_SectVirtOff,
LNK_CmdSwitch_Rad_SharedThreadPool,
LNK_CmdSwitch_Rad_SharedThreadPoolMaxWorkers,
LNK_CmdSwitch_Rad_SuppressError,
LNK_CmdSwitch_Rad_SymbolTableCapDefined,
LNK_CmdSwitch_Rad_SymbolTableCapInternal,
@@ -221,6 +229,42 @@ typedef struct LNK_AltNameList
String8List to_list;
} LNK_AltNameList;
typedef struct LNK_ExportParse
{
struct LNK_ExportParse *next;
String8 name;
String8 alias;
String8 type;
} LNK_ExportParse;
typedef struct LNK_ExportParseList
{
U64 count;
LNK_ExportParse *first;
LNK_ExportParse *last;
} LNK_ExportParseList;
typedef struct LNK_MergeDirective
{
String8 src;
String8 dst;
} LNK_MergeDirective;
typedef struct LNK_MergeDirectiveNode
{
struct LNK_MergeDirectiveNode *next;
LNK_MergeDirective data;
} LNK_MergeDirectiveNode;
typedef struct LNK_MergeDirectiveList
{
U64 count;
LNK_MergeDirectiveNode *first;
LNK_MergeDirectiveNode *last;
} LNK_MergeDirectiveList;
typedef enum
{
LNK_DebugInfoGuid_Null,
@@ -243,6 +287,8 @@ typedef enum
# error
#endif
#define LNK_DEFAULT_THREAD_POOL_NAME "RADLINK_THREAD_POOL"
typedef struct LNK_Config
{
LNK_ConfigFlags flags;
@@ -268,7 +314,8 @@ typedef struct LNK_Config
U64 page_size;
U64 pdb_page_size;
U64 worker_count;
U64 idle_worker_count;
U64 max_worker_count;
String8 shared_thread_pool_name;
U64 *function_pad_min;
U64 *manifest_resource_id;
B32 no_default_libs;
@@ -281,7 +328,6 @@ typedef struct LNK_Config
Version subsystem_ver;
PE_ImageFileCharacteristics file_characteristics;
PE_DllCharacteristics dll_characteristics;
String8 user_entry_point_name;
String8 entry_point_name;
String8List lib_dir_list;
PathStyle path_style;
@@ -296,6 +342,7 @@ typedef struct LNK_Config
LNK_TypeNameHashMode pdb_hash_type_names;
String8 pdb_hash_type_name_map;
U64 pdb_hash_type_name_length;
LNK_ExportParseList export_symbol_list;
String8List input_list[LNK_Input_Count];
String8List input_default_lib_list;
String8List disallow_lib_list;
@@ -465,15 +512,15 @@ internal LNK_TypeNameHashMode lnk_type_name_hash_mode_from_string(String8 string
// Command Line Helpers
internal LNK_CmdOption * lnk_cmd_line_push_option_if_not_presentf(Arena *arena, LNK_CmdLine *cmd_line, LNK_CmdSwitchType cmd_switch_type, char *param_fmt, ...);
internal LNK_CmdOption * lnk_cmd_line_push_optionf(Arena *arena, LNK_CmdLine *cmd_line, LNK_CmdSwitchType cmd_switch_type, char *param_fmt, ...);
internal LNK_CmdOption * lnk_cmd_line_push_optionf (Arena *arena, LNK_CmdLine *cmd_line, LNK_CmdSwitchType cmd_switch_type, char *param_fmt, ...);
internal B32 lnk_cmd_line_has_switch(LNK_CmdLine cmd_line, LNK_CmdSwitchType cmd_switch_type);
////////////////////////////////
// Errors
internal void lnk_error_cmd_switch(LNK_ErrorCode code, LNK_CmdSwitchType cmd_switch, char *fmt, ...);
internal void lnk_error_cmd_switch_invalid_param_count(LNK_ErrorCode code, LNK_CmdSwitchType cmd_switch);
internal void lnk_error_cmd_switch_invalid_param(LNK_ErrorCode code, LNK_CmdSwitchType cmd_switch, String8 param);
internal void lnk_error_cmd_switch (LNK_ErrorCode code, String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, char *fmt, ...);
internal void lnk_error_cmd_switch_invalid_param_count(LNK_ErrorCode code, String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch);
internal void lnk_error_cmd_switch_invalid_param (LNK_ErrorCode code, String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8 param);
////////////////////////////////
// Getters
@@ -483,29 +530,40 @@ internal U64 lnk_get_base_addr(LNK_Config *config);
internal Version lnk_get_default_subsystem_version(PE_WindowsSubsystem subsystem, COFF_MachineType machine);
internal Version lnk_get_min_subsystem_version(PE_WindowsSubsystem subsystem, COFF_MachineType machine);
internal B32 lnk_do_debug_info(LNK_Config *config);
internal B32 lnk_do_debug_info (LNK_Config *config);
internal B32 lnk_is_thread_pool_shared(LNK_Config *config);
////////////////////////////////
// Specialized Parsers
internal B32 lnk_cmd_switch_parse_version(String8List value_strings, LNK_CmdSwitchType cmd_switch, Version *ver_out);
internal B32 lnk_cmd_switch_parse_tuple(String8List value_strings, LNK_CmdSwitchType cmd_switch, Rng1U64 *tuple_out);
internal B32 lnk_cmd_switch_parse_u64(String8List value_strings, LNK_CmdSwitchType cmd_switch, U64 *value_out, LNK_ParseU64Flags flags);
internal B32 lnk_cmd_switch_parse_u32(String8List value_strings, LNK_CmdSwitchType cmd_switch, U32 *value_out, LNK_ParseU64Flags flags);
internal B32 lnk_cmd_switch_parse_flag(String8List value_strings, LNK_CmdSwitchType cmd_switch, LNK_SwitchState *value_out);
internal void lnk_cmd_switch_set_flag_inv_16(String8List value_strings, LNK_CmdSwitchType cmd_switch, U16 *flags, U16 bits);
internal void lnk_cmd_switch_set_flag_inv_64(String8List value_strings, LNK_CmdSwitchType cmd_switch, U64 *flags, U64 bits);
internal void lnk_cmd_switch_set_flag_16(String8List value_strings, LNK_CmdSwitchType cmd_switch, U16 *flags, U16 bits);
internal void lnk_cmd_switch_set_flag_32(String8List value_strings, LNK_CmdSwitchType cmd_switch, U32 *flags, U32 bits);
internal void lnk_cmd_switch_set_flag_64(String8List value_strings, LNK_CmdSwitchType cmd_switch, U64 *flags, U64 bits);
internal B32 lnk_cmd_switch_parse_string(String8List value_strings, LNK_CmdSwitchType cmd_switch, String8 *string_out);
internal void lnk_cmd_switch_parse_string_copy(Arena *arena, String8List value_strings, LNK_CmdSwitchType cmd_switch, String8 *string_out);
internal B32 lnk_parse_alt_name_directive(Arena *arena, String8 input, LNK_AltNameList *list_out);
internal String8 * lnk_parse_alt_name_directive_list(Arena *arena, String8List list, LNK_AltNameList *list_out);
internal B32 lnk_cmd_switch_parse_version (String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, Version *ver_out);
internal B32 lnk_cmd_switch_parse_tuple (String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, Rng1U64 *tuple_out);
internal B32 lnk_cmd_switch_parse_u64 (String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, U64 *value_out, LNK_ParseU64Flags flags);
internal B32 lnk_cmd_switch_parse_u32 (String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, U32 *value_out, LNK_ParseU64Flags flags);
internal B32 lnk_cmd_switch_parse_flag (String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, LNK_SwitchState *value_out);
internal void lnk_cmd_switch_set_flag_inv_16(String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, U16 *flags, U16 bits);
internal void lnk_cmd_switch_set_flag_inv_64(String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, U64 *flags, U64 bits);
internal void lnk_cmd_switch_set_flag_16 (String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, U16 *flags, U16 bits);
internal void lnk_cmd_switch_set_flag_32 (String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, U32 *flags, U32 bits);
internal void lnk_cmd_switch_set_flag_64 (String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, U64 *flags, U64 bits);
internal B32 lnk_cmd_switch_parse_string (String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, String8 *string_out);
internal void lnk_cmd_switch_parse_string_copy(Arena *arena, String8 obj_path, String8 lib_path, LNK_CmdSwitchType cmd_switch, String8List value_strings, String8 *string_out);
////////////////////////////////
internal LNK_Config * lnk_config_from_raw_cmd_line(Arena *arena, String8List raw_cmd_line);
internal LNK_Config * lnk_build_config(Arena *arena, int argc, char **argv);
internal void lnk_alt_name_list_concat_in_place(LNK_AltNameList *list, LNK_AltNameList *to_concat);
internal B32 lnk_parse_alt_name_directive (Arena *arena, String8 input, LNK_AltNameList *list_out);
internal String8 * lnk_parse_alt_name_directive_list(Arena *arena, String8List list, LNK_AltNameList *list_out);
internal LNK_ExportParse * lnk_parse_export_directive(Arena *arena, LNK_ExportParseList *list, String8List value_list, String8 obj_path, String8 lib_path);
internal LNK_MergeDirectiveNode * lnk_merge_directive_list_push(Arena *arena, LNK_MergeDirectiveList *list, LNK_MergeDirective data);
internal B32 lnk_parse_merge_directive(String8 string, LNK_MergeDirective *out);
////////////////////////////////
internal void lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 name, String8List value_list, String8 obj_path, String8 lib_path);
internal LNK_Config * lnk_config_from_raw_cmd_line(Arena *arena, String8List raw_cmd_line);
internal LNK_Config * lnk_build_config (Arena *arena, int argc, char **argv);
+32 -24
View File
@@ -305,8 +305,8 @@ THREAD_POOL_TASK_FUNC(lnk_get_external_leaves_task)
LNK_GetExternalLeavesTask *task = raw_task;
MSF_Parsed *msf_parse = task->msf_parse_arr[ts_idx];
task->external_ti_ranges[ts_idx] = push_array_no_zero(arena, Rng1U64, CV_TypeIndexSource_COUNT);
task->external_leaves[ts_idx] = push_array_no_zero(arena, CV_DebugT, CV_TypeIndexSource_COUNT);
task->external_ti_ranges[ts_idx] = push_array(arena, Rng1U64, CV_TypeIndexSource_COUNT);
task->external_leaves[ts_idx] = push_array(arena, CV_DebugT, CV_TypeIndexSource_COUNT);
task->is_corrupted[ts_idx] = 1;
if (msf_parse) {
@@ -2505,7 +2505,7 @@ THREAD_POOL_TASK_FUNC(lnk_replace_type_names_with_hashes_lenient_task)
map = &task->maps[task_id];
}
U64 hash_max_chars = hash_length;
U64 hash_max_chars = hash_length*2;
U8 temp[128];
for (U64 leaf_idx = range.min; leaf_idx < range.max; ++leaf_idx) {
@@ -2513,7 +2513,9 @@ THREAD_POOL_TASK_FUNC(lnk_replace_type_names_with_hashes_lenient_task)
if (leaf.kind == CV_LeafKind_STRUCTURE || leaf.kind == CV_LeafKind_CLASS) {
CV_UDTInfo udt_info = cv_get_udt_info(leaf.kind, leaf.data);
if (udt_info.props & CV_TypeProp_HasUniqueName && udt_info.unique_name.size > hash_max_chars) {
if ((udt_info.props & CV_TypeProp_HasUniqueName) &&
udt_info.unique_name.size > hash_max_chars &&
udt_info.name.size > hash_max_chars) {
// hash unique name
U128 name_hash;
blake3_hasher hasher; blake3_hasher_init(&hasher);
@@ -2523,27 +2525,33 @@ THREAD_POOL_TASK_FUNC(lnk_replace_type_names_with_hashes_lenient_task)
// emit hash -> unique name map
if (make_map) {
lnk_format_u128(temp, sizeof(temp), hash_length, name_hash);
str8_list_pushf(map_arena, map, "%s %.*s\n", temp, str8_varg(udt_info.unique_name));
str8_list_pushf(map_arena, map, "%s %S\n", temp, str8_varg(udt_info.unique_name));
}
// parse leaf size
CV_NumericParsed dummy;
U64 numeric_size = cv_read_numeric(leaf.data, sizeof(CV_LeafStruct), &dummy);
U64 colon_pos = str8_find_needle_reverse(udt_info.name, 0, str8_lit("<lambda_"), 0);
B32 is_lambda = colon_pos != 0;
String8 lambda_prefix = str8_lit("<lambda_");
U64 colon_pos = str8_find_needle_reverse(udt_info.name, 0, lambda_prefix, 0);
B32 is_lambda = colon_pos != 0;
if (is_lambda) {
// replace display type string with unique type name hash
udt_info.name.size = lnk_format_u128(udt_info.name.str, udt_info.name.size, hash_length, name_hash);
U64 size = lnk_format_u128(temp, sizeof(temp), hash_length, name_hash);
Assert(size < udt_info.name.size);
Assert(size < udt_info.unique_name.size);
MemoryCopy(udt_info.name.str, temp, size+1);
MemoryCopy(udt_info.name.str+size+1, temp, size+1);
udt_info.name.size = size;
udt_info.unique_name.size = size;
// update leaf header
CV_LeafHeader *header = cv_debug_t_get_leaf_header(debug_t, leaf_idx);
header->size = sizeof(CV_LeafKind) + sizeof(CV_LeafStruct) + numeric_size + udt_info.name.size + 1;
// discard unique name
CV_LeafStruct *lf = (CV_LeafStruct *)(header + 1);
lf->props &= ~CV_TypeProp_HasUniqueName;
header->size = sizeof(CV_LeafKind) +
sizeof(CV_LeafStruct) +
numeric_size +
udt_info.name.size + 1 +
udt_info.unique_name.size + 1;
} else {
// replace uniuqe type name with hash
udt_info.unique_name.str = udt_info.name.str + udt_info.name.size + 1;
@@ -3017,7 +3025,7 @@ THREAD_POOL_TASK_FUNC(lnk_push_dbi_sec_contrib_task)
// Mod1::fUpdateSecContrib
if (sc_count > 0) {
for (U64 sc_idx = 0; sc_idx < sc_count; ++sc_idx) {
if (sc_arr[sc_idx].data.base.flags & COFF_SectionFlag_CNT_CODE) {
if (sc_arr[sc_idx].data.base.flags & COFF_SectionFlag_CntCode) {
mod->first_sc = sc_arr[sc_idx].data;
break;
}
@@ -3699,9 +3707,9 @@ THREAD_POOL_TASK_FUNC(lnk_convert_types_to_rdi_task)
} break;
case CV_LeafKind_POINTER: {
CV_LeafPointer *ptr = (CV_LeafPointer *) src.data.str;
CV_PointerKind ptr_kind = CV_PointerAttribs_ExtractKind(ptr->attribs);
CV_PointerMode ptr_mode = CV_PointerAttribs_ExtractMode(ptr->attribs);
U32 ptr_size = CV_PointerAttribs_ExtractSize(ptr->attribs);
CV_PointerKind ptr_kind = CV_PointerAttribs_Extract_Kind(ptr->attribs);
CV_PointerMode ptr_mode = CV_PointerAttribs_Extract_Mode(ptr->attribs);
U32 ptr_size = CV_PointerAttribs_Extract_Size(ptr->attribs);
(void)ptr_kind;
// parse ahead type chain and squash modifiers
@@ -4010,7 +4018,7 @@ THREAD_POOL_TASK_FUNC(lnk_convert_types_to_rdi_task)
for (U64 cursor = 0; cursor + sizeof(CV_LeafMethodListMember) <= method_list_leaf.data.size; ) {
// parse CodeView method overload info
CV_LeafMethodListMember *list_member = (CV_LeafMethodListMember *) (method_list_leaf.data.str + cursor);
CV_MethodProp prop = CV_FieldAttribs_ExtractMethodProp(list_member->attribs);
CV_MethodProp prop = CV_FieldAttribs_Extract_MethodProp(list_member->attribs);
cursor += sizeof(CV_LeafMethodListMember);
U32 vftable_offset = 0;
if (prop == CV_MethodProp_Intro || prop == CV_MethodProp_PureIntro) {
@@ -4037,7 +4045,7 @@ THREAD_POOL_TASK_FUNC(lnk_convert_types_to_rdi_task)
case CV_LeafKind_ONEMETHOD: {
// parse CodeView method
CV_LeafOneMethod *one_method = (CV_LeafOneMethod *) (src.data.str + cursor);
CV_MethodProp prop = CV_FieldAttribs_ExtractMethodProp(one_method->attribs);
CV_MethodProp prop = CV_FieldAttribs_Extract_MethodProp(one_method->attribs);
cursor += sizeof(CV_LeafOneMethod);
U32 vftable_offset = 0;
if (prop == CV_MethodProp_Intro || prop == CV_MethodProp_PureIntro) {
@@ -4493,21 +4501,21 @@ THREAD_POOL_TASK_FUNC(lnk_find_obj_compiler_info_task)
AssertAlways(sizeof(CV_SymCompile) <= symbol.data.size);
CV_SymCompile *compile = (CV_SymCompile *)symbol.data.str;
comp_info->arch = compile->machine;
comp_info->language = CV_CompileFlags_ExtractLanguage(compile->flags);
comp_info->language = CV_CompileFlags_Extract_Language(compile->flags);
comp_info->compiler_name = str8_cstring_capped(compile + 1, symbol.data.str + symbol.data.size);
goto exit;
} else if (symbol.kind == CV_SymKind_COMPILE2) {
AssertAlways(sizeof(CV_SymCompile2) <= symbol.data.size);
CV_SymCompile2 *compile2 = (CV_SymCompile2 *)symbol.data.str;
comp_info->arch = compile2->machine;
comp_info->language = CV_Compile2Flags_ExtractLanguage(compile2->flags);
comp_info->language = CV_Compile2Flags_Extract_Language(compile2->flags);
comp_info->compiler_name = str8_cstring_capped(compile2 + 1, symbol.data.str + symbol.data.size);
goto exit;
} else if (symbol.kind == CV_SymKind_COMPILE3) {
AssertAlways(sizeof(CV_SymCompile3) <= symbol.data.size);
CV_SymCompile3 *compile3 = (CV_SymCompile3 *)symbol.data.str;
comp_info->arch = compile3->machine;
comp_info->language = CV_Compile3Flags_ExtractLanguage(compile3->flags);
comp_info->language = CV_Compile3Flags_Extract_Language(compile3->flags);
comp_info->compiler_name = str8_cstring_capped(compile3 + 1, symbol.data.str + symbol.data.size);
goto exit;
}
@@ -5104,7 +5112,7 @@ THREAD_POOL_TASK_FUNC(lnk_convert_symbols_to_rdi_task)
CV_LvarAddrGap *gaps = (CV_LvarAddrGap *) (defrange_subfield_register + 1);
U64 gap_count = (symbol.data.size - sizeof(*defrange_subfield_register)) / sizeof(gaps[0]);
RDI_RegCode reg_rdi = rdi_reg_code_from_cv(comp_info.arch, defrange_subfield_register->reg);
U32 value_pos = CV_DefrangeSubfieldRegister_ExtractParentOffset(defrange_subfield_register->field_offset);
U32 value_pos = CV_DefrangeSubfieldRegister_Extract_ParentOffset(defrange_subfield_register->field_offset);
U32 value_size = cv_size_from_reg(comp_info.arch, defrange_subfield_register->reg) - value_pos;
Rng1U64 defrange = lnk_virt_range_from_sect_off_size(defrange_subfield_register->range.sec, defrange_subfield_register->range.off, defrange_subfield_register->range.len, task->image_sects, obj, symbol.kind, symbol.offset);
Rng1U64List ranges = cv_make_defined_range_list_from_gaps(arena, defrange, gaps, gap_count);
-188
View File
@@ -1,188 +0,0 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
internal void
lnk_alt_name_list_concat_in_place(LNK_AltNameList *list, LNK_AltNameList *to_concat)
{
str8_list_concat_in_place(&list->from_list, &to_concat->from_list);
str8_list_concat_in_place(&list->to_list, &to_concat->to_list);
}
internal LNK_MergeDirectiveNode *
lnk_merge_directive_list_push(Arena *arena, LNK_MergeDirectiveList *list, LNK_MergeDirective data)
{
LNK_MergeDirectiveNode *node = push_array_no_zero(arena, LNK_MergeDirectiveNode, 1);
node->data = data;
node->next = 0;
SLLQueuePush(list->first, list->last, node);
++list->count;
return node;
}
////////////////////////////////
internal void
lnk_parse_directives(Arena *arena, LNK_DirectiveInfo *directive_info, String8 buffer, String8 obj_path)
{
Temp scratch = scratch_begin(&arena, 1);
String8 unparsed_directives = buffer;
{
static const U8 BOM_SIG[] = { 0xEF, 0xBB, 0xBF };
B32 is_bom = MemoryMatch(buffer.str, &BOM_SIG[0], sizeof(BOM_SIG));
if (is_bom) {
unparsed_directives = str8_zero();
lnk_not_implemented("TODO: support for BOM encoding");
}
static const U8 ASCII_SIG[] = { 0x20, 0x20, 0x20 };
B32 is_ascii = MemoryMatch(buffer.str, &ASCII_SIG[0], sizeof(ASCII_SIG));
if (is_ascii) {
unparsed_directives = str8_skip(buffer, sizeof(ASCII_SIG));
}
}
String8List arg_list = lnk_arg_list_parse_windows_rules(scratch.arena, unparsed_directives);
LNK_CmdLine cmd_line = lnk_cmd_line_parse_windows_rules(scratch.arena, arg_list);
for (LNK_CmdOption *opt = cmd_line.first_option; opt != 0; opt = opt->next) {
static struct {
LNK_DirectiveKind kind;
String8 name;
} directive_table[LNK_Directive_Count] = {
{ LNK_Directive_Null, str8_lit_comp("") },
{ LNK_Directive_DefaultLib, str8_lit_comp("defaultlib") },
{ LNK_Directive_Export, str8_lit_comp("export" ) },
{ LNK_Directive_Include, str8_lit_comp("include") },
{ LNK_Directive_ManifestDependency, str8_lit_comp("manifestdependency") },
{ LNK_Directive_Merge, str8_lit_comp("merge") },
{ LNK_Directive_Section, str8_lit_comp("section") },
{ LNK_Directive_AlternateName, str8_lit_comp("alternatename") },
{ LNK_Directive_GuardSym, str8_lit_comp("guardsym") },
{ LNK_Directive_DisallowLib, str8_lit_comp("disallowlib") },
{ LNK_Directive_FailIfMismatch, str8_lit_comp("failifmismatch") },
{ LNK_Directive_EditAndContinue, str8_lit_comp("editandcontinue") },
{ LNK_Directive_ThrowingNew, str8_lit_comp("throwingnew") },
};
LNK_DirectiveKind kind = LNK_Directive_Null;
for (U64 i = 0; i < ArrayCount(directive_table); ++i) {
if (str8_match(directive_table[i].name, opt->string, StringMatchFlag_CaseInsensitive)) {
kind = directive_table[i].kind;
if (kind == LNK_Directive_Merge) {
String8 v = str8_list_join(scratch.arena, &opt->value_strings, &(StringJoin){ .sep = str8_lit_comp(" ")});
}
break;
}
}
if (kind == LNK_Directive_Null) {
lnk_error(LNK_Warning_UnknownDirective, "%S: unknown directive \"%S\"", obj_path, opt->string);
}
LNK_Directive *directive = push_array_no_zero(arena, LNK_Directive, 1);
directive->next = 0;
directive->id = push_str8_copy(arena, opt->string);
directive->value_list = str8_list_copy(arena, &opt->value_strings);
LNK_DirectiveList *directive_list = &directive_info->v[kind];
SLLQueuePush(directive_list->first, directive_list->last, directive);
++directive_list->count;
}
scratch_end(scratch);
}
internal String8List
lnk_parse_default_lib_directive(Arena *arena, LNK_DirectiveList *dir_list)
{
ProfBeginFunction();
String8List default_libs = {0};
for (LNK_Directive *dir = dir_list->first; dir != 0; dir = dir->next) {
for (String8Node *i = dir->value_list.first; i != 0; i = i->next) {
String8 lib_path = i->string;
// is there lib extension?
String8 ext = str8_skip_last_dot(lib_path);
if (ext.size == lib_path.size) { // TODO: fix string_extension_from_path, if there is no extension it should return zero
lib_path = push_str8f(arena, "%S.lib", lib_path);
} else {
lib_path = push_str8_copy(arena, lib_path);
}
str8_list_push(arena, &default_libs, lib_path);
}
}
ProfEnd();
return default_libs;
}
internal LNK_ExportParse *
lnk_parse_export_direcive(Arena *arena, LNK_ExportParseList *list, String8List value_list, LNK_Obj *obj)
{
ProfBeginFunction();
Temp scratch = scratch_begin(&arena, 1);
LNK_ExportParse *parse = 0;
// parse directive
String8 name = str8(0,0);
String8 alias = str8(0,0);
String8 type = coff_string_from_import_header_type(COFF_ImportHeaderType_CODE);
if (value_list.node_count > 0) {
String8List dir_split = str8_split_by_string_chars(scratch.arena, value_list.first->string, str8_lit("="), 0);
B32 is_export_valid = value_list.node_count <= 2 && value_list.node_count > 0;
if (is_export_valid) {
if (dir_split.node_count > 0) {
name = dir_split.last->string;
}
if (dir_split.node_count == 2) {
alias = dir_split.first->string;
}
if (value_list.node_count == 2) {
type = value_list.last->string;
}
}
}
// prase error check
if (name.size == 0) {
String8 dir = str8_list_join(scratch.arena, &value_list, 0);
lnk_error_obj(LNK_Error_IllData, obj, "invalid export directive \"%S\"", dir);
goto exit;
}
parse = push_array_no_zero(arena, LNK_ExportParse, 1);
parse->next = 0;
parse->name = name;
parse->alias = alias;
parse->type = type;
SLLQueuePush(list->first, list->last, parse);
++list->count;
exit:;
scratch_end(scratch);
ProfEnd();
return parse;
}
internal B32
lnk_parse_merge_directive(String8 string, LNK_MergeDirective *out)
{
Temp scratch = scratch_begin(0, 0);
B32 is_parse_ok = 0;
String8List list = str8_split_by_string_chars(scratch.arena, string, str8_lit("="), 0);
if (list.node_count == 2) {
out->src = list.first->string;
out->dst = list.last->string;
is_parse_ok = 1;
}
scratch_end(scratch);
return is_parse_ok;
}
-89
View File
@@ -1,89 +0,0 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#pragma once
typedef struct LNK_Directive
{
struct LNK_Directive *next;
String8 id;
String8List value_list;
} LNK_Directive;
typedef struct LNK_DirectiveList
{
U64 count;
LNK_Directive *first;
LNK_Directive *last;
} LNK_DirectiveList;
typedef struct LNK_ExportParse
{
struct LNK_ExportParse *next;
String8 name;
String8 alias;
String8 type;
} LNK_ExportParse;
typedef struct LNK_ExportParseList
{
U64 count;
LNK_ExportParse *first;
LNK_ExportParse *last;
} LNK_ExportParseList;
typedef struct LNK_MergeDirective
{
String8 src;
String8 dst;
} LNK_MergeDirective;
typedef struct LNK_MergeDirectiveNode
{
struct LNK_MergeDirectiveNode *next;
LNK_MergeDirective data;
} LNK_MergeDirectiveNode;
typedef struct LNK_MergeDirectiveList
{
U64 count;
LNK_MergeDirectiveNode *first;
LNK_MergeDirectiveNode *last;
} LNK_MergeDirectiveList;
typedef enum
{
LNK_Directive_Null,
LNK_Directive_DefaultLib,
LNK_Directive_Export,
LNK_Directive_Include,
LNK_Directive_ManifestDependency,
LNK_Directive_Merge,
LNK_Directive_Section,
LNK_Directive_AlternateName,
LNK_Directive_GuardSym,
LNK_Directive_DisallowLib,
LNK_Directive_FailIfMismatch,
LNK_Directive_EditAndContinue,
LNK_Directive_ThrowingNew,
LNK_Directive_Count
} LNK_DirectiveKind;
typedef struct LNK_DirectiveInfo
{
LNK_DirectiveList v[LNK_Directive_Count];
} LNK_DirectiveInfo;
////////////////////////////////
internal void lnk_alt_name_list_concat_in_place(LNK_AltNameList *list, LNK_AltNameList *to_concat);
internal LNK_MergeDirectiveNode * lnk_merge_directive_list_push(Arena *arena, LNK_MergeDirectiveList *list, LNK_MergeDirective data);
////////////////////////////////
internal void lnk_parse_directives(Arena *arena, LNK_DirectiveInfo *directive_info, String8 buffer, String8 obj_path);
internal String8List lnk_parse_default_lib_directive(Arena *arena, LNK_DirectiveList *dir_list);
internal B32 lnk_parse_merge_directive(String8 directive, LNK_MergeDirective *out);
+25
View File
@@ -67,6 +67,31 @@ lnk_error(LNK_ErrorCode code, char *fmt, ...)
va_end(args);
}
internal void
lnk_error_with_loc_fv(LNK_ErrorCode code, String8 obj_path, String8 lib_path, char *fmt, va_list args)
{
Temp scratch = scratch_begin(0, 0);
String8 text = push_str8fv(scratch.arena, fmt, args);
if (obj_path.size) {
if (lib_path.size) {
lnk_error(code, "%S(%S): %S", lib_path, obj_path, text);
} else {
lnk_error(code, "%S: %S", obj_path, text);
}
} else {
lnk_error(code, "%S", text);
}
scratch_end(scratch);
}
internal void
lnk_error_with_loc(LNK_ErrorCode code, String8 obj_path, String8 lib_path, char *fmt, ...)
{
va_list args; va_start(args, fmt);
lnk_error_with_loc_fv(code, obj_path, lib_path, fmt, args);
va_end(args);
}
internal void
lnk_supplement_error(char *fmt, ...)
{
+3
View File
@@ -74,11 +74,13 @@ typedef enum
LNK_Warning_SectionFlagsConflict,
LNK_Warning_Subsystem,
LNK_Warning_UnknownDirective,
LNK_Warning_IllegalDirective,
LNK_Warning_UnresolvedComdat,
LNK_Warning_UnusedDelayLoadDll,
LNK_Warning_LongSectionName,
LNK_Warning_UnknownSwitch,
LNK_Warning_TLSAlign,
LNK_Warning_DirectiveSectionWithRelocs,
LNK_Warning_Last,
LNK_Error_Count
@@ -110,6 +112,7 @@ typedef enum
internal void lnk_init_error_handler(void);
internal void lnk_errorfv(LNK_ErrorCode code, char *fmt, va_list args);
internal void lnk_error(LNK_ErrorCode code, char *fmt, ...);
internal void lnk_error_with_loc(LNK_ErrorCode code, String8 obj_path, String8 lib_path, char *fmt, ...);
internal void lnk_supplement_error(char *fmt, ...);
internal void lnk_supplement_error_list(String8List list);
internal void lnk_suppress_error(LNK_ErrorCode code);
+5 -5
View File
@@ -82,22 +82,22 @@ lnk_export_table_push_export(LNK_ExportTable *exptab, LNK_SymbolTable *symtab, L
// to CODE instead of DATA. But if you try export global variable with:
// #pragma comment(linker, "/export:global_bar,CODE")
// MSVC and LLD issue an error. For compatibility sake we do the same thing too.
COFF_ImportHeaderType type = coff_import_header_type_from_string(exp_parse->type);
COFF_ImportType type = coff_import_header_type_from_string(exp_parse->type);
switch (type) {
case COFF_ImportHeaderType_CODE: {
case COFF_ImportHeader_Code: {
B32 is_export_data = !(def->flags & (LNK_DefinedSymbolFlag_IsFunc|LNK_DefinedSymbolFlag_IsThunk));
if (is_export_data) {
lnk_error(LNK_Error_IllExport, "export \"%S\" is DATA but has specifier CODE", exp_parse->name);
}
} break;
case COFF_ImportHeaderType_DATA: {
case COFF_ImportHeader_Data: {
B32 is_export_code = !!(def->flags & (LNK_DefinedSymbolFlag_IsFunc|LNK_DefinedSymbolFlag_IsThunk));
if (is_export_code) {
lnk_error(LNK_Error_IllExport, "export \"%S\" is CODE but has specifier DATA", exp_parse->name);
}
} break;
case COFF_ImportHeaderType_CONST: {
lnk_not_implemented("TODO: COFF_ImportHeaderType_CONST");
case COFF_ImportHeader_Const: {
lnk_not_implemented("TODO: COFF_ImportHeader_Const");
} break;
default: {
if (exp_parse->type.size) {
+7 -7
View File
@@ -5,13 +5,13 @@
typedef struct LNK_Export
{
struct LNK_Export *next;
String8 name;
LNK_Symbol *symbol;
U32 id;
U16 ordinal;
COFF_ImportHeaderType type;
B32 is_private;
struct LNK_Export *next;
String8 name;
LNK_Symbol *symbol;
U32 id;
U16 ordinal;
COFF_ImportType type;
B32 is_private;
} LNK_Export;
typedef struct LNK_ExportList
+34 -34
View File
@@ -345,7 +345,7 @@ lnk_import_table_push_dll_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *symt
// emit tail merge
LNK_Chunk *tail_merge_chunk = 0;
switch (machine) {
case COFF_MachineType_X64: {
case COFF_Machine_X64: {
LNK_Symbol *delay_load_helper_symbol = lnk_make_undefined_symbol(symtab->arena->v[0], str8_lit(LNK_DELAY_LOAD_HELPER2_SYMBOL_NAME), LNK_SymbolScopeFlag_Main);
tail_merge_chunk = lnk_emit_tail_merge_thunk_x64(code_sect, code_chunk, imp_desc_symbol, delay_load_helper_symbol);
} break;
@@ -375,7 +375,7 @@ lnk_import_table_push_dll_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *symt
}
internal LNK_ImportFunc *
lnk_import_table_push_func_static(LNK_ImportTable *imptab, LNK_SymbolTable *symtab, LNK_ImportDLL *dll, COFF_ImportHeader *header)
lnk_import_table_push_func_static(LNK_ImportTable *imptab, LNK_SymbolTable *symtab, LNK_ImportDLL *dll, COFF_ParsedArchiveImportHeader *header)
{
ProfBeginFunction();
@@ -395,20 +395,20 @@ lnk_import_table_push_func_static(LNK_ImportTable *imptab, LNK_SymbolTable *symt
U64 import_size = coff_word_size_from_machine(dll->machine);
// generate sort index (optional)
String8 sort_index = str8_from_bits_u32(data_sect->arena, header->hint);
String8 sort_index = str8_from_bits_u32(data_sect->arena, header->hint_or_ordinal);
switch (header->name_type) {
case COFF_ImportHeaderNameType_ORDINAL: {
String8 ordinal_data = lnk_ordinal_data_from_hint(data_sect->arena, dll->machine, header->hint);
switch (header->import_by) {
case COFF_ImportBy_Ordinal: {
String8 ordinal_data = lnk_ordinal_data_from_hint(data_sect->arena, dll->machine, header->hint_or_ordinal);
ilt_chunk = lnk_section_push_chunk_data(data_sect, ilt_table_chunk, ordinal_data, sort_index);
iat_chunk = lnk_section_push_chunk_data(data_sect, iat_table_chunk, ordinal_data, sort_index);
// associate chunks
lnk_section_associate_chunks(data_sect, iat_chunk, ilt_chunk);
} break;
case COFF_ImportHeaderNameType_NAME: {
case COFF_ImportBy_Name: {
// put together name look up entry
String8 int_data = coff_make_import_lookup(data_sect->arena, header->hint, header->func_name);
String8 int_data = coff_make_import_lookup(data_sect->arena, header->hint_or_ordinal, header->func_name);
LNK_Chunk *int_chunk = lnk_section_push_chunk_data(data_sect, int_table_chunk, int_data, str8_zero());
// create symbol for lookup chunk
@@ -429,11 +429,11 @@ lnk_import_table_push_func_static(LNK_ImportTable *imptab, LNK_SymbolTable *symt
lnk_section_push_reloc(data_sect, ilt_chunk, LNK_Reloc_VIRT_OFF_32, 0, int_symbol);
lnk_section_push_reloc(data_sect, iat_chunk, LNK_Reloc_VIRT_OFF_32, 0, int_symbol);
} break;
case COFF_ImportHeaderNameType_UNDECORATE: {
lnk_not_implemented("TODO: COFF_ImportHeaderNameType_UNDECORATE");
case COFF_ImportBy_Undecorate: {
lnk_not_implemented("TODO: COFF_ImportBy_Undecorate");
} break;
case COFF_ImportHeaderNameType_NAME_NOPREFIX: {
lnk_not_implemented("TODO: COFF_ImportHeaderNameType_NAME_NOPREFIX");
case COFF_ImportBy_NameNoPrefix: {
lnk_not_implemented("TODO: COFF_ImportBy_NameNoPrefix");
} break;
}
@@ -444,9 +444,9 @@ lnk_import_table_push_func_static(LNK_ImportTable *imptab, LNK_SymbolTable *symt
// generate thunks
LNK_Symbol *jmp_thunk_symbol = g_null_symbol_ptr;
if (header->type == COFF_ImportHeaderType_CODE) {
if (header->type == COFF_ImportHeader_Code) {
switch (dll->machine) {
case COFF_MachineType_X64: {
case COFF_Machine_X64: {
// generate jump thunk
LNK_Chunk *jmp_thunk_chunk = lnk_emit_indirect_jump_thunk_x64(code_sect, code_table_chunk, iat_symbol);
lnk_section_associate_chunks(data_sect, iat_chunk, jmp_thunk_chunk);
@@ -472,7 +472,7 @@ lnk_import_table_push_func_static(LNK_ImportTable *imptab, LNK_SymbolTable *symt
}
internal LNK_ImportFunc *
lnk_import_table_push_func_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *symtab, LNK_ImportDLL *dll, COFF_ImportHeader *header)
lnk_import_table_push_func_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *symtab, LNK_ImportDLL *dll, COFF_ParsedArchiveImportHeader *header)
{
ProfBeginFunction();
@@ -498,16 +498,16 @@ lnk_import_table_push_func_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *sym
LNK_Symbol *int_symbol = 0;
// generate sort index (optional)
String8 sort_index = str8_from_bits_u32(data_sect->arena, header->hint);
String8 sort_index = str8_from_bits_u32(data_sect->arena, header->hint_or_ordinal);
// generate thunks
LNK_Symbol *jmp_thunk_symbol = g_null_symbol_ptr;
LNK_Symbol *load_thunk_symbol = g_null_symbol_ptr;
LNK_Chunk *jmp_thunk_chunk = 0;
LNK_Chunk *load_thunk_chunk = 0;
if (header->type == COFF_ImportHeaderType_CODE) {
if (header->type == COFF_ImportHeader_Code) {
switch (dll->machine) {
case COFF_MachineType_X64: {
case COFF_Machine_X64: {
String8 iat_symbol_name = push_str8f(symtab->arena->v[0], "__imp_%S", header->func_name);
LNK_Symbol *iat_symbol = lnk_make_undefined_symbol(symtab->arena->v[0], iat_symbol_name, LNK_SymbolScopeFlag_Main);
@@ -523,9 +523,9 @@ lnk_import_table_push_func_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *sym
}
}
switch (header->name_type) {
case COFF_ImportHeaderNameType_ORDINAL: {
String8 ordinal_data = lnk_ordinal_data_from_hint(data_sect->arena, dll->machine, header->hint);
switch (header->import_by) {
case COFF_ImportBy_Ordinal: {
String8 ordinal_data = lnk_ordinal_data_from_hint(data_sect->arena, dll->machine, header->hint_or_ordinal);
Assert(ordinal_data.size == import_size);
ilt_chunk = lnk_section_push_chunk_data(data_sect, ilt_table_chunk, ordinal_data, sort_index);
iat_chunk = lnk_section_push_chunk_bss(data_sect, iat_table_chunk, import_size, sort_index);
@@ -543,9 +543,9 @@ lnk_import_table_push_func_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *sym
lnk_section_associate_chunks(data_sect, iat_chunk, uiat_chunk);
}
} break;
case COFF_ImportHeaderNameType_NAME: {
case COFF_ImportBy_Name: {
// put together name look up entry
String8 int_data = coff_make_import_lookup(data_sect->arena, header->hint, header->func_name);
String8 int_data = coff_make_import_lookup(data_sect->arena, header->hint_or_ordinal, header->func_name);
LNK_Chunk *int_chunk = lnk_section_push_chunk_data(data_sect, int_table_chunk, int_data, str8_zero());
// create symbol for lookup chunk
@@ -586,11 +586,11 @@ lnk_import_table_push_func_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *sym
lnk_section_push_reloc(data_sect, uiat_chunk, LNK_Reloc_ADDR_64, 0, load_thunk_symbol);
}
} break;
case COFF_ImportHeaderNameType_UNDECORATE: {
lnk_not_implemented("TODO: COFF_ImportHeaderNameType_UNDECORATE");
case COFF_ImportBy_Undecorate: {
lnk_not_implemented("TODO: COFF_ImportBy_Undecorate");
} break;
case COFF_ImportHeaderNameType_NAME_NOPREFIX: {
lnk_not_implemented("TODO: COFF_ImportHeaderNameType_NAME_NOPREFIX");
case COFF_ImportBy_NameNoPrefix: {
lnk_not_implemented("TODO: COFF_ImportBy_NameNoPrefix");
} break;
}
@@ -624,14 +624,14 @@ lnk_ordinal_data_from_hint(Arena *arena, COFF_MachineType machine, U16 hint)
{
String8 ordinal_data = str8_zero();
switch (machine) {
case COFF_MachineType_X64: {
case COFF_Machine_X64: {
U64 *ordinal = push_array(arena, U64, 1);
*ordinal = coff_make_ordinal_64(hint);
*ordinal = coff_make_ordinal64(hint);
ordinal_data = str8_struct(ordinal);
} break;
case COFF_MachineType_X86: {
case COFF_Machine_X86: {
U32 *ordinal = push_array(arena, U32, 1);
*ordinal = coff_make_ordinal_32(hint);
*ordinal = coff_make_ordinal32(hint);
ordinal_data = str8_struct(ordinal);
} break;
default: lnk_not_implemented("TODO: support for machine 0x%x", machine);
@@ -736,7 +736,7 @@ lnk_emit_load_thunk_symbol(LNK_SymbolTable *symtab, LNK_Chunk *chunk, String8 fu
ProfBeginFunction();
// emit load thunk symbol
String8 load_thunk_name = push_str8f(symtab->arena->v[0], "__imp_load_%S", func_name);
LNK_Symbol *load_thunk_symbol = lnk_symbol_table_push_defined_chunk(symtab, load_thunk_name, LNK_DefinedSymbolVisibility_Extern, LNK_DefinedSymbolFlag_IsFunc|LNK_DefinedSymbolFlag_IsThunk, chunk, 0, 0, 0);
LNK_Symbol *load_thunk_symbol = lnk_symbol_table_push_defined_chunk(symtab, load_thunk_name, LNK_DefinedSymbolVisibility_Extern, LNK_DefinedSymbolFlag_IsFunc|LNK_DefinedSymbolFlag_IsThunk, chunk, 0, COFF_ComdatSelect_NoDuplicates, 0);
ProfEnd();
return load_thunk_symbol;
}
@@ -746,7 +746,7 @@ lnk_emit_jmp_thunk_symbol(LNK_SymbolTable *symtab, LNK_Chunk *chunk, String8 fun
{
ProfBeginFunction();
String8 jmp_thunk_name = push_str8f(symtab->arena->v[0], "%S", func_name);
LNK_Symbol *jmp_thunk_symbol = lnk_symbol_table_push_defined_chunk(symtab, jmp_thunk_name, LNK_DefinedSymbolVisibility_Extern, LNK_DefinedSymbolFlag_IsFunc|LNK_DefinedSymbolFlag_IsThunk, chunk, 0, 0, 0);
LNK_Symbol *jmp_thunk_symbol = lnk_symbol_table_push_defined_chunk(symtab, jmp_thunk_name, LNK_DefinedSymbolVisibility_Extern, LNK_DefinedSymbolFlag_IsFunc|LNK_DefinedSymbolFlag_IsThunk, chunk, 0, COFF_ComdatSelect_Any, 0);
ProfEnd();
return jmp_thunk_symbol;
}
@@ -756,7 +756,7 @@ lnk_emit_tail_merge_symbol(LNK_SymbolTable *symtab, LNK_Chunk *chunk, String8 fu
{
ProfBeginFunction();
String8 tail_merge_name = push_str8f(symtab->arena->v[0], "__tailMerge_%S", func_name);
LNK_Symbol *tail_merge_symbol = lnk_symbol_table_push_defined_chunk(symtab, tail_merge_name, LNK_DefinedSymbolVisibility_Extern, LNK_DefinedSymbolFlag_IsFunc|LNK_DefinedSymbolFlag_IsThunk, chunk, 0, 0, 0);
LNK_Symbol *tail_merge_symbol = lnk_symbol_table_push_defined_chunk(symtab, tail_merge_name, LNK_DefinedSymbolVisibility_Extern, LNK_DefinedSymbolFlag_IsFunc|LNK_DefinedSymbolFlag_IsThunk, chunk, 0, COFF_ComdatSelect_NoDuplicates, 0);
ProfEnd();
return tail_merge_symbol;
}
+2 -2
View File
@@ -64,8 +64,8 @@ internal LNK_ImportTable * lnk_import_table_alloc_delayed(LNK_SectionTable *st,
internal void lnk_import_table_release(LNK_ImportTable **imptab);
internal LNK_ImportDLL * lnk_import_table_push_dll_static(LNK_ImportTable *imptab, LNK_SymbolTable *symtab, String8 dll_name, COFF_MachineType machine);
internal LNK_ImportDLL * lnk_import_table_push_dll_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *symtab, String8 dll_name, COFF_MachineType machine);
internal LNK_ImportFunc * lnk_import_table_push_func_static(LNK_ImportTable *imptab, LNK_SymbolTable *symtab, LNK_ImportDLL *dll, COFF_ImportHeader *header);
internal LNK_ImportFunc * lnk_import_table_push_func_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *symtab, LNK_ImportDLL *dll, COFF_ImportHeader *header);
internal LNK_ImportFunc * lnk_import_table_push_func_static(LNK_ImportTable *imptab, LNK_SymbolTable *symtab, LNK_ImportDLL *dll, COFF_ParsedArchiveImportHeader *header);
internal LNK_ImportFunc * lnk_import_table_push_func_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *symtab, LNK_ImportDLL *dll, COFF_ParsedArchiveImportHeader *header);
internal LNK_ImportDLL * lnk_import_table_search_dll(LNK_ImportTable *imptab, String8 name);
internal LNK_ImportFunc * lnk_import_table_search_func(LNK_ImportDLL *dll, String8 name);
+2 -1
View File
@@ -173,7 +173,8 @@ lnk_write_data_list_to_file_path(String8 path, String8List data)
if (lnk_open_file_write((char*)path.str, path.size, &handle, sizeof(handle))) {
U64 offset = 0;
for (String8Node *data_n = data.first; data_n != 0; data_n = data_n->next) {
if (!lnk_write_file(&handle, offset, data_n->string.str, data_n->string.size)) {
U64 write_size = lnk_write_file(&handle, offset, data_n->string.str, data_n->string.size);
if (write_size != data_n->string.size) {
break;
}
offset += data_n->string.size;
+51 -51
View File
@@ -303,19 +303,19 @@ lnk_lib_writer_push_export(LNK_LibWriter *writer, COFF_MachineType machine, U64
lnk_lib_member_list_push(writer->arena, &writer->member_list, member);
switch (exp->type) {
case COFF_ImportHeaderType_CODE: {
case COFF_ImportHeader_Code: {
LNK_LibSymbol def_symbol = {0};
def_symbol.name = push_str8_copy(writer->arena, exp->name);
def_symbol.member_idx = member_idx;
lnk_lib_symbol_list_push(writer->arena, &writer->symbol_list, def_symbol);
}
case COFF_ImportHeaderType_DATA: {
case COFF_ImportHeader_Data: {
LNK_LibSymbol imp_symbol = {0};
imp_symbol.name = push_str8f(writer->arena, "__imp_%S", exp->name);
imp_symbol.member_idx = member_idx;
lnk_lib_symbol_list_push(writer->arena, &writer->symbol_list, imp_symbol);
} break;
case COFF_ImportHeaderType_CONST: {
case COFF_ImportHeader_Const: {
NotImplemented;
} break;
default: InvalidPath;
@@ -361,7 +361,7 @@ lnk_coff_archive_from_lib_build(Arena *arena, LNK_LibBuild *lib, B32 emit_second
// make member name
String8 name;
U64 name_with_slash_size = member->name.size + 1;
if (name_with_slash_size > COFF_ARCHIVE_MAX_SHORT_NAME_SIZE) {
if (name_with_slash_size > COFF_Archive_MaxShortNameSize) {
// have we seen this member name before?
KeyValuePair *is_present = hash_table_search_string(name_ht, member->name);
if (is_present) {
@@ -382,7 +382,7 @@ lnk_coff_archive_from_lib_build(Arena *arena, LNK_LibBuild *lib, B32 emit_second
str8_list_push(arena, &member_data_list, member_header);
str8_list_push(arena, &member_data_list, member_data);
str8_list_push_pad(arena, &member_data_list, member_data_list.total_size, COFF_ARCHIVE_ALIGN);
str8_list_push_pad(arena, &member_data_list, member_data_list.total_size, COFF_Archive_MemberAlign);
}
// long names member
@@ -390,7 +390,7 @@ lnk_coff_archive_from_lib_build(Arena *arena, LNK_LibBuild *lib, B32 emit_second
String8 header = lnk_build_lib_member_header(arena, str8_lit("//"), time_stamp, 0, 0, mode, long_names_list.total_size);
String8 data = str8_list_join(arena, &long_names_list, 0);
U64 member_offset = member_data_list.total_size + data.size + header.size;
str8_list_push_pad_front(arena, &member_data_list, member_offset, COFF_ARCHIVE_ALIGN);
str8_list_push_pad_front(arena, &member_data_list, member_offset, COFF_Archive_MemberAlign);
str8_list_push_front(arena, &member_data_list, data);
str8_list_push_front(arena, &member_data_list, header);
}
@@ -415,13 +415,13 @@ lnk_coff_archive_from_lib_build(Arena *arena, LNK_LibBuild *lib, B32 emit_second
U64 member_base_off;
{
U64 sizeof_first_header = COFF_ARCHIVE_MEMBER_HEADER_SIZE + sizeof(U32) + sizeof(U32) * symbol_count + name_buffer_size;
U64 sizeof_second_header = COFF_ARCHIVE_MEMBER_HEADER_SIZE + sizeof(U32) + sizeof(U32) * lib->member_count + sizeof(U32) + sizeof(U16) * symbol_count + name_buffer_size;
U64 sizeof_long_names = COFF_ARCHIVE_MEMBER_HEADER_SIZE + long_names_list.total_size;
U64 sizeof_first_header = sizeof(COFF_ArchiveMemberHeader) + sizeof(U32) + sizeof(U32) * symbol_count + name_buffer_size;
U64 sizeof_second_header = sizeof(COFF_ArchiveMemberHeader) + sizeof(U32) + sizeof(U32) * lib->member_count + sizeof(U32) + sizeof(U16) * symbol_count + name_buffer_size;
U64 sizeof_long_names = sizeof(COFF_ArchiveMemberHeader) + long_names_list.total_size;
sizeof_first_header = AlignPow2(sizeof_first_header, COFF_ARCHIVE_ALIGN);
sizeof_second_header = AlignPow2(sizeof_second_header, COFF_ARCHIVE_ALIGN);
sizeof_long_names = AlignPow2(sizeof_long_names, COFF_ARCHIVE_ALIGN);
sizeof_first_header = AlignPow2(sizeof_first_header, COFF_Archive_MemberAlign);
sizeof_second_header = AlignPow2(sizeof_second_header, COFF_Archive_MemberAlign);
sizeof_long_names = AlignPow2(sizeof_long_names, COFF_Archive_MemberAlign);
member_base_off = sizeof(g_coff_archive_sig);
member_base_off += sizeof_first_header;
@@ -468,7 +468,7 @@ lnk_coff_archive_from_lib_build(Arena *arena, LNK_LibBuild *lib, B32 emit_second
String8 member_header = lnk_build_lib_member_header(arena, str8_lit("/"), time_stamp, 0, 0, mode, member_data.size);
U64 member_offset = member_data_list.total_size + member_data.size + member_header.size;
str8_list_push_pad_front(arena, &member_data_list, member_offset, COFF_ARCHIVE_ALIGN);
str8_list_push_pad_front(arena, &member_data_list, member_offset, COFF_Archive_MemberAlign);
str8_list_push_front(arena, &member_data_list, member_data);
str8_list_push_front(arena, &member_data_list, member_header);
}
@@ -497,7 +497,7 @@ lnk_coff_archive_from_lib_build(Arena *arena, LNK_LibBuild *lib, B32 emit_second
String8 member_header = lnk_build_lib_member_header(arena, str8_lit("/"), time_stamp, 0, 0, mode, member_data.size);
U64 member_offset = sizeof(g_coff_archive_sig) + member_header.size + member_data.size;
str8_list_push_pad_front(arena, &member_data_list, member_offset, COFF_ARCHIVE_ALIGN);
str8_list_push_pad_front(arena, &member_data_list, member_offset, COFF_Archive_MemberAlign);
str8_list_push_front(arena, &member_data_list, member_data);
str8_list_push_front(arena, &member_data_list, member_header);
}
@@ -541,18 +541,18 @@ lnk_build_import_entry_obj(Arena *arena, String8 dll_name, COFF_MachineType mach
{
ProfBeginFunction();
Assert(machine == COFF_MachineType_X64);
Assert(str8_match(str8_lit("dll"), str8_skip_last_dot(dll_name), StringMatchFlag_CaseInsensitive|StringMatchFlag_RightSideSloppy));
Assert(machine == COFF_Machine_X64);
Assert(str8_match_lit("dll", str8_skip_last_dot(dll_name), StringMatchFlag_CaseInsensitive|StringMatchFlag_RightSideSloppy));
String8List list = {0};
COFF_Header *coff_header = push_array(arena, COFF_Header, 1);
coff_header->machine = machine;
str8_list_push(arena, &list, str8_struct(coff_header));
COFF_FileHeader *file_header = push_array(arena, COFF_FileHeader, 1);
file_header->machine = machine;
str8_list_push(arena, &list, str8_struct(file_header));
coff_header->section_count = 2;
COFF_SectionHeader *coff_sect_header_array = push_array(arena, COFF_SectionHeader, coff_header->section_count);
str8_list_push(arena, &list, str8_array(coff_sect_header_array, coff_header->section_count));
file_header->section_count = 2;
COFF_SectionHeader *coff_sect_header_array = push_array(arena, COFF_SectionHeader, file_header->section_count);
str8_list_push(arena, &list, str8_array(coff_sect_header_array, file_header->section_count));
PE_ImportEntry *import_entry = push_array(arena, PE_ImportEntry, 1);
U64 import_entry_off = list.total_size;
@@ -567,10 +567,10 @@ lnk_build_import_entry_obj(Arena *arena, String8 dll_name, COFF_MachineType mach
U64 import_entry_reloc_off = list.total_size;
str8_list_push(arena, &list, str8_array(import_entry_reloc_array, import_entry_reloc_count));
coff_header->symbol_count = 7;
COFF_Symbol16 *symbol_array = push_array(arena, COFF_Symbol16, coff_header->symbol_count);
coff_header->symbol_table_foff = safe_cast_u32(list.total_size);
str8_list_push(arena, &list, str8_array(symbol_array, coff_header->symbol_count));
file_header->symbol_count = 7;
COFF_Symbol16 *symbol_array = push_array(arena, COFF_Symbol16, file_header->symbol_count);
file_header->symbol_table_foff = safe_cast_u32(list.total_size);
str8_list_push(arena, &list, str8_array(symbol_array, file_header->symbol_count));
U64 string_table_base = list.total_size;
U32 *string_table_size_ptr = push_array(arena, U32, 1);
@@ -591,23 +591,23 @@ lnk_build_import_entry_obj(Arena *arena, String8 dll_name, COFF_MachineType mach
sect->foff = import_entry_off;
sect->reloc_count = import_entry_reloc_count;
sect->relocs_foff = import_entry_reloc_off;
sect->flags = COFF_SectionFlag_CNT_INITIALIZED_DATA|(COFF_SectionAlign_4BYTES << COFF_SectionFlag_ALIGN_SHIFT)|COFF_SectionFlag_MEM_READ|COFF_SectionFlag_MEM_WRITE;
sect->flags = COFF_SectionFlag_CntInitializedData|(COFF_SectionAlign_4Bytes << COFF_SectionFlag_AlignShift)|COFF_SectionFlag_MemRead|COFF_SectionFlag_MemWrite;
}
{
COFF_Reloc *lookup_table_voff_reloc = &import_entry_reloc_array[0];
lookup_table_voff_reloc->apply_off = OffsetOf(PE_ImportEntry, lookup_table_voff);
lookup_table_voff_reloc->isymbol = 3;
lookup_table_voff_reloc->type = COFF_RelocTypeX64_ADDR32NB;
lookup_table_voff_reloc->type = COFF_Reloc_X64_Addr32Nb;
COFF_Reloc *name_voff_reloc = &import_entry_reloc_array[1];
name_voff_reloc->apply_off = OffsetOf(PE_ImportEntry, name_voff);
name_voff_reloc->isymbol = 2;
name_voff_reloc->type = COFF_RelocTypeX64_ADDR32NB;
name_voff_reloc->type = COFF_Reloc_X64_Addr32Nb;
COFF_Reloc *import_addr_table_voff = &import_entry_reloc_array[2];
import_addr_table_voff->apply_off = OffsetOf(PE_ImportEntry, import_addr_table_voff);
import_addr_table_voff->isymbol = 4;
import_addr_table_voff->type = COFF_RelocTypeX64_ADDR32NB;
import_addr_table_voff->type = COFF_Reloc_X64_Addr32Nb;
}
// dll name
@@ -623,7 +623,7 @@ lnk_build_import_entry_obj(Arena *arena, String8 dll_name, COFF_MachineType mach
sect->name[7] = '6';
sect->fsize = dll_name_cstr.size;
sect->foff = dll_name_off;
sect->flags = COFF_SectionFlag_CNT_INITIALIZED_DATA|(COFF_SectionAlign_2BYTES << COFF_SectionFlag_ALIGN_SHIFT)|COFF_SectionFlag_MEM_READ|COFF_SectionFlag_MEM_WRITE;
sect->flags = COFF_SectionFlag_CntInitializedData|(COFF_SectionAlign_2Bytes << COFF_SectionFlag_AlignShift)|COFF_SectionFlag_MemRead|COFF_SectionFlag_MemWrite;
}
// import descriptor
@@ -638,7 +638,7 @@ lnk_build_import_entry_obj(Arena *arena, String8 dll_name, COFF_MachineType mach
symbol->name.long_name.zeroes = 0;
symbol->name.long_name.string_table_offset = symbol_name_off;
symbol->section_number = 1;
symbol->storage_class = COFF_SymStorageClass_EXTERNAL;
symbol->storage_class = COFF_SymStorageClass_External;
}
// .idata$2
@@ -653,7 +653,7 @@ lnk_build_import_entry_obj(Arena *arena, String8 dll_name, COFF_MachineType mach
symbol->name.short_name[6] = '$';
symbol->name.short_name[7] = '2';
symbol->section_number = 1;
symbol->storage_class = COFF_SymStorageClass_SECTION;
symbol->storage_class = COFF_SymStorageClass_Section;
}
// .idata$6
@@ -668,7 +668,7 @@ lnk_build_import_entry_obj(Arena *arena, String8 dll_name, COFF_MachineType mach
symbol->name.short_name[6] = '$';
symbol->name.short_name[7] = '6';
symbol->section_number = 2;
symbol->storage_class = COFF_SymStorageClass_STATIC;
symbol->storage_class = COFF_SymStorageClass_Static;
}
// .idata$4
@@ -682,8 +682,8 @@ lnk_build_import_entry_obj(Arena *arena, String8 dll_name, COFF_MachineType mach
symbol->name.short_name[5] = 'a';
symbol->name.short_name[6] = '$';
symbol->name.short_name[7] = '4';
symbol->section_number = COFF_SYMBOL_UNDEFINED_SECTION;
symbol->storage_class = COFF_SymStorageClass_SECTION;
symbol->section_number = COFF_Symbol_UndefinedSection;
symbol->storage_class = COFF_SymStorageClass_Section;
}
// .idata$5
@@ -697,8 +697,8 @@ lnk_build_import_entry_obj(Arena *arena, String8 dll_name, COFF_MachineType mach
symbol->name.short_name[5] = 'a';
symbol->name.short_name[6] = '$';
symbol->name.short_name[7] = '5';
symbol->section_number = COFF_SYMBOL_UNDEFINED_SECTION;
symbol->storage_class = COFF_SymStorageClass_SECTION;
symbol->section_number = COFF_Symbol_UndefinedSection;
symbol->storage_class = COFF_SymStorageClass_Section;
}
// __NULL_IMPORT_DESCRIPTOR
@@ -709,8 +709,8 @@ lnk_build_import_entry_obj(Arena *arena, String8 dll_name, COFF_MachineType mach
COFF_Symbol16 *symbol = &symbol_array[5];
symbol->name.long_name.zeroes = 0;
symbol->name.long_name.string_table_offset = symbol_name_off;
symbol->section_number = COFF_SYMBOL_UNDEFINED_SECTION;
symbol->storage_class = COFF_SymStorageClass_EXTERNAL;
symbol->section_number = COFF_Symbol_UndefinedSection;
symbol->storage_class = COFF_SymStorageClass_External;
}
// NULL_THUNK_DATA
@@ -724,8 +724,8 @@ lnk_build_import_entry_obj(Arena *arena, String8 dll_name, COFF_MachineType mach
COFF_Symbol16 *symbol = &symbol_array[6];
symbol->name.long_name.zeroes = 0;
symbol->name.long_name.string_table_offset = symbol_name_off;
symbol->section_number = COFF_SYMBOL_UNDEFINED_SECTION;
symbol->storage_class = COFF_SymStorageClass_EXTERNAL;
symbol->section_number = COFF_Symbol_UndefinedSection;
symbol->storage_class = COFF_SymStorageClass_External;
}
// update string table size
@@ -742,7 +742,7 @@ lnk_build_null_import_descriptor_obj(Arena *arena, COFF_MachineType machine)
String8List list = {0};
COFF_Header *coff_header = push_array(arena, COFF_Header, 1);
COFF_FileHeader *coff_header = push_array(arena, COFF_FileHeader, 1);
coff_header->machine = machine;
str8_list_push(arena, &list, str8_struct(coff_header));
@@ -776,7 +776,7 @@ lnk_build_null_import_descriptor_obj(Arena *arena, COFF_MachineType machine)
sect->name[7] = '3';
sect->fsize = null_import_data_size;
sect->foff = null_import_data_off;
sect->flags = COFF_SectionFlag_CNT_INITIALIZED_DATA|(COFF_SectionAlign_4BYTES << COFF_SectionFlag_ALIGN_SHIFT)|COFF_SectionFlag_MEM_READ|COFF_SectionFlag_MEM_WRITE;
sect->flags = COFF_SectionFlag_CntInitializedData|(COFF_SectionAlign_4Bytes << COFF_SectionFlag_AlignShift)|COFF_SectionFlag_MemRead|COFF_SectionFlag_MemWrite;
}
{
@@ -787,7 +787,7 @@ lnk_build_null_import_descriptor_obj(Arena *arena, COFF_MachineType machine)
symbol->name.long_name.zeroes = 0;
symbol->name.long_name.string_table_offset = symbol_name_off;
symbol->section_number = 1;
symbol->storage_class = COFF_SymStorageClass_EXTERNAL;
symbol->storage_class = COFF_SymStorageClass_External;
}
// update string table size
@@ -802,11 +802,11 @@ lnk_build_null_thunk_data_obj(Arena *arena, String8 dll_name, COFF_MachineType m
{
ProfBeginFunction();
Assert(str8_match(str8_lit("dll"), str8_skip_last_dot(dll_name), StringMatchFlag_CaseInsensitive|StringMatchFlag_RightSideSloppy));
Assert(str8_match_lit("dll", str8_skip_last_dot(dll_name), StringMatchFlag_CaseInsensitive|StringMatchFlag_RightSideSloppy));
String8List list = {0};
COFF_Header *coff_header = push_array(arena, COFF_Header, 1);
COFF_FileHeader *coff_header = push_array(arena, COFF_FileHeader, 1);
coff_header->machine = machine;
str8_list_push(arena, &list, str8_struct(coff_header));
@@ -845,7 +845,7 @@ lnk_build_null_thunk_data_obj(Arena *arena, String8 dll_name, COFF_MachineType m
sect->name[7] = '5';
sect->fsize = lookup_entry_data_size;
sect->foff = lookup_entry_data_off;
sect->flags = COFF_SectionFlag_CNT_INITIALIZED_DATA|(COFF_SectionAlign_8BYTES << COFF_SectionFlag_ALIGN_SHIFT)|COFF_SectionFlag_MEM_READ|COFF_SectionFlag_MEM_WRITE;
sect->flags = COFF_SectionFlag_CntInitializedData | (COFF_SectionAlign_8Bytes << COFF_SectionFlag_AlignShift)|(COFF_SectionFlag_MemRead|COFF_SectionFlag_MemWrite);
}
{
@@ -860,7 +860,7 @@ lnk_build_null_thunk_data_obj(Arena *arena, String8 dll_name, COFF_MachineType m
sect->name[7] = '4';
sect->fsize = null_thunk_data_size;
sect->foff = null_thunk_data_off;
sect->flags = COFF_SectionFlag_CNT_INITIALIZED_DATA|(COFF_SectionAlign_8BYTES << COFF_SectionFlag_ALIGN_SHIFT)|COFF_SectionFlag_MEM_READ|COFF_SectionFlag_MEM_WRITE;
sect->flags = COFF_SectionFlag_CntInitializedData|(COFF_SectionAlign_8Bytes << COFF_SectionFlag_AlignShift)|COFF_SectionFlag_MemRead|COFF_SectionFlag_MemWrite;
}
{
@@ -874,7 +874,7 @@ lnk_build_null_thunk_data_obj(Arena *arena, String8 dll_name, COFF_MachineType m
symbol->name.long_name.zeroes = 0;
symbol->name.long_name.string_table_offset = symbol_name_off;
symbol->section_number = 1;
symbol->storage_class = COFF_SymStorageClass_EXTERNAL;
symbol->storage_class = COFF_SymStorageClass_External;
}
// update string table size
@@ -908,7 +908,7 @@ lnk_build_lib_member_header(Arena *arena, String8 name, COFF_TimeStamp time_stam
str8_list_pushf(scratch.arena, &list, "`\n");
String8 result = str8_list_join(arena, &list, 0);
Assert(result.size == COFF_ARCHIVE_MEMBER_HEADER_SIZE);
Assert(result.size == sizeof(COFF_ArchiveMemberHeader));
scratch_end(scratch);
ProfEnd();
return result;
+391 -319
View File
@@ -6,19 +6,9 @@
internal void
lnk_error_obj(LNK_ErrorCode code, LNK_Obj *obj, char *fmt, ...)
{
Temp scratch = scratch_begin(0, 0);
va_list args;
va_start(args, fmt);
String8 text = push_str8fv(scratch.arena, fmt, args);
if (obj->lib_path.size) {
lnk_error(code, "%S(%S): %S", obj->lib_path, obj->path, text);
} else {
lnk_error(code, "%S: %S", obj->path, text);
}
va_list args; va_start(args, fmt);
lnk_error_with_loc_fv(code, obj->path, obj->lib_path, fmt, args);
va_end(args);
scratch_end(scratch);
}
////////////////////////////////
@@ -229,9 +219,10 @@ THREAD_POOL_TASK_FUNC(lnk_default_lib_collector)
Rng1U64 range = task->range_arr[task_id];
String8List *result = &task->out_arr[task_id];
for (U64 obj_idx = range.min; obj_idx < range.max; obj_idx += 1) {
LNK_Obj *obj = &task->in_arr.v[obj_idx].data;
String8List list = lnk_parse_default_lib_directive(arena, &obj->directive_info.v[LNK_Directive_DefaultLib]);
str8_list_concat_in_place(result, &list);
LNK_Obj *obj = &task->in_arr.v[obj_idx].data;
for (LNK_Directive *dir = obj->directive_info.v[LNK_CmdSwitch_DefaultLib].first; dir != 0; dir = dir->next) {
str8_list_concat_in_place(result, &dir->value_list);
}
}
}
@@ -264,7 +255,7 @@ THREAD_POOL_TASK_FUNC(lnk_manifest_dependency_collector)
for (; obj_ptr < obj_opl; obj_ptr += 1) {
LNK_Obj *obj = &obj_ptr->data;
LNK_DirectiveList *dirs = &obj->directive_info.v[LNK_Directive_ManifestDependency];
LNK_DirectiveList *dirs = &obj->directive_info.v[LNK_CmdSwitch_ManifestDependency];
for (LNK_Directive *dir = dirs->first; dir != 0; dir = dir->next) {
String8List dep = str8_list_copy(arena, &dir->value_list);
str8_list_concat_in_place(list, &dep);
@@ -332,19 +323,26 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer)
LNK_ObjNode *obj_node = task->obj_node_arr + task_id;
LNK_Obj *obj = &obj_node->data;
// cache path, we need it for error reports and debug stuff
String8 cached_path = push_str8_copy(arena, input->path);
String8 cached_lib_path = push_str8_copy(arena, input->lib_path);
// parse coff obj
COFF_HeaderInfo coff_info = coff_header_info_from_data(input->data);
COFF_SectionHeader *coff_sect_arr = (COFF_SectionHeader *)(input->data.str + coff_info.section_array_off);
void *coff_symbols = input->data.str + coff_info.symbol_off;
COFF_FileHeaderInfo coff_info = coff_file_header_info_from_data(input->data);
Rng1U64 coff_file_header_range = rng_1u64(0, coff_info.header_size);
Rng1U64 coff_sect_arr_range = rng_1u64(coff_info.section_array_off, coff_info.section_array_off + coff_info.section_count_no_null * sizeof(COFF_SectionHeader));
Rng1U64 coff_symbols_range = rng_1u64(coff_info.symbol_off, coff_info.symbol_off + coff_info.symbol_count * coff_info.symbol_size);
String8 raw_coff_sect_arr = str8_substr(input->data, coff_sect_arr_range);
String8 raw_coff_symbols = str8_substr(input->data, coff_symbols_range);
// handle machines we dont support
if (coff_info.machine != COFF_MachineType_UNKNOWN && coff_info.machine != COFF_MachineType_X64) {
lnk_error(LNK_Error_UnsupportedMachine, "%S: %S machine is supported", input->path, coff_string_from_machine_type(coff_info.machine));
if (raw_coff_sect_arr.size != dim_1u64(coff_sect_arr_range)) {
lnk_error_with_loc(LNK_Error_IllData, cached_path, cached_lib_path, "corrupted file, unable to read section header table");
}
if (raw_coff_symbols.size != dim_1u64(coff_symbols_range)) {
lnk_error_with_loc(LNK_Error_IllData, cached_path, cached_lib_path, "corrupted file, unable to read symbol table");
}
COFF_SectionHeader *coff_sect_arr = (COFF_SectionHeader *)raw_coff_sect_arr.str;
void *coff_symbols = raw_coff_symbols.str;
// :function_pad_min
U64 function_pad_min;
@@ -354,29 +352,12 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer)
function_pad_min = lnk_get_default_function_pad_min(coff_info.machine);
}
U64 chunk_count = 0;
chunk_count += coff_info.section_count_no_null;
chunk_count += 1; // :common_block
U64 chunk_count = 1; // :common_block
chunk_count += coff_info.section_count_no_null;
String8 *sect_name_arr = push_array_no_zero(arena, String8, chunk_count);
String8 *sect_sort_arr = push_array_no_zero(arena, String8, chunk_count);
LNK_Chunk *chunk_arr = push_array_no_zero(arena, LNK_Chunk, chunk_count);
// init section name and postfix array
for (U64 sect_idx = 0; sect_idx < coff_info.section_count_no_null; sect_idx += 1) {
COFF_SectionHeader *coff_sect = &coff_sect_arr[sect_idx];
// read name
String8 sect_name = coff_name_from_section_header(coff_sect, input->data, coff_info.string_table_off);
// parse section name
String8 name, postfix;
coff_parse_section_name(sect_name, &name, &postfix);
// fill out
sect_name_arr[sect_idx] = name;
sect_sort_arr[sect_idx] = postfix;
}
String8 *sect_name_arr = push_array_no_zero(arena, String8, chunk_count);
String8 *sect_sort_arr = push_array_no_zero(arena, String8, chunk_count);
LNK_Chunk *chunk_arr = push_array(arena, LNK_Chunk, chunk_count);
// :common_block
U64 common_block_idx = chunk_count - 1;
@@ -386,24 +367,48 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer)
for (U64 sect_idx = 0; sect_idx < coff_info.section_count_no_null; sect_idx += 1) {
COFF_SectionHeader *coff_sect = &coff_sect_arr[sect_idx];
// read name
String8 sect_name = coff_name_from_section_header(input->data, coff_sect, coff_info.string_table_off);
// parse section name
coff_parse_section_name(sect_name, &sect_name_arr[sect_idx], &sect_sort_arr[sect_idx]);
String8 data;
if (coff_sect->flags & COFF_SectionFlag_CNT_UNINITIALIZED_DATA) {
if (coff_sect->flags & COFF_SectionFlag_CntUninitializedData) {
data = str8(0, coff_sect->fsize);
} else {
data = str8(input->data.str + coff_sect->foff, coff_sect->fsize);
if (coff_sect->fsize > 0) {
Rng1U64 range = rng_1u64(coff_sect->foff, coff_sect->foff + coff_sect->fsize);
data = str8_substr(input->data, range);
if (contains_1u64(coff_file_header_range, coff_sect->foff) ||
(coff_sect->fsize > 0 && contains_1u64(coff_file_header_range, coff_sect->foff + coff_sect->fsize-1))) {
lnk_error_with_loc(LNK_Error_IllData, cached_path, cached_lib_path, "header (%S No. %#llx) defines out of bounds section data (file offsets point into file header)", sect_name, sect_idx+1);
}
if (contains_1u64(coff_sect_arr_range, coff_sect->foff) ||
(coff_sect->fsize > 0 && contains_1u64(coff_sect_arr_range, coff_sect->foff + coff_sect->fsize-1))) {
lnk_error_with_loc(LNK_Error_IllData, cached_path, cached_lib_path, "header (%S No. %#llx) defines out of bounds section data (file offsets point into section header table)", sect_name, sect_idx+1);
}
if (contains_1u64(coff_symbols_range, coff_sect->foff) ||
(coff_sect->fsize > 0 && contains_1u64(coff_symbols_range, coff_sect->foff + coff_sect->fsize-1))) {
lnk_error_with_loc(LNK_Error_IllData, cached_path, cached_lib_path, "header (%S No. %#llx) defines out of bounds section data (file offsets point into symbol table)", sect_name, sect_idx+1);
}
if (dim_1u64(range) != coff_sect->fsize) {
lnk_error_with_loc(LNK_Error_IllData, cached_path, cached_lib_path, "header (%S No. %#llx) defines out of bounds section data", sect_name, sect_idx+1);
}
} else {
data = str8_zero();
}
}
LNK_Chunk *chunk = &chunk_arr[sect_idx];
chunk->ref = lnk_chunk_ref(0,0); // :chunk_ref_assign
chunk->align = coff_align_size_from_section_flags(coff_sect->flags);
chunk->min_size = 0;
chunk->is_discarded = !!(coff_sect->flags & COFF_SectionFlag_LNK_REMOVE);
chunk->is_discarded = !!(coff_sect->flags & COFF_SectionFlag_LnkRemove);
chunk->sort_chunk = 1;
chunk->type = LNK_Chunk_Leaf;
chunk->sort_idx = sect_sort_arr[sect_idx];
chunk->input_idx = LNK_MakeChunkInputIdx(obj_idx, sect_idx);
chunk->flags = coff_sect->flags;
chunk->associate = 0;
chunk->u.leaf = data;
lnk_chunk_set_debugf(arena, chunk, "%S: name: %S, obj_idx: 0x%llX isect: 0x%llX", cached_path, sect_name_arr[sect_idx], obj_idx, sect_idx);
}
@@ -428,10 +433,10 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer)
}
// convert from coff
B32 is_big_obj = coff_info.type == COFF_DataType_BIG_OBJ;
LNK_SymbolArray symbol_arr = lnk_symbol_array_from_coff(arena, input->data, obj, cached_path, is_big_obj, function_pad_min, coff_info.string_table_off, coff_info.section_count_no_null, coff_sect_arr, coff_info.symbol_count, coff_symbols, chunk_ptr_arr, master_common_block);
LNK_SymbolList symbol_list = lnk_symbol_list_from_array(arena, symbol_arr);
LNK_RelocList *reloc_list_arr = lnk_reloc_list_array_from_coff(arena, coff_info.machine, input->data, coff_info.section_count_no_null, coff_sect_arr, chunk_ptr_arr, symbol_arr);
LNK_SymbolArray symbol_arr = lnk_symbol_array_from_coff(arena, input->data, obj, cached_path, cached_lib_path, coff_info.is_big_obj, function_pad_min, coff_info.string_table_off, coff_info.section_count_no_null, coff_sect_arr, coff_info.symbol_count, coff_symbols, chunk_ptr_arr, master_common_block);
LNK_SymbolList symbol_list = lnk_symbol_list_from_array(arena, symbol_arr);
LNK_RelocList *reloc_list_arr = lnk_reloc_list_array_from_coff(arena, coff_info.machine, input->data, coff_info.section_count_no_null, coff_sect_arr, chunk_ptr_arr, symbol_arr);
LNK_DirectiveInfo directive_info = lnk_directive_info_from_sections(arena, cached_path, cached_lib_path, coff_info.section_count_no_null, reloc_list_arr, sect_name_arr, chunk_arr);
// fill out obj
obj->data = input->data;
@@ -446,12 +451,12 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer)
obj->chunk_arr = chunk_ptr_arr;
obj->symbol_list = symbol_list;
obj->sect_reloc_list_arr = reloc_list_arr;
obj->directive_info = lnk_init_directives(arena, cached_path, coff_info.section_count_no_null, sect_name_arr, chunk_arr);
obj->directive_info = directive_info;
// parse exports
LNK_ExportParseList export_parse = {0};
for (LNK_Directive *dir = obj->directive_info.v[LNK_Directive_Export].first; dir != 0; dir = dir->next) {
lnk_parse_export_direcive(arena, &obj->export_parse, dir->value_list, obj);
for (LNK_Directive *dir = obj->directive_info.v[LNK_CmdSwitch_Export].first; dir != 0; dir = dir->next) {
lnk_parse_export_directive(arena, &obj->export_parse, dir->value_list, obj->path, obj->lib_path);
}
// push /export symbols
@@ -461,12 +466,12 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer)
}
// push /include symbols
for (LNK_Directive *dir = obj->directive_info.v[LNK_Directive_Include].first; dir != 0; dir = dir->next) {
for (LNK_Directive *dir = obj->directive_info.v[LNK_CmdSwitch_Include].first; dir != 0; dir = dir->next) {
str8_list_concat_in_place(&obj->include_symbol_list, &dir->value_list);
}
// parse /alternatename
for (LNK_Directive *dir = obj->directive_info.v[LNK_Directive_AlternateName].first; dir != 0; dir = dir->next) {
for (LNK_Directive *dir = obj->directive_info.v[LNK_CmdSwitch_AlternateName].first; dir != 0; dir = dir->next) {
String8 *invalid_string = lnk_parse_alt_name_directive_list(arena, dir->value_list, &obj->alt_name_list);
if (invalid_string != 0) {
lnk_error_obj(LNK_Error_Cmdl, obj, "invalid syntax \"%S\", expected format \"FROM=TO\"", *invalid_string);
@@ -489,7 +494,7 @@ THREAD_POOL_TASK_FUNC(lnk_obj_new_sect_scanner)
for (U64 chunk_idx = 0; chunk_idx < obj->chunk_count; chunk_idx += 1) {
String8 sect_name = obj->sect_name_arr[chunk_idx];
COFF_SectionFlags sect_flags = obj->chunk_arr[chunk_idx]->flags & ~COFF_SectionFlags_LNK_FLAGS;
COFF_SectionFlags sect_flags = obj->chunk_arr[chunk_idx]->flags & ~COFF_SectionFlags_LnkFlags;
KeyValuePair *is_present = hash_table_search_string(ht, sect_name);
if (is_present) {
@@ -669,7 +674,7 @@ lnk_obj_list_push_parallel(TP_Context *tp,
// push new sections for :find_chunk_section
for (LNK_SectDefn *curr = new_list.first; curr != 0; curr = curr->next) {
lnk_section_table_push(st, curr->name, curr->flags & ~COFF_SectionFlags_LNK_FLAGS);
lnk_section_table_push(st, curr->name, curr->flags & ~COFF_SectionFlags_LnkFlags);
}
tp_temp_end(temp);
@@ -731,9 +736,10 @@ lnk_obj_list_push_parallel(TP_Context *tp,
internal LNK_SymbolArray
lnk_symbol_array_from_coff(Arena *arena,
String8 coff_data,
String8 raw_coff,
LNK_Obj *obj,
String8 obj_path,
String8 lib_path,
B32 is_big_obj,
U64 function_pad_min,
U64 string_table_off,
@@ -744,282 +750,270 @@ lnk_symbol_array_from_coff(Arena *arena,
LNK_ChunkPtr *chunk_ptr_arr,
LNK_Chunk *master_common_block)
{
LNK_SymbolArray symbol_array;
symbol_array.count = coff_symbol_count;
symbol_array.v = push_array(arena, LNK_Symbol, symbol_array.count);
for (U64 symbol_idx = 0; symbol_idx < coff_symbol_count; ++symbol_idx) {
String8 name;
U32 section_number;
U32 value;
COFF_SymStorageClass storage_class;
COFF_SymbolType type;
U64 aux_symbol_count;
void *aux_symbols;
if (function_pad_min) {
COFF_ParsedSymbol symbol;
for (U64 symbol_idx = 0; symbol_idx < coff_symbol_count; symbol_idx += (1 + symbol.aux_symbol_count)) {
// read symbol
if (is_big_obj) {
symbol = coff_parse_symbol32(raw_coff, string_table_off, &((COFF_Symbol32 *)coff_symbols)[symbol_idx]);
} else {
symbol = coff_parse_symbol16(raw_coff, string_table_off, &((COFF_Symbol16 *)coff_symbols)[symbol_idx]);
}
// is this a function symbol?
COFF_SymbolValueInterpType interp = coff_interp_symbol(symbol.section_number, symbol.value, symbol.storage_class);
if (interp == COFF_SymbolValueInterp_Regular && COFF_SymbolType_IsFunc(symbol.type)) {
if (symbol.section_number == 0 || symbol.section_number > sect_count) {
lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "out ouf bounds section index in symbol \"%S (%u)\"", symbol.name, symbol.section_number);
}
if (symbol.value > coff_sect_arr[symbol.section_number-1].fsize) {
lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "out of bounds section offset in symbol \"%S (%u)\"", symbol.name, symbol.value);
}
LNK_Chunk *chunk = chunk_ptr_arr[symbol.section_number-1];
if (symbol.value > 0) {
// convert leaf to list
//
// there is no way to know up front how many splits we have,
// so lazily convert chunks when see two or more functions
// in a section
if (chunk->type == LNK_Chunk_Leaf) {
// make a list chunk
LNK_Chunk *chunk_list = push_array(arena, LNK_Chunk, 1);
chunk_list->type = LNK_Chunk_List;
chunk_list->align = chunk->align;
chunk_list->is_discarded = chunk->is_discarded;
chunk_list->sort_idx = chunk->sort_idx;
chunk_list->input_idx = chunk->input_idx;
chunk_list->flags = chunk->flags;
chunk_list->u.list = push_array(arena, LNK_ChunkList, 1);
lnk_chunk_set_debugf(arena, chunk_list, "%S: function chunk list for %S", obj_path, symbol.name);
// update properties on first chunk
chunk->min_size = function_pad_min;
chunk->sort_chunk = 0;
chunk->sort_idx = str8_zero();
chunk->input_idx = 0;
// push leaf to list
lnk_chunk_list_push(arena, chunk_list->u.list, chunk);
// set list as target chunk
chunk = chunk_list;
// set list chunk to be head of this section
chunk_ptr_arr[symbol.section_number-1] = chunk_list;
}
// find chunk that is near symbol
U64 offset_cursor = 0;
LNK_ChunkNode *current = chunk->u.list->last;
for (LNK_ChunkNode *c = chunk->u.list->first; c != 0; c = c->next) {
Assert(c->data->type == LNK_Chunk_Leaf);
if (offset_cursor + c->data->u.leaf.size >= symbol.value) {
current = c;
break;
}
offset_cursor += c->data->u.leaf.size;
}
Assert(current->data->type == LNK_Chunk_Leaf);
if (offset_cursor < symbol.value) {
// bifurcate chunk at symbol offset
U64 split_pos = symbol.value - offset_cursor;
Rng1U64 left_data_range = rng_1u64(0, split_pos);
Rng1U64 right_data_range = rng_1u64(left_data_range.max, current->data->u.leaf.size);
String8 left_data = str8_substr(current->data->u.leaf, left_data_range);
String8 right_data = str8_substr(current->data->u.leaf, right_data_range);
// create new chunk
LNK_Chunk *split_chunk = push_array(arena, LNK_Chunk, 1);
split_chunk->type = LNK_Chunk_Leaf;
split_chunk->align = current->data->align;
split_chunk->min_size = function_pad_min;
split_chunk->is_discarded = current->data->is_discarded;
split_chunk->flags = current->data->flags;
split_chunk->u.leaf = right_data;
lnk_chunk_set_debugf(arena, split_chunk, "%S: chunk split on function %S SECT%x SPLIT_POS %#llx", obj_path, symbol.name, symbol.section_number, split_pos);
LNK_ChunkNode *split_node = push_array(arena, LNK_ChunkNode, 1);
split_node->data = split_chunk;
// update split chunk data
current->data->u.leaf = left_data;
// insert split chunk after current chunk
if (split_node->next == 0) {
chunk->u.list->last = split_node;
}
split_node->next = current->next;
current->next = split_node;
chunk->u.list->count += 1;
}
}
}
}
}
LNK_SymbolArray symbol_array = {0};
symbol_array.count = coff_symbol_count;
symbol_array.v = push_array(arena, LNK_Symbol, symbol_array.count);
COFF_ParsedSymbol parsed_symbol;
for (U64 symbol_idx = 0; symbol_idx < coff_symbol_count; symbol_idx += (1 + parsed_symbol.aux_symbol_count)) {
void *aux_symbols;
if (is_big_obj) {
COFF_Symbol32 *coff_symbol32 = (COFF_Symbol32 *)coff_symbols + symbol_idx;
name = coff_read_symbol_name(coff_data, string_table_off, &coff_symbol32->name);
section_number = coff_symbol32->section_number;
value = coff_symbol32->value;
storage_class = coff_symbol32->storage_class;
type = coff_symbol32->type;
aux_symbol_count = coff_symbol32->aux_symbol_count;
aux_symbols = coff_symbol32 + 1;
COFF_Symbol32 *ptr = &((COFF_Symbol32 *)coff_symbols)[symbol_idx];
parsed_symbol = coff_parse_symbol32(raw_coff, string_table_off, ptr);
aux_symbols = parsed_symbol.aux_symbol_count ? ptr+1 : 0;
} else {
COFF_Symbol16 *coff_symbol16 = (COFF_Symbol16 *)coff_symbols + symbol_idx;
name = coff_read_symbol_name(coff_data, string_table_off, &coff_symbol16->name);
section_number = coff_symbol16->section_number;
value = coff_symbol16->value;
storage_class = coff_symbol16->storage_class;
type = coff_symbol16->type;
aux_symbol_count = coff_symbol16->aux_symbol_count;
aux_symbols = coff_symbol16 + 1;
// promote special section numbers to 32 bit
if (section_number == COFF_SYMBOL_DEBUG_SECTION_16) {
section_number = COFF_SYMBOL_DEBUG_SECTION;
} else if (section_number == COFF_SYMBOL_ABS_SECTION_16) {
section_number = COFF_SYMBOL_ABS_SECTION;
}
COFF_Symbol16 *ptr = (COFF_Symbol16 *)coff_symbols + symbol_idx;
parsed_symbol = coff_parse_symbol16(raw_coff, string_table_off, ptr);
aux_symbols = parsed_symbol.aux_symbol_count ? ptr+1 : 0;
}
if (symbol_idx + aux_symbol_count + 1 > coff_symbol_count) {
lnk_error(LNK_Error_IllData, "%S: symbol %S has out of bounds aux symbol count %u", obj_path, name, aux_symbol_count);
if (symbol_idx + parsed_symbol.aux_symbol_count + 1 > coff_symbol_count) {
lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "symbol %S (No. %llx) has out of bounds aux symbol count %llu", parsed_symbol.name, symbol_idx, parsed_symbol.aux_symbol_count);
}
COFF_SymbolValueInterpType interp = coff_interp_symbol(section_number, value, storage_class);
COFF_SymbolValueInterpType interp = coff_interp_symbol(parsed_symbol.section_number, parsed_symbol.value, parsed_symbol.storage_class);
switch (interp) {
case COFF_SymbolValueInterp_REGULAR: {
if (section_number == 0 || section_number > sect_count) {
lnk_error(LNK_Error_IllData, "%S: out ouf bounds section index in symbol \"%S (%u)\"", obj_path, name, section_number);
break;
}
case COFF_SymbolValueInterp_Regular: {
if (parsed_symbol.section_number == 0 || parsed_symbol.section_number > sect_count) {
lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "symbol %S (No. %llx) has out ouf bounds section index %x", parsed_symbol.name, symbol_idx, parsed_symbol.section_number);
}
if (parsed_symbol.value > coff_sect_arr[parsed_symbol.section_number-1].fsize) {
lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "symbol %S (No. %llx) has out of bounds section offset %x into section %x", parsed_symbol.name, symbol_idx, parsed_symbol.value, parsed_symbol.section_number);
}
COFF_SectionHeader *coff_sect_header = &coff_sect_arr[section_number-1];
if (value > coff_sect_header->fsize) {
lnk_error(LNK_Error_IllData, "%S: out of bounds section offset in symbol \"%S (%u)\"", obj_path, name, value);
break;
}
LNK_DefinedSymbolVisibility visibility = LNK_DefinedSymbolVisibility_Static;
if (parsed_symbol.storage_class == COFF_SymStorageClass_External) {
visibility = LNK_DefinedSymbolVisibility_Extern;
}
LNK_DefinedSymbolFlags flags = 0;
if (COFF_SymbolType_IsFunc(parsed_symbol.type)) {
flags |= LNK_DefinedSymbolFlag_IsFunc;
}
LNK_DefinedSymbolVisibility visibility = LNK_DefinedSymbolVisibility_Static;
if (storage_class == COFF_SymStorageClass_EXTERNAL) {
visibility = LNK_DefinedSymbolVisibility_Extern;
}
LNK_DefinedSymbolFlags flags = 0;
if (COFF_SymbolType_IsFunc(type)) {
flags |= LNK_DefinedSymbolFlag_IsFunc;
}
LNK_Chunk *chunk = chunk_ptr_arr[parsed_symbol.section_number-1];
U64 offset = parsed_symbol.value;
COFF_ComdatSelectType selection = COFF_ComdatSelect_Any;
U64 check_sum = 0;
LNK_Chunk *chunk = chunk_ptr_arr[section_number-1];
U64 offset = value;
COFF_ComdatSelectType selection = COFF_ComdatSelectType_ANY;
U64 check_sum = 0;
if (coff_sect_header->flags & COFF_SectionFlag_LNK_COMDAT) {
B32 has_static_def = value == 0 &&
type.u.lsb == COFF_SymType_NULL &&
storage_class == COFF_SymStorageClass_STATIC &&
aux_symbol_count == 1;
if (has_static_def) {
B32 is_comdat = (coff_sect_arr[parsed_symbol.section_number-1].flags & COFF_SectionFlag_LnkCOMDAT) &&
parsed_symbol.value == 0 &&
parsed_symbol.aux_symbol_count > 0 &&
parsed_symbol.type.u.lsb == COFF_SymType_Null &&
parsed_symbol.storage_class == COFF_SymStorageClass_Static;
if (is_comdat) {
COFF_SymbolSecDef *secdef = aux_symbols;
selection = secdef->selection;
check_sum = secdef->check_sum;
if (secdef->selection == COFF_ComdatSelectType_ASSOCIATIVE) {
// create association link between chunks
if (secdef->selection == COFF_ComdatSelect_Associative) {
U32 secdef_number = secdef->number_lo;
// promote secdef number to 32 bits
if (is_big_obj) {
secdef_number |= (U32)secdef->number_hi << 16;
}
if (secdef_number == 0 || secdef_number > sect_count) {
lnk_error(LNK_Error_IllData, "%S: symbol %u has out of bounds section definition number %u", name, symbol_idx, secdef_number);
}
LNK_Chunk *head_chunk = chunk_ptr_arr[secdef_number-1];
LNK_Chunk *associate_chunk = chunk_ptr_arr[section_number-1];
lnk_chunk_associate(arena, head_chunk, associate_chunk);
}
}
}
if (function_pad_min) {
if ((flags & LNK_DefinedSymbolFlag_IsFunc)) {
if (offset > 0) {
// convert leaf to list
//
// there is no way to know up front how many splits we have,
// so lazily convert chunks when see two or more functions
// in a section
if (chunk->type == LNK_Chunk_Leaf) {
// make a list chunk
LNK_Chunk *chunk_list = push_array(arena, LNK_Chunk, 1);
chunk_list->type = LNK_Chunk_List;
chunk_list->align = chunk->align;
chunk_list->is_discarded = chunk->is_discarded;
chunk_list->sort_idx = chunk->sort_idx;
chunk_list->input_idx = chunk->input_idx;
chunk_list->flags = chunk->flags;
chunk_list->associate = chunk->associate;
chunk_list->u.list = push_array(arena, LNK_ChunkList, 1);
lnk_chunk_set_debugf(arena, chunk_list, "%S: function chunk list for %S", obj_path, name);
// reset chunk properties
chunk->align = 1;
chunk->min_size = function_pad_min;
chunk->sort_chunk = 0;
chunk->sort_idx = str8_zero();
chunk->input_idx = 0;
chunk->associate = 0;
// push leaf to list
lnk_chunk_list_push(arena, chunk_list->u.list, chunk);
// set list as target chunk
chunk = chunk_list;
// set list chunk to be head of this section
chunk_ptr_arr[section_number-1] = chunk_list;
}
// find chunk that is near symbol
U64 cursor = 0;
LNK_ChunkNode *current = chunk->u.list->last;
for (LNK_ChunkNode *c = chunk->u.list->first; c != 0; c = c->next) {
Assert(c->data->type == LNK_Chunk_Leaf);
if (cursor + c->data->u.leaf.size > value) {
current = c;
break;
}
cursor += c->data->u.leaf.size;
}
if (cursor < value) {
// bifurcate chunk at symbol offset
U64 split_pos = value - cursor;
Rng1U64 left_data_range = rng_1u64(0, split_pos);
Rng1U64 right_data_range = rng_1u64(left_data_range.max, current->data->u.leaf.size);
String8 left_data = str8_substr(current->data->u.leaf, left_data_range);
String8 right_data = str8_substr(current->data->u.leaf, right_data_range);
// create new chunk for new part
LNK_Chunk *split_chunk = push_array(arena, LNK_Chunk, 1);
split_chunk->align = 1;
split_chunk->is_discarded = current->data->is_discarded;
split_chunk->type = LNK_Chunk_Leaf;
split_chunk->flags = current->data->flags;
split_chunk->u.leaf = right_data;
lnk_chunk_set_debugf(arena, chunk, "%S: chunk split on function %S", obj_path, name);
LNK_ChunkNode *split_node = push_array(arena, LNK_ChunkNode, 1);
split_node->data = split_chunk;
// update split chunk data
current->data->u.leaf = left_data;
// insert split chunk after current chunk
split_node->next = current->next;
current->next = split_node;
chunk->u.list->count += 1;
// point symbol to new split chunk
chunk = split_chunk;
offset = 0;
// associate chunks
if (secdef_number > 0 && secdef_number <= sect_count) {
LNK_Chunk *head_chunk = chunk_ptr_arr[secdef_number-1];
LNK_Chunk *associate_chunk = chunk_ptr_arr[parsed_symbol.section_number-1];
lnk_chunk_associate(head_chunk, associate_chunk);
} else {
// chunk was already split at the offset
chunk = current->data;
offset = value - cursor;
lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "symbol %S (No. %llx) has out of bounds section definition number %u", parsed_symbol.name, symbol_idx, secdef_number);
}
}
chunk->min_size = function_pad_min;
}
// if symbol points to bifurcated section then we have an alias symbol (e.g. memmove is an alias to memcpy)
// and we need to find chunk that is near symbol
if (chunk->type == LNK_Chunk_List) {
U64 cursor = 0;
LNK_Chunk *closest_chunk = chunk->u.list->last->data;
U64 offset_cursor = 0;
for (LNK_ChunkNode *c = chunk->u.list->first; c != 0; c = c->next) {
if (cursor + c->data->u.leaf.size > value) {
chunk = c->data;
offset = offset - cursor;
if (offset_cursor + c->data->u.leaf.size > offset) {
closest_chunk = c->data;
break;
}
cursor += c->data->u.leaf.size;
offset_cursor += c->data->u.leaf.size;
}
Assert(offset >= offset_cursor);
offset -= offset_cursor;
chunk = closest_chunk;
}
}
Assert(chunk->type == LNK_Chunk_Leaf);
Assert(chunk->type == LNK_Chunk_Leaf);
LNK_Symbol *symbol = &symbol_array.v[symbol_idx];
lnk_init_defined_symbol_chunk(symbol, name, visibility, flags, chunk, offset, selection, check_sum);
symbol->obj = obj;
} break;
case COFF_SymbolValueInterp_WEAK: {
if (aux_symbol_count == 0) {
lnk_error(LNK_Error_IllData, "%S: Weak symbol \"%S (%u)\" must at least one aux symbol", obj_path, name, symbol_idx);
}
COFF_SymbolWeakExt *weak_ext = aux_symbols;
if (weak_ext->tag_index >= coff_symbol_count) {
lnk_error(LNK_Error_IllData, "%S: Weak symbol \"%S (%u)\" points to out of bounds symbol", obj_path, name, symbol_idx);
break;
}
lnk_init_defined_symbol_chunk(&symbol_array.v[symbol_idx], parsed_symbol.name, visibility, flags, chunk, offset, selection, check_sum);
symbol_array.v[symbol_idx].obj = obj;
} break;
case COFF_SymbolValueInterp_Weak: {
if (parsed_symbol.aux_symbol_count == 0) {
lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "weak symbol \"%S (%u)\" must at least one aux symbol", parsed_symbol.name, symbol_idx);
}
COFF_SymbolWeakExt *weak_ext = aux_symbols;
if (weak_ext->tag_index >= coff_symbol_count) {
lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "weak symbol \"%S (%u)\" points to out of bounds symbol", parsed_symbol.name, symbol_idx);
}
LNK_Symbol *symbol = &symbol_array.v[symbol_idx];
LNK_Symbol *fallback_symbol = &symbol_array.v[weak_ext->tag_index];
lnk_init_weak_symbol(symbol, name, weak_ext->characteristics, fallback_symbol);
LNK_Symbol *symbol = &symbol_array.v[symbol_idx];
LNK_Symbol *fallback_symbol = &symbol_array.v[weak_ext->tag_index];
lnk_init_weak_symbol(symbol, parsed_symbol.name, weak_ext->characteristics, fallback_symbol);
symbol->obj = obj;
fallback_symbol->obj = obj;
} break;
case COFF_SymbolValueInterp_UNDEFINED: {
LNK_Symbol *symbol = &symbol_array.v[symbol_idx];
lnk_init_undefined_symbol(symbol, name, LNK_SymbolScopeFlag_Main);
symbol->obj = obj;
} break;
case COFF_SymbolValueInterp_COMMON: {
// :common_block
//
// TODO: sort chunks on size to reduce bss usage
LNK_Chunk *chunk = push_array(arena, LNK_Chunk, 1);
chunk->align = Min(32, u64_up_to_pow2(value)); // link.exe caps align at 32 bytes
chunk->type = LNK_Chunk_Leaf;
chunk->flags = master_common_block->flags;
chunk->u.leaf = str8(0, value);
lnk_chunk_set_debugf(arena, chunk, "%S: common block %S", obj_path, name);
lnk_chunk_list_push(arena, master_common_block->u.list, chunk);
symbol->obj = obj;
fallback_symbol->obj = obj;
} break;
case COFF_SymbolValueInterp_Undefined: {
LNK_Symbol *symbol = &symbol_array.v[symbol_idx];
lnk_init_undefined_symbol(symbol, parsed_symbol.name, LNK_SymbolScopeFlag_Main);
symbol->obj = obj;
} break;
case COFF_SymbolValueInterp_Common: {
// :common_block
//
// TODO: sort chunks on size to reduce bss usage
LNK_Chunk *chunk = push_array(arena, LNK_Chunk, 1);
chunk->align = Min(32, u64_up_to_pow2(parsed_symbol.value)); // link.exe caps align at 32 bytes
chunk->type = LNK_Chunk_Leaf;
chunk->flags = master_common_block->flags;
chunk->u.leaf = str8(0, parsed_symbol.value);
lnk_chunk_set_debugf(arena, chunk, "%S: common block %S", obj_path, parsed_symbol.name);
lnk_chunk_list_push(arena, master_common_block->u.list, chunk);
LNK_DefinedSymbolFlags flags = 0;
if (COFF_SymbolType_IsFunc(type)) {
flags |= LNK_DefinedSymbolFlag_IsFunc;
}
LNK_DefinedSymbolFlags flags = 0;
if (COFF_SymbolType_IsFunc(parsed_symbol.type)) {
flags |= LNK_DefinedSymbolFlag_IsFunc;
}
LNK_Symbol *symbol = &symbol_array.v[symbol_idx];
lnk_init_defined_symbol_chunk(symbol, name, LNK_DefinedSymbolVisibility_Extern, flags, chunk, 0, COFF_ComdatSelectType_LARGEST, 0);
symbol->obj = obj;
} break;
case COFF_SymbolValueInterp_ABS: {
// Never code or data, synthetic symbol. COFF spec says bits in value are used
// as flags in symbol @feat.00, other symbols like @comp.id and @vol.md are undocumented.
// LLVM uses undocumented mask 0x4800 on @feat.00 to tell if object was compiled with /guard:cf.
LNK_Symbol *symbol = &symbol_array.v[symbol_idx];
lnk_init_defined_symbol_chunk(symbol, parsed_symbol.name, LNK_DefinedSymbolVisibility_Extern, flags, chunk, 0, COFF_ComdatSelect_Largest, 0);
symbol->obj = obj;
} break;
case COFF_SymbolValueInterp_Abs: {
// Never code or data, synthetic symbol. COFF spec says bits in value are used
// as flags in symbol @feat.00, other symbols like @comp.id and @vol.md are undocumented.
// LLVM uses undocumented mask 0x4800 on @feat.00 to tell if object was compiled with /guard:cf.
LNK_DefinedSymbolVisibility visibility = LNK_DefinedSymbolVisibility_Static;
if (storage_class == COFF_SymStorageClass_EXTERNAL) {
visibility = LNK_DefinedSymbolVisibility_Extern;
}
LNK_DefinedSymbolVisibility visibility = LNK_DefinedSymbolVisibility_Static;
if (parsed_symbol.storage_class == COFF_SymStorageClass_External) {
visibility = LNK_DefinedSymbolVisibility_Extern;
}
LNK_Symbol *symbol = &symbol_array.v[symbol_idx];
lnk_init_defined_symbol_va(symbol, name, visibility, 0, value);
symbol->obj = obj;
} break;
case COFF_SymbolValueInterp_DEBUG: break;
LNK_Symbol *symbol = &symbol_array.v[symbol_idx];
lnk_init_defined_symbol_va(symbol, parsed_symbol.name, visibility, 0, parsed_symbol.value);
symbol->obj = obj;
} break;
case COFF_SymbolValueInterp_Debug: {
} break;
}
// skip aux symbols
symbol_idx += aux_symbol_count;
}
return symbol_array;
@@ -1030,8 +1024,8 @@ lnk_reloc_list_array_from_coff(Arena *arena, COFF_MachineType machine, String8 c
{
LNK_RelocList *reloc_list_arr = push_array_no_zero(arena, LNK_RelocList, sect_count);
for (U64 sect_idx = 0; sect_idx < sect_count; ++sect_idx) {
COFF_SectionHeader *coff_header = &coff_sect_arr[sect_idx];
COFF_RelocInfo coff_reloc_info = coff_reloc_info_from_section_header(coff_data, coff_header);
COFF_SectionHeader *COFF_FileHeader = &coff_sect_arr[sect_idx];
COFF_RelocInfo coff_reloc_info = coff_reloc_info_from_section_header(coff_data, COFF_FileHeader);
COFF_Reloc *coff_reloc_v = (COFF_Reloc *)(coff_data.str + coff_reloc_info.array_off);
LNK_Chunk *sect_chunk = chunk_ptr_arr[sect_idx];
reloc_list_arr[sect_idx] = lnk_reloc_list_from_coff_reloc_array(arena, machine, sect_chunk, symbol_array, coff_reloc_v, coff_reloc_info.count);
@@ -1039,30 +1033,108 @@ lnk_reloc_list_array_from_coff(Arena *arena, COFF_MachineType machine, String8 c
return reloc_list_arr;
}
internal void
lnk_parse_msvc_linker_directive(Arena *arena, String8 obj_path, String8 lib_path, LNK_DirectiveInfo *directive_info, String8 buffer)
{
Temp scratch = scratch_begin(&arena, 1);
local_persist B32 init_table = 1;
local_persist B8 is_legal[LNK_CmdSwitch_Count];
if (init_table) {
init_table = 0;
is_legal[LNK_CmdSwitch_AlternateName] = 1;
is_legal[LNK_CmdSwitch_DefaultLib] = 1;
is_legal[LNK_CmdSwitch_DisallowLib] = 1;
is_legal[LNK_CmdSwitch_EditAndContinue] = 1;
is_legal[LNK_CmdSwitch_Entry] = 1;
is_legal[LNK_CmdSwitch_Export] = 1;
is_legal[LNK_CmdSwitch_FailIfMismatch] = 1;
is_legal[LNK_CmdSwitch_GuardSym] = 1;
is_legal[LNK_CmdSwitch_Include] = 1;
is_legal[LNK_CmdSwitch_InferAsanLibs] = 1;
is_legal[LNK_CmdSwitch_InferAsanLibsNo] = 1;
is_legal[LNK_CmdSwitch_ManifestDependency] = 1;
is_legal[LNK_CmdSwitch_Merge] = 1;
is_legal[LNK_CmdSwitch_NoDefaultLib] = 1;
is_legal[LNK_CmdSwitch_Release] = 1;
is_legal[LNK_CmdSwitch_Section] = 1;
is_legal[LNK_CmdSwitch_Stack] = 1;
is_legal[LNK_CmdSwitch_SubSystem] = 1;
is_legal[LNK_CmdSwitch_ThrowingNew] = 1;
}
String8 to_parse;
{
local_persist const U8 bom_sig[] = { 0xEF, 0xBB, 0xBF };
local_persist const U8 ascii_sig[] = { 0x20, 0x20, 0x20 };
if (MemoryMatch(buffer.str, &bom_sig[0], sizeof(bom_sig))) {
to_parse = str8_zero();
lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "TODO: support for BOM encoding");
} else if (MemoryMatch(buffer.str, &ascii_sig[0], sizeof(ascii_sig))) {
to_parse = str8_skip(buffer, sizeof(ascii_sig));
} else {
to_parse = buffer;
}
}
String8List arg_list = lnk_arg_list_parse_windows_rules(scratch.arena, to_parse);
LNK_CmdLine cmd_line = lnk_cmd_line_parse_windows_rules(scratch.arena, arg_list);
for (LNK_CmdOption *opt = cmd_line.first_option; opt != 0; opt = opt->next) {
LNK_CmdSwitchType type = lnk_cmd_switch_type_from_string(opt->string);
if (type == LNK_CmdSwitch_Null) {
lnk_error_with_loc(LNK_Warning_UnknownDirective, obj_path, lib_path, "unknown directive \"%S\"", opt->string);
continue;
}
if (!is_legal[type]) {
lnk_error_with_loc(LNK_Warning_IllegalDirective, obj_path, lib_path, "illegal directive \"%S\"", opt->string);
continue;
}
LNK_Directive *directive = push_array_no_zero(arena, LNK_Directive, 1);
directive->next = 0;
directive->id = push_str8_copy(arena, opt->string);
directive->value_list = str8_list_copy(arena, &opt->value_strings);
LNK_DirectiveList *directive_list = &directive_info->v[type];
SLLQueuePush(directive_list->first, directive_list->last, directive);
++directive_list->count;
}
scratch_end(scratch);
}
internal LNK_DirectiveInfo
lnk_init_directives(Arena *arena, String8 obj_path, U64 chunk_count, String8 *sect_name_arr, LNK_Chunk *chunk_arr)
lnk_directive_info_from_sections(Arena *arena,
String8 obj_path,
String8 lib_path,
U64 chunk_count,
LNK_RelocList *reloc_list_arr,
String8 *sect_name_arr,
LNK_Chunk *chunk_arr)
{
LNK_DirectiveInfo directive_info = {0};
for (U64 chunk_idx = 0; chunk_idx < chunk_count; chunk_idx += 1) {
for (U64 chunk_idx = 0; chunk_idx < chunk_count; ++chunk_idx) {
String8 sect_name = sect_name_arr[chunk_idx];
LNK_Chunk *sect_chunk = &chunk_arr[chunk_idx];
Assert(sect_chunk->type == LNK_Chunk_Leaf);
if (!str8_match(sect_name, str8_lit(".drectve"), 0)) {
continue;
LNK_Chunk *sect_chunk = chunk_arr + chunk_idx;
if (str8_match_lit(".drectve", sect_name, 0)) {
if (sect_chunk->type == LNK_Chunk_Leaf) {
if (sect_chunk->u.leaf.size >= 3) {
if (~sect_chunk->flags & COFF_SectionFlag_LnkInfo) {
lnk_error_with_loc(LNK_Warning_IllData, obj_path, lib_path, "%S missing COFF_SectionFlag_LnkInfo", sect_name);
}
if (reloc_list_arr[chunk_idx].count > 0) {
lnk_error_with_loc(LNK_Warning_DirectiveSectionWithRelocs, obj_path, lib_path, "directive section %S(%#x) has relocations", sect_name, (chunk_idx+1));
}
lnk_parse_msvc_linker_directive(arena, obj_path, lib_path, &directive_info, sect_chunk->u.leaf);
} else {
lnk_error_with_loc(LNK_Warning_IllData, obj_path, lib_path, "unable to parse %S", sect_name);
}
} else {
Assert(!"linker directive section chunk must be of leaf type");
}
}
if (sect_chunk->u.leaf.size < 3) {
lnk_error(LNK_Warning_IllData, "%S: can't parse %S", obj_path, sect_name);
continue;
}
if (~sect_chunk->flags & COFF_SectionFlag_LNK_INFO) {
lnk_error(LNK_Warning_IllData, "%S: %S missing COFF_SectionFlag_LNK_INFO.", obj_path, sect_name);
}
// TODO: warn if section has relocations
lnk_parse_directives(arena, &directive_info, sect_chunk->u.leaf, obj_path);
int bad_vs = 0; (void)bad_vs;
}
return directive_info;
}
+23 -2
View File
@@ -25,6 +25,27 @@ typedef struct LNK_InputObjList
////////////////////////////////
typedef struct LNK_Directive
{
struct LNK_Directive *next;
String8 id;
String8List value_list;
} LNK_Directive;
typedef struct LNK_DirectiveList
{
U64 count;
LNK_Directive *first;
LNK_Directive *last;
} LNK_DirectiveList;
typedef struct LNK_DirectiveInfo
{
LNK_DirectiveList v[LNK_CmdSwitch_Count];
} LNK_DirectiveInfo;
////////////////////////////////
#define LNK_MakeChunkInputIdx(obj_idx, sect_idx) (((U64)(obj_idx) << 32) | (U64)((sect_idx) & max_U32))
typedef struct LNK_Obj
@@ -181,10 +202,10 @@ internal LNK_ChunkList * lnk_collect_obj_chunks(TP_Context *tp, TP_Arena *arena
internal LNK_ObjNodeArray lnk_obj_list_push_parallel(TP_Context *tp, TP_Arena *tp_arena, LNK_ObjList *obj_list, LNK_SectionTable *st, U64 *function_pad_min, U64 input_count, LNK_InputObj **inputs);
internal LNK_Chunk * lnk_sect_chunk_array_from_coff(Arena *arena, U64 obj_id, String8 obj_path, String8 coff_data, U64 sect_count, COFF_SectionHeader *coff_sect_arr, String8 *sect_name_arr, String8 *sect_postfix_arr);
internal LNK_SymbolArray lnk_symbol_array_from_coff(Arena *arena, String8 coff_data, LNK_Obj *obj, String8 obj_path, B32 is_big_obj, U64 function_pad_min, U64 string_table_off, U64 sect_count, COFF_SectionHeader *coff_sect_arr, U64 coff_symbol_count, void *coff_symbols, LNK_ChunkPtr *chunk_ptr_arr, LNK_Chunk *master_common_block);
internal LNK_SymbolArray lnk_symbol_array_from_coff(Arena *arena, String8 coff_data, LNK_Obj *obj, String8 obj_path, String8 lib_path, B32 is_big_obj, U64 function_pad_min, U64 string_table_off, U64 sect_count, COFF_SectionHeader *coff_sect_arr, U64 coff_symbol_count, void *coff_symbols, LNK_ChunkPtr *chunk_ptr_arr, LNK_Chunk *master_common_block);
internal LNK_RelocList lnk_reloc_list_from_coff_reloc_array(Arena *arena, COFF_MachineType machine, LNK_Chunk *chunk, LNK_SymbolArray symbol_array, COFF_Reloc *reloc_v, U64 reloc_count);
internal LNK_RelocList * lnk_reloc_list_array_from_coff(Arena *arena, COFF_MachineType machine, String8 coff_data, U64 sect_count, COFF_SectionHeader *coff_sect_arr, LNK_ChunkPtr *chunk_ptr_arr, LNK_SymbolArray symbol_array);
internal LNK_DirectiveInfo lnk_init_directives(Arena *arena, String8 obj_path, U64 chunk_count, String8 *sect_name_arr, LNK_Chunk *chunk_arr);
internal LNK_DirectiveInfo lnk_directive_info_from_sections(Arena *arena, String8 obj_path, String8 lib_path, U64 chunk_count, LNK_RelocList *reloc_list_arr, String8 *sect_name_arr, LNK_Chunk *chunk_arr);
internal U32 lnk_obj_get_features(LNK_Obj *obj);
internal U32 lnk_obj_get_comp_id(LNK_Obj *obj);
+35 -33
View File
@@ -77,18 +77,20 @@ lnk_reloc_list_from_coff_reloc_array(Arena *arena, COFF_MachineType machine, LNK
LNK_Symbol *symbol = symbol_array.v + coff_reloc_ptr->isymbol;
if (chunk->type == LNK_Chunk_List) {
reloc_chunk = chunk->u.list->last->data;
U64 cursor = 0;
for (LNK_ChunkNode *c = chunk->u.list->first; c != 0; c = c->next) {
Assert(c->data->type == LNK_Chunk_Leaf);
if (coff_reloc_ptr->apply_off < cursor + c->data->u.leaf.size) {
reloc_chunk = c->data;
apply_off = coff_reloc_ptr->apply_off - cursor;
break;
}
cursor += c->data->u.leaf.size;
}
apply_off = coff_reloc_ptr->apply_off - cursor;
}
Assert(reloc_chunk->type == LNK_Chunk_Leaf);
Assert(coff_reloc_ptr->isymbol < symbol_array.count);
reloc_ptr->chunk = reloc_chunk;
reloc_ptr->type = type;
@@ -115,26 +117,26 @@ lnk_ext_reloc_type_from_coff(COFF_MachineType machine, U32 type)
{
LNK_RelocType result = LNK_Reloc_NULL;
switch (machine) {
case COFF_MachineType_UNKNOWN: break;
case COFF_MachineType_X64: {
case COFF_Machine_Unknown: break;
case COFF_Machine_X64: {
switch (type) {
case COFF_RelocTypeX64_ABS: result = LNK_Reloc_NULL; break;
case COFF_RelocTypeX64_ADDR64: result = LNK_Reloc_ADDR_64; break;
case COFF_RelocTypeX64_ADDR32: result = LNK_Reloc_ADDR_32; break;
case COFF_RelocTypeX64_ADDR32NB: result = LNK_Reloc_VIRT_OFF_32; break;
case COFF_RelocTypeX64_REL32: result = LNK_Reloc_REL32; break;
case COFF_RelocTypeX64_REL32_1: result = LNK_Reloc_REL32_1; break;
case COFF_RelocTypeX64_REL32_2: result = LNK_Reloc_REL32_2; break;
case COFF_RelocTypeX64_REL32_3: result = LNK_Reloc_REL32_3; break;
case COFF_RelocTypeX64_REL32_4: result = LNK_Reloc_REL32_4; break;
case COFF_RelocTypeX64_REL32_5: result = LNK_Reloc_REL32_5; break;
case COFF_RelocTypeX64_SECTION: result = LNK_Reloc_SECT_IDX; break;
case COFF_RelocTypeX64_SECREL: result = LNK_Reloc_SECT_REL; break;
case COFF_RelocTypeX64_SECREL7: lnk_not_implemented("TODO: COFF_RelocTypeX64_SECREL7"); break;
case COFF_RelocTypeX64_TOKEN: lnk_not_implemented("TODO: COFF_RelocTypeX64_TOKEN"); break;
case COFF_RelocTypeX64_SREL32: lnk_not_implemented("TODO: COFF_RelocTypeX64_SREL32"); break;
case COFF_RelocTypeX64_PAIR: lnk_not_implemented("TODO: COFF_RelocTypeX64_PAIR"); break;
case COFF_RelocTypeX64_SSPAN32: lnk_not_implemented("TODO: COFF_RelocTypeX64_SSPAN32"); break;
case COFF_Reloc_X64_Abs: result = LNK_Reloc_NULL; break;
case COFF_Reloc_X64_Addr64: result = LNK_Reloc_ADDR_64; break;
case COFF_Reloc_X64_Addr32: result = LNK_Reloc_ADDR_32; break;
case COFF_Reloc_X64_Addr32Nb: result = LNK_Reloc_VIRT_OFF_32; break;
case COFF_Reloc_X64_Rel32: result = LNK_Reloc_REL32; break;
case COFF_Reloc_X64_Rel32_1: result = LNK_Reloc_REL32_1; break;
case COFF_Reloc_X64_Rel32_2: result = LNK_Reloc_REL32_2; break;
case COFF_Reloc_X64_Rel32_3: result = LNK_Reloc_REL32_3; break;
case COFF_Reloc_X64_Rel32_4: result = LNK_Reloc_REL32_4; break;
case COFF_Reloc_X64_Rel32_5: result = LNK_Reloc_REL32_5; break;
case COFF_Reloc_X64_Section: result = LNK_Reloc_SECT_IDX; break;
case COFF_Reloc_X64_SecRel: result = LNK_Reloc_SECT_REL; break;
case COFF_Reloc_X64_SecRel7: lnk_not_implemented("TODO: COFF_Reloc_X64_SecRel7"); break;
case COFF_Reloc_X64_Token: lnk_not_implemented("TODO: COFF_Reloc_X64_Token"); break;
case COFF_Reloc_X64_SRel32: lnk_not_implemented("TODO: COFF_Reloc_X64_SRel32"); break;
case COFF_Reloc_X64_Pair: lnk_not_implemented("TODO: COFF_Reloc_X64_Pair"); break;
case COFF_Reloc_X64_SSpan32: lnk_not_implemented("TODO: COFF_Reloc_X64_SSpan32"); break;
default: lnk_invalid_path("unknown relocation type 0x%X", type);
}
} break;
@@ -148,20 +150,20 @@ lnk_ext_reloc_type_to_coff(COFF_MachineType machine, LNK_RelocType type)
{
U32 result = 0;
switch (machine) {
case COFF_MachineType_X64: {
case COFF_Machine_X64: {
switch (type) {
case LNK_Reloc_NULL: result = COFF_RelocTypeX64_ABS; break;
case LNK_Reloc_ADDR_64: result = COFF_RelocTypeX64_ADDR64; break;
case LNK_Reloc_ADDR_32: result = COFF_RelocTypeX64_ADDR32; break;
case LNK_Reloc_VIRT_OFF_32: result = COFF_RelocTypeX64_ADDR32NB; break;
case LNK_Reloc_REL32: result = COFF_RelocTypeX64_REL32; break;
case LNK_Reloc_REL32_1: result = COFF_RelocTypeX64_REL32_1; break;
case LNK_Reloc_REL32_2: result = COFF_RelocTypeX64_REL32_2; break;
case LNK_Reloc_REL32_3: result = COFF_RelocTypeX64_REL32_3; break;
case LNK_Reloc_REL32_4: result = COFF_RelocTypeX64_REL32_4; break;
case LNK_Reloc_REL32_5: result = COFF_RelocTypeX64_REL32_5; break;
case LNK_Reloc_SECT_IDX: result = COFF_RelocTypeX64_SECTION; break;
case LNK_Reloc_SECT_REL: result = COFF_RelocTypeX64_SECREL; break;
case LNK_Reloc_NULL: result = COFF_Reloc_X64_Abs; break;
case LNK_Reloc_ADDR_64: result = COFF_Reloc_X64_Addr64; break;
case LNK_Reloc_ADDR_32: result = COFF_Reloc_X64_Addr32; break;
case LNK_Reloc_VIRT_OFF_32: result = COFF_Reloc_X64_Addr32Nb; break;
case LNK_Reloc_REL32: result = COFF_Reloc_X64_Rel32; break;
case LNK_Reloc_REL32_1: result = COFF_Reloc_X64_Rel32_1; break;
case LNK_Reloc_REL32_2: result = COFF_Reloc_X64_Rel32_2; break;
case LNK_Reloc_REL32_3: result = COFF_Reloc_X64_Rel32_3; break;
case LNK_Reloc_REL32_4: result = COFF_Reloc_X64_Rel32_4; break;
case LNK_Reloc_REL32_5: result = COFF_Reloc_X64_Rel32_5; break;
case LNK_Reloc_SECT_IDX: result = COFF_Reloc_X64_Section; break;
case LNK_Reloc_SECT_REL: result = COFF_Reloc_X64_SecRel; break;
default: InvalidPath;
}
} break;
+18 -18
View File
@@ -85,16 +85,16 @@ lnk_make_section_sort_index(Arena *arena, String8 name, COFF_SectionFlags flags,
// pack sections with run-time data closer
String8List sort_index_list = {0};
if (flags & COFF_SectionFlag_MEM_DISCARDABLE) {
if (flags & COFF_SectionFlag_MemDiscardable) {
str8_list_pushf(scratch.arena, &sort_index_list, "b");
} else {
str8_list_pushf(scratch.arena, &sort_index_list, "a");
}
if (str8_match(name, str8_lit(".null"), 0)) {
if (str8_match_lit(".null", name, 0)) {
// null section always first
str8_list_pushf(scratch.arena, &sort_index_list, "a");
} else if (str8_match(name, str8_lit(".rsrc"), 0)) {
} else if (str8_match_lit(".rsrc", name, 0)) {
// section with resource data must be last because during runtime windows might append pages
str8_list_pushf(scratch.arena, &sort_index_list, "c");
} else {
@@ -102,32 +102,32 @@ lnk_make_section_sort_index(Arena *arena, String8 name, COFF_SectionFlags flags,
}
// sort sections based on the contents
if (flags & COFF_SectionFlag_CNT_CODE) {
if (flags & COFF_SectionFlag_CntCode) {
str8_list_pushf(scratch.arena, &sort_index_list, "a");
if (str8_match(name, str8_lit(".text"), 0)) {
if (str8_match_lit(".text", name, 0)) {
str8_list_pushf(scratch.arena, &sort_index_list, "a");
} else {
str8_list_pushf(scratch.arena, &sort_index_list, "b");
}
} else if (flags & COFF_SectionFlag_CNT_INITIALIZED_DATA) {
} else if (flags & COFF_SectionFlag_CntInitializedData) {
str8_list_pushf(scratch.arena, &sort_index_list, "b");
if (str8_match(name, str8_lit(".data"), 0)) {
if (str8_match_lit(".data", name, 0)) {
str8_list_pushf(scratch.arena, &sort_index_list, "a");
} else if (str8_match(name, str8_lit(".rdata"), 0)) {
} else if (str8_match_lit(".rdata", name, 0)) {
str8_list_pushf(scratch.arena, &sort_index_list, "b");
} else if (str8_match(name, str8_lit(".tls"), 0)) {
} else if (str8_match_lit(".tls", name, 0)) {
str8_list_pushf(scratch.arena, &sort_index_list, "c");
} else {
str8_list_pushf(scratch.arena, &sort_index_list, "d");
}
} else if (flags & COFF_SectionFlag_CNT_UNINITIALIZED_DATA) {
} else if (flags & COFF_SectionFlag_CntUninitializedData) {
str8_list_pushf(scratch.arena, &sort_index_list, "c");
} else {
str8_list_pushf(scratch.arena, &sort_index_list, "d");
}
// sort sections based on read/write access so final section layout looks cleaner
if (flags & COFF_SectionFlag_MEM_READ && ~flags & COFF_SectionFlag_MEM_WRITE) {
if (flags & COFF_SectionFlag_MemRead && ~flags & COFF_SectionFlag_MemWrite) {
str8_list_pushf(scratch.arena, &sort_index_list, "a");
} else {
str8_list_pushf(scratch.arena, &sort_index_list, "b");
@@ -145,7 +145,7 @@ lnk_make_section_sort_index(Arena *arena, String8 name, COFF_SectionFlags flags,
internal void
lnk_section_associate_chunks(LNK_Section *sect, LNK_Chunk *head, LNK_Chunk *associate)
{
lnk_chunk_associate(sect->arena, head, associate);
lnk_chunk_associate(head, associate);
}
internal LNK_Chunk *
@@ -236,8 +236,8 @@ lnk_code_align_byte_from_machine(COFF_MachineType machine)
{
U8 align_byte = 0;
switch (machine) {
case COFF_MachineType_X64:
case COFF_MachineType_X86: {
case COFF_Machine_X64:
case COFF_Machine_X86: {
align_byte = 0xCC;
} break;
default: {
@@ -570,7 +570,7 @@ lnk_section_table_assign_file_offsets(LNK_SectionTable *st)
U64 cursor = 0;
for (LNK_SectionNode *sect_node = st->list.first; sect_node != NULL; sect_node = sect_node->next) {
LNK_Section *sect = &sect_node->data;
if (sect->flags & COFF_SectionFlag_CNT_UNINITIALIZED_DATA) {
if (sect->flags & COFF_SectionFlag_CntUninitializedData) {
continue;
}
if (!sect->has_layout) continue;
@@ -617,7 +617,7 @@ lnk_section_table_serialize(TP_Context *tp, Arena *arena, LNK_SectionTable *st,
for (LNK_SectionNode *sect_n = st->list.first; sect_n != 0; sect_n = sect_n->next) {
LNK_Section *sect = &sect_n->data;
if (sect->has_layout) {
if (sect->flags & COFF_SectionFlag_CNT_UNINITIALIZED_DATA) {
if (sect->flags & COFF_SectionFlag_CntUninitializedData) {
continue;
}
@@ -625,7 +625,7 @@ lnk_section_table_serialize(TP_Context *tp, Arena *arena, LNK_SectionTable *st,
String8 sect_data = str8_substr(image, rng_1u64(image_cursor, image_cursor + sect_size));
U8 fill_byte = 0;
if (sect->flags & COFF_SectionFlag_CNT_CODE) {
if (sect->flags & COFF_SectionFlag_CntCode) {
fill_byte = lnk_code_align_byte_from_machine(machine);
}
@@ -888,7 +888,7 @@ lnk_dump_chunks(LNK_SectionTable *st)
LNK_Section *sect = sect_id_map[sect_id];
if (!sect) continue;
if (sect->is_merged) continue;
if (str8_match(sect->name, str8_lit(".text"), 0)) {
if (str8_match_lit(".text", sect->name, 0)) {
for (U64 chunk_id = 0; chunk_id < sect->cman->total_chunk_count; ++chunk_id) {
LNK_ChunkRef chunk_ref = { sect_id, chunk_id };
LNK_Chunk *chunk = lnk_chunk_from_chunk_ref(sect_id_map, chunk_id_map, chunk_ref);
+12 -12
View File
@@ -271,17 +271,17 @@ lnk_can_replace_symbol(const LNK_Symbol *dst, const LNK_Symbol *src)
COFF_ComdatSelectType src_select = src_defn->u.selection;
// handle objs compiled with /GR- and /GR
if ((src_select == COFF_ComdatSelectType_ANY && dst_select == COFF_ComdatSelectType_LARGEST) ||
(src_select == COFF_ComdatSelectType_LARGEST && dst_select == COFF_ComdatSelectType_ANY)) {
dst_select = COFF_ComdatSelectType_LARGEST;
src_select = COFF_ComdatSelectType_LARGEST;
if ((src_select == COFF_ComdatSelect_Any && dst_select == COFF_ComdatSelect_Largest) ||
(src_select == COFF_ComdatSelect_Largest && dst_select == COFF_ComdatSelect_Any)) {
dst_select = COFF_ComdatSelect_Largest;
src_select = COFF_ComdatSelect_Largest;
}
if (src_select == dst_select) {
switch (src_select) {
default: InvalidPath;
case COFF_ComdatSelectType_NULL:
case COFF_ComdatSelectType_ANY: {
case COFF_ComdatSelect_Null:
case COFF_ComdatSelect_Any: {
LNK_Chunk *dst_chunk = dst_defn->u.chunk;
LNK_Chunk *src_chunk = src_defn->u.chunk;
U64 dst_chunk_size = lnk_chunk_get_size(dst_chunk);
@@ -293,10 +293,10 @@ lnk_can_replace_symbol(const LNK_Symbol *dst, const LNK_Symbol *src)
can_replace = src_chunk_size < dst_chunk_size;
}
} break;
case COFF_ComdatSelectType_NODUPLICATES: {
case COFF_ComdatSelect_NoDuplicates: {
lnk_error_obj(LNK_Error_MultiplyDefinedSymbol, src->obj, "multiply defined symbol %S in %S.", dst->name, dst->obj->path);
} break;
case COFF_ComdatSelectType_SAME_SIZE: {
case COFF_ComdatSelect_SameSize: {
LNK_Chunk *dst_chunk = dst_defn->u.chunk;
LNK_Chunk *src_chunk = src_defn->u.chunk;
U64 dst_chunk_size = lnk_chunk_get_size(dst_chunk);
@@ -306,13 +306,13 @@ lnk_can_replace_symbol(const LNK_Symbol *dst, const LNK_Symbol *src)
lnk_error_obj(LNK_Error_MultiplyDefinedSymbol, src->obj, "multiply defined symbol %S in %S.", dst->name, dst->obj->path);
}
} break;
case COFF_ComdatSelectType_EXACT_MATCH: {
case COFF_ComdatSelect_ExactMatch: {
B32 is_exact_match = (dst_defn->u.check_sum == src_defn->u.check_sum);
if (!is_exact_match) {
lnk_error_obj(LNK_Error_MultiplyDefinedSymbol, src->obj, "multiply defined symbol %S in %S.", dst->name, dst->obj->path);
}
} break;
case COFF_ComdatSelectType_LARGEST: {
case COFF_ComdatSelect_Largest: {
LNK_Chunk *dst_chunk = dst_defn->u.chunk;
LNK_Chunk *src_chunk = src_defn->u.chunk;
U64 dst_chunk_size = lnk_chunk_get_size(dst_chunk);
@@ -330,7 +330,7 @@ lnk_can_replace_symbol(const LNK_Symbol *dst, const LNK_Symbol *src)
can_replace = dst_chunk_size < src_chunk_size;
}
} break;
case COFF_ComdatSelectType_ASSOCIATIVE: {
case COFF_ComdatSelect_Associative: {
// ignore
} break;
}
@@ -630,7 +630,7 @@ lnk_symbol_table_push_weak(LNK_SymbolTable *symtab, String8 weak_name, COFF_Weak
weak_name = push_str8_copy(symtab->arena->v[0], weak_name);
strong_name = push_str8_copy(symtab->arena->v[0], strong_name);
LNK_Symbol *strong_symbol = lnk_make_undefined_symbol(symtab->arena->v[0], strong_name, LNK_SymbolScopeFlag_Main);
LNK_Symbol *weak_symbol = lnk_make_weak_symbol(symtab->arena->v[0], weak_name, COFF_WeakExtType_SEARCH_ALIAS, strong_symbol);
LNK_Symbol *weak_symbol = lnk_make_weak_symbol(symtab->arena->v[0], weak_name, COFF_WeakExt_SearchAlias, strong_symbol);
lnk_symbol_table_push(symtab, weak_symbol);
return weak_symbol;
}
-17
View File
@@ -9,23 +9,6 @@ make_file_name_with_ext(Arena *arena, String8 file_name, String8 ext)
return result;
}
internal String8
make_file_path_with_ext(Arena *arena, String8 file_name, String8 ext)
{
Temp scratch = scratch_begin(&arena, 1);
String8 curr = os_get_current_path(scratch.arena);
String8 name = make_file_name_with_ext(scratch.arena, str8_skip_last_slash(file_name), ext);
String8List list = {0};
str8_list_push(scratch.arena, &list, curr);
str8_list_push(scratch.arena, &list, name);
String8 result = str8_path_list_join_by_style(arena, &list, PathStyle_SystemAbsolute);
scratch_end(scratch);
return result;
}
internal String8
path_char_from_style(PathStyle style)
{
-1
View File
@@ -4,7 +4,6 @@
#pragma once
internal String8 make_file_name_with_ext(Arena *arena, String8 file_name, String8 ext);
internal String8 make_file_path_with_ext(Arena *arena, String8 file_name, String8 ext);
internal String8 path_convert_slashes(Arena *arena, String8 path, PathStyle path_style);
internal String8 path_canon_from_regular_path(Arena *arena, String8 path);
internal PathStyle path_style_from_string(String8 string);
+43 -42
View File
@@ -2131,55 +2131,57 @@ gsi_release(PDB_GsiContext **gsi_ptr)
}
internal void
gsi_write_build_result(TP_Context *tp, PDB_GsiBuildResult build, MSF_Context *msf, MSF_StreamNumber gsi_sn, MSF_StreamNumber symbols_sn)
gsi_write_build_result(TP_Context *tp,
PDB_GsiBuildResult build,
MSF_Context *msf,
MSF_StreamNumber gsi_sn,
MSF_StreamNumber symbols_sn)
{
ProfBeginFunction();
// reserve stream memory
U64 hash_record_arr_size = sizeof(build.hash_record_arr[0]) * build.hash_record_count;
U64 bitmap_size = sizeof(build.bitmap[0]) * build.bitmap_count;
U64 hash_record_arr_size = sizeof(build.hash_record_arr[0]) * build.hash_record_count;
U64 bitmap_size = sizeof(build.bitmap[0]) * build.bitmap_count;
U64 compressed_bucket_arr_size = sizeof(build.compressed_bucket_arr[0]) * build.compressed_bucket_count;
U64 gsi_size = sizeof(build.header) + hash_record_arr_size + bitmap_size + compressed_bucket_arr_size;
ProfBegin("GSI Reserve");
ProfBeginV("Reserve %M for GSI hash table", gsi_size);
msf_stream_reserve(msf, gsi_sn, gsi_size);
ProfEnd();
ProfBegin("Symbol Data Reserve");
ProfBeginV("Reserve %M for symbols", build.symbol_data.size);
msf_stream_reserve(msf, symbols_sn, build.symbol_data.size);
ProfEnd();
// write gsi stream
ProfBegin("Write GSI header");
msf_stream_write_struct(msf, gsi_sn, &build.header);
ProfEnd();
ProfBegin("Hash Record Write");
ProfBegin("Write hash records [%M]", hash_record_arr_size);
msf_stream_write_parallel(tp, msf, gsi_sn, &build.hash_record_arr[0], hash_record_arr_size);
ProfEnd();
ProfBegin("Bitmap Write");
ProfBeginV("Write bucket bitmap [%M]", bitmap_size);
msf_stream_write(msf, gsi_sn, &build.bitmap[0], bitmap_size);
ProfEnd();
ProfBegin("Compressed Bucket Write");
ProfBegin("Write buckets [%M]", compressed_bucket_arr_size);
msf_stream_write(msf, gsi_sn, &build.compressed_bucket_arr[0], compressed_bucket_arr_size);
ProfEnd();
// write symbol stream
ProfBegin("Symbol Data Write");
ProfBegin("Write symbols [%M]", build.symbol_data.size);
msf_stream_write_string_parallel(tp, msf, symbols_sn, build.symbol_data);
ProfEnd();
ProfEnd();
}
int
gsi_hash_record_compar_is_before(void *a_, void *b_)
internal int
gsi_hash_record_compar_is_before(void *raw_a, void *raw_b)
{
PDB_GsiSortRecord *a = (PDB_GsiSortRecord*)a_;
PDB_GsiSortRecord *b = (PDB_GsiSortRecord*)b_;
PDB_GsiSortRecord *a = raw_a;
PDB_GsiSortRecord *b = raw_b;
int is_before;
if (a->name.size != b->name.size) {
is_before = a->name.size < b->name.size;
} else {
@@ -2193,20 +2195,19 @@ gsi_hash_record_compar_is_before(void *a_, void *b_)
return is_before;
}
int
psi_addr_map_compar_is_before(void *a_, void *b_)
internal int
psi_addr_map_compar_is_before(void *raw_a, void *raw_b)
{
PDB_GsiSortRecord *a = (PDB_GsiSortRecord*)a_;
PDB_GsiSortRecord *b = (PDB_GsiSortRecord*)b_;
PDB_GsiSortRecord *a = raw_a;
PDB_GsiSortRecord *b = raw_b;
int is_before;
if (a->isect_off.isect != b->isect_off.isect) {
is_before = a->isect_off.isect < b->isect_off.isect;
} else if (a->isect_off.off != b->isect_off.off) {
is_before = a->isect_off.off < b->isect_off.off;
} else {
is_before = a->name.size < b->name.size;
is_before = str8_compar_case_sensitive(&a->name, &b->name);
}
return is_before;
@@ -2231,9 +2232,9 @@ gsi_record_sort_by_sc(PDB_GsiSortRecord *arr, U64 count)
internal
THREAD_POOL_TASK_FUNC(gsi_size_buckets_task)
{
U64 bucket_idx = task_id;
PDB_GsiSerializeSymbolsTask *task = raw_task;
CV_SymbolList *bucket_list = &task->bucket_arr[bucket_idx];
U64 bucket_idx = task_id;
PDB_GsiSerializeSymbolsTask *task = raw_task;
CV_SymbolList *bucket_list = &task->bucket_arr[bucket_idx];
for (CV_SymbolNode *node = bucket_list->first; node != 0; node = node->next) {
task->bucket_size_arr[bucket_idx] += cv_compute_symbol_record_size(&node->data, task->symbol_align);
}
@@ -2258,16 +2259,16 @@ THREAD_POOL_TASK_FUNC(gsi_serialize_pub32)
CV_Symbol *symbol = &node->data;
Assert(symbol->kind == CV_SymKind_PUB32);
CV_SymPub32 *pub32 = (CV_SymPub32 *)symbol->data.str;
U8 *str_ptr = (U8 *)(pub32 + 1);
U64 str_size = symbol->data.size - sizeof(*pub32);
String8 name = str8(str_ptr, str_size);
CV_SymPub32 *pub32 = (CV_SymPub32 *)symbol->data.str;
U8 *str_ptr = (U8 *)(pub32 + 1);
U64 str_size = symbol->data.size - sizeof(*pub32);
String8 name = str8(str_ptr, str_size);
// init sort record
PDB_GsiSortRecord *sr = &sort_record_arr[sort_idx];
sr->isect_off = isect_off(pub32->sec, pub32->off);
sr->name = name;
sr->offset = buffer_cursor;
sr->isect_off = isect_off(pub32->sec, pub32->off);
sr->name = name;
sr->offset = buffer_cursor;
// serialize symbol
U64 serial_size = cv_serialize_symbol_to_buffer(buffer, buffer_cursor, buffer_size, symbol, task->symbol_align);
@@ -3269,21 +3270,21 @@ dbi_build_sec_map(Arena *arena, PDB_DbiContext *dbi)
U64 isect = 0;
for (PDB_DbiSectionNode *sect = dbi->section_list.first; sect; sect = sect->next, ++isect) {
PDB_DbiSecMapEntry *s = &entry_array[isect];
COFF_SectionHeader *coff_header = &sect->data;
if (coff_header->flags & COFF_SectionFlag_MEM_READ) {
COFF_SectionHeader *section_header = &sect->data;
if (section_header->flags & COFF_SectionFlag_MemRead) {
s->flags |= PDB_DbiOMF_READ;
}
if (coff_header->flags & COFF_SectionFlag_MEM_WRITE) {
if (section_header->flags & COFF_SectionFlag_MemWrite) {
s->flags |= PDB_DbiOMF_WRITE;
}
if (coff_header->flags & COFF_SectionFlag_MEM_EXECUTE) {
if (section_header->flags & COFF_SectionFlag_MemExecute) {
s->flags |= PDB_DbiOMF_EXEC;
}
if (~coff_header->flags & COFF_SectionFlag_MEM_16BIT) {
if (~section_header->flags & COFF_SectionFlag_Mem16Bit) {
s->flags |= PDB_DbiOMF_IS_32BIT_ADDR;
}
s->flags |= PDB_DbiOMF_IS_SELECTOR; // always set
s->sec_size = coff_header->vsize;
s->sec_size = section_header->vsize;
s->frame = isect + 1;
s->sec_name = max_U16;
s->class_name = max_U16;
@@ -3443,7 +3444,7 @@ dbi_module_push_section_contrib(PDB_DbiContext *dbi,
// Mod1::fUpdateSecContrib
if (mod->first_sc.base.mod == 0) {
if (flags & COFF_SectionFlag_CNT_CODE) {
if (flags & COFF_SectionFlag_CntCode) {
mod->first_sc = sc;
}
}
+27 -27
View File
@@ -5,31 +5,31 @@ internal RDI_Arch
rdi_arch_from_coff_machine(COFF_MachineType machine)
{
switch (machine) {
case COFF_MachineType_X86: return RDI_Arch_X86;
case COFF_MachineType_X64: return RDI_Arch_X64;
case COFF_Machine_X86: return RDI_Arch_X86;
case COFF_Machine_X64: return RDI_Arch_X64;
case COFF_MachineType_UNKNOWN:
case COFF_MachineType_AM33:
case COFF_MachineType_ARM:
case COFF_MachineType_ARM64:
case COFF_MachineType_ARMNT:
case COFF_MachineType_EBC:
case COFF_MachineType_IA64:
case COFF_MachineType_M32R:
case COFF_MachineType_MIPS16:
case COFF_MachineType_MIPSFPU:
case COFF_MachineType_MIPSFPU16:
case COFF_MachineType_POWERPC:
case COFF_MachineType_POWERPCFP:
case COFF_MachineType_R4000:
case COFF_MachineType_RISCV32:
case COFF_MachineType_RISCV64:
case COFF_MachineType_SH3:
case COFF_MachineType_SH3DSP:
case COFF_MachineType_SH4:
case COFF_MachineType_SH5:
case COFF_MachineType_THUMB:
case COFF_MachineType_WCEMIPSV2:
case COFF_Machine_Unknown:
case COFF_Machine_Am33:
case COFF_Machine_Arm:
case COFF_Machine_Arm64:
case COFF_Machine_ArmNt:
case COFF_Machine_Ebc:
case COFF_Machine_Ia64:
case COFF_Machine_M32R:
case COFF_Machine_Mips16:
case COFF_Machine_MipsFpu:
case COFF_Machine_MipsFpu16:
case COFF_Machine_PowerPc:
case COFF_Machine_PowerPcFp:
case COFF_Machine_R4000:
case COFF_Machine_RiscV32:
case COFF_Machine_RiscV64:
case COFF_Machine_Sh3:
case COFF_Machine_Sh3Dsp:
case COFF_Machine_Sh4:
case COFF_Machine_Sh5:
case COFF_Machine_Thumb:
case COFF_Machine_WceMipsV2:
NotImplemented;
default:
return RDI_Arch_NULL;
@@ -40,13 +40,13 @@ internal RDI_BinarySectionFlags
rdi_binary_section_flags_from_coff_section_flags(COFF_SectionFlags flags)
{
RDI_BinarySectionFlags result = 0;
if (flags & COFF_SectionFlag_MEM_READ) {
if (flags & COFF_SectionFlag_MemRead) {
result |= RDI_BinarySectionFlag_Read;
}
if (flags & COFF_SectionFlag_MEM_WRITE) {
if (flags & COFF_SectionFlag_MemWrite) {
result |= RDI_BinarySectionFlag_Write;
}
if (flags & COFF_SectionFlag_MEM_EXECUTE) {
if (flags & COFF_SectionFlag_MemExecute) {
result |= RDI_BinarySectionFlag_Execute;
}
return result;
+109 -64
View File
@@ -2,64 +2,91 @@
// Licensed under the MIT license (https://opensource.org/license/mit/)
internal void
tp_execute_tasks(TP_Worker *worker)
tp_run_tasks(TP_Context *pool, TP_Worker *worker)
{
TP_Context *pool = worker->pool;
Arena *arena = NULL;
if (pool->worker_arena) {
arena = pool->worker_arena->v[worker->id];
}
for (;;) {
// get task id
U64 next_task_id = ins_atomic_u64_inc_eval(&pool->next_task_id);
if (next_task_id > pool->task_count) {
S64 task_left = ins_atomic_u64_dec_eval(&pool->task_left);
// are there any tasks left to run?
if (task_left < 0) {
break;
}
// invoke task func
U64 task_id = next_task_id - 1;
// run task
Arena *arena = pool->task_arena ? pool->task_arena->v[worker->id] : 0;
U64 task_id = pool->task_count - (task_left+1);
pool->task_func(arena, worker->id, task_id, pool->task_data);
// cache task count so we dont touch pool memory after atomic inc
U64 task_count = pool->task_count;
// on last task ping main thread
U64 task_done = ins_atomic_u64_inc_eval(&pool->task_done);
if (task_done == task_count) {
os_semaphore_drop(pool->main_semaphore);
}
}
}
internal void
tp_worker_main(void *raw_worker)
{
TCTX tctx_;
tctx_init_and_equip(&tctx_);
TP_Worker *worker = (TP_Worker *)raw_worker;
TP_Context *pool = worker->pool;
while (pool->is_live) {
TCTX tctx_; tctx_init_and_equip(&tctx_);
TP_Worker *worker = raw_worker;
TP_Context *pool = worker->pool;
for (; pool->is_live; ) {
if (os_semaphore_take(pool->task_semaphore, max_U64)) {
tp_execute_tasks(worker);
// before last worker takes semaphore wake up main worker
U64 take_count = ins_atomic_u64_dec_eval(&pool->take_count);
if (take_count == 1) {
os_semaphore_drop(pool->main_semaphore);
tp_run_tasks(pool, worker);
}
}
}
internal void
tp_worker_main_shared(void *raw_worker)
{
TCTX tctx_; tctx_init_and_equip(&tctx_);
TP_Worker *worker = raw_worker;
TP_Context *pool = worker->pool;
for (; pool->is_live; ) {
if (os_semaphore_take(pool->exec_semaphore, max_U64)) {
if (os_semaphore_take(pool->task_semaphore, max_U64)) {
tp_run_tasks(pool, worker);
}
} else {
Assert(!"time out");
}
}
}
internal TP_Context *
tp_alloc(Arena *arena, U32 worker_count)
tp_alloc(Arena *arena, U32 worker_count, U32 max_worker_count, String8 name)
{
ProfBeginDynamic("Alloc Thread Pool [Worker Count: %u]", worker_count);
Assert(worker_count > 0);
// init pool
TP_Context *pool = push_array(arena, TP_Context, 1);
AssertAlways(worker_count > 0);
B32 is_shared = (name.size > 0);
// alloc semaphores
OS_Handle main_semaphore = {0};
OS_Handle task_semaphore = {0};
OS_Handle exec_semaphore = {0};
if (worker_count > 1) {
pool->task_semaphore = os_semaphore_alloc(0, worker_count - 1, str8(0,0));
pool->main_semaphore = os_semaphore_alloc(0, 1, str8(0,0));
main_semaphore = os_semaphore_alloc(0, 1, str8_zero());
if (is_shared) {
AssertAlways(worker_count <= max_worker_count);
task_semaphore = os_semaphore_alloc(0, max_worker_count, name);
exec_semaphore = os_semaphore_alloc(0, worker_count, str8_zero());
} else {
task_semaphore = os_semaphore_alloc(0, worker_count, str8_zero());
}
}
// pick entry point for the workers
void *worker_entry = is_shared ? tp_worker_main_shared : tp_worker_main;
// init pool
TP_Context *pool = push_array(arena, TP_Context, 1);
pool->exec_semaphore = exec_semaphore;
pool->task_semaphore = task_semaphore;
pool->main_semaphore = main_semaphore;
pool->is_live = 1;
pool->worker_count = worker_count;
pool->worker_arr = push_array(arena, TP_Worker, worker_count);
@@ -67,14 +94,14 @@ tp_alloc(Arena *arena, U32 worker_count)
// init worker data
for (U64 i = 0; i < worker_count; i += 1) {
TP_Worker *worker = &pool->worker_arr[i];
worker->id = i;
worker->pool = pool;
worker->id = i;
worker->pool = pool;
}
// launch worker threads
for (U64 i = 1; i < worker_count; i += 1) {
TP_Worker *worker = &pool->worker_arr[i];
worker->handle = os_thread_launch(tp_worker_main, worker, 0);
worker->handle = os_thread_launch(worker_entry, worker, 0);
}
ProfEnd();
@@ -85,11 +112,25 @@ internal void
tp_release(TP_Context *pool)
{
pool->is_live = 0;
os_semaphore_release(pool->task_semaphore);
os_semaphore_release(pool->main_semaphore);
B32 is_shared = !os_handle_match(pool->exec_semaphore, os_handle_zero());
if (is_shared) {
for (U64 i = 0; i < pool->worker_count; ++i) {
os_semaphore_drop(pool->exec_semaphore);
}
}
for (U64 i = 0; i < pool->worker_count; ++i) {
os_semaphore_drop(pool->task_semaphore);
}
for (U64 i = 1; i < pool->worker_count; i += 1) {
os_thread_detach(pool->worker_arr[i].handle);
}
if (is_shared) {
os_semaphore_release(pool->exec_semaphore);
}
os_semaphore_release(pool->task_semaphore);
os_semaphore_release(pool->main_semaphore);
MemoryZeroStruct(pool);
}
@@ -156,31 +197,35 @@ tp_temp_end(TP_Temp temp)
}
internal void
tp_for_parallel(TP_Context *pool, TP_Arena *arena, U64 task_count, TP_TaskFunc *task_func, void *task_data)
tp_for_parallel(TP_Context *pool, TP_Arena *task_arena, U64 task_count, TP_TaskFunc *task_func, void *task_data)
{
Assert(!arena || arena->count == pool->worker_count);
if (task_count > 0) {
// init run
pool->task_arena = task_arena;
pool->task_func = task_func;
pool->task_data = task_data;
pool->task_count = task_count;
pool->task_done = 0;
ins_atomic_u64_eval_assign(&pool->task_left, task_count);
// setup pool state
pool->worker_arena = arena;
pool->task_count = task_count;
pool->task_func = task_func;
pool->task_data = task_data;
pool->next_task_id = 0;
pool->take_count = 0;
// do we have enough work for other workers?
pool->take_count = Min(pool->task_count, pool->worker_count);
U64 drop_count = pool->take_count;
for (U64 worker_idx = 1; worker_idx < drop_count; worker_idx += 1) {
os_semaphore_drop(pool->task_semaphore);
}
// execute tasks on main worker too
TP_Worker *main_worker = &pool->worker_arr[0];
tp_execute_tasks(main_worker);
if (drop_count > 1) {
// wait for workers to finish assigned tasks
U64 drop_count = Min(task_count, pool->worker_count);
// if we are in shared mode ping local semaphore
if (!os_handle_match(pool->exec_semaphore, os_handle_zero())) {
for (U64 worker_idx = 0; worker_idx < drop_count; worker_idx +=1) {
os_semaphore_drop(pool->exec_semaphore);
}
}
// ping shared semaphore
for (U64 worker_idx = 0; worker_idx < drop_count; worker_idx += 1) {
os_semaphore_drop(pool->task_semaphore);
}
// run tasks on main worker
tp_run_tasks(pool, &pool->worker_arr[0]);
// wait for workers to finish tasks
os_semaphore_take(pool->main_semaphore, max_U64);
}
}
+9 -6
View File
@@ -27,20 +27,23 @@ typedef struct TP_Worker
typedef struct TP_Context
{
B32 is_live;
OS_Handle exec_semaphore;
OS_Handle task_semaphore;
OS_Handle main_semaphore;
B32 is_live;
U32 worker_count;
TP_Worker *worker_arr;
TP_Arena *worker_arena;
U64 task_count;
TP_Arena *task_arena;
TP_TaskFunc *task_func;
void *task_data;
volatile U64 next_task_id;
volatile U64 take_count;
U64 task_count;
U64 task_done;
S64 task_left;
} TP_Context;
internal TP_Context * tp_alloc(Arena *arena, U32 worker_count);
internal TP_Context * tp_alloc(Arena *arena, U32 worker_count, U32 max_worker_count, String8 name);
internal void tp_release(TP_Context *pool);
internal TP_Arena * tp_arena_alloc(TP_Context *pool);
internal void tp_arena_release(TP_Arena **arena_ptr);
+79 -35
View File
@@ -86,6 +86,50 @@ mscrt_parse_func_info(Arena *arena,
////////////////////////////////
internal U64
mscrt_v4_parse_u32(String8 raw_data, U64 offset, U32 *uint_out)
{
U64 cursor = offset;
U8 one = 0;
cursor += str8_deserial_read_struct(raw_data, cursor, &one);
if ((one & 0xF) == 15) {
U8 two = 0, three = 0, four = 0, five = 0;
cursor += str8_deserial_read_struct(raw_data, cursor, &two);
cursor += str8_deserial_read_struct(raw_data, cursor, &three);
cursor += str8_deserial_read_struct(raw_data, cursor, &four);
cursor += str8_deserial_read_struct(raw_data, cursor, &five);
*uint_out = (U32)two | ((U32)three << 8) | ((U32)four << 16) | ((U32)five << 24);
} else if ((one & 0xF) == 7) {
U8 two = 0, three = 0, four = 0;
cursor += str8_deserial_read_struct(raw_data, cursor, &two);
cursor += str8_deserial_read_struct(raw_data, cursor, &three);
cursor += str8_deserial_read_struct(raw_data, cursor, &four);
*uint_out = ((U32)one >> 4) | ((U32)two << 4) | ((U32)three << 12) | ((U32)four << 20);
} else if ((one & 0x7) == 3) {
U8 two = 0, three = 0;
cursor += str8_deserial_read_struct(raw_data, cursor, &two);
cursor += str8_deserial_read_struct(raw_data, cursor, &three);
*uint_out = ((U32)one >> 3) | ((U32)two << 5) | ((U32)three << 13);
} else if ((one & 0x3) == 1) {
U8 two = 0;
cursor += str8_deserial_read_struct(raw_data, cursor, &two);
*uint_out = ((U32)one >> 2) | ((U32)two << 6);
} else {
*uint_out = one >> 1;
}
U64 read_size = cursor - offset;
return read_size;
}
internal U64
mscrt_v4_parse_s32(String8 raw_data, U64 offset, S32 *int_out)
{
return str8_deserial_read_struct(raw_data, offset, int_out);
}
internal U64
mscrt_parse_handler_type_v4(String8 raw_data, U64 offset, U64 func_voff, MSCRT_EhHandlerTypeV4 *handler)
{
@@ -93,15 +137,15 @@ mscrt_parse_handler_type_v4(String8 raw_data, U64 offset, U64 func_voff, MSCRT_E
cursor += str8_deserial_read_struct(raw_data, cursor, &handler->flags);
if (handler->flags & MSCRT_EhHandlerV4Flag_Adjectives) {
cursor += str8_deserial_read_struct(raw_data, cursor, &handler->adjectives);
cursor += mscrt_v4_parse_u32(raw_data, cursor, &handler->adjectives);
}
if (handler->flags & MSCRT_EhHandlerV4Flag_DispType) {
cursor += str8_deserial_read_struct(raw_data, cursor, &handler->type_voff);
cursor += mscrt_v4_parse_s32(raw_data, cursor, &handler->type_voff);
}
if (handler->flags & MSCRT_EhHandlerV4Flag_DispCatchObj) {
cursor += str8_deserial_read_struct(raw_data, cursor, &handler->catch_obj_voff);
cursor += mscrt_v4_parse_u32(raw_data, cursor, &handler->catch_obj_voff);
}
cursor += str8_deserial_read_struct(raw_data, cursor, &handler->catch_code_voff);
cursor += mscrt_v4_parse_s32(raw_data, cursor, &handler->catch_code_voff);
U32 cont_type = (handler->flags & MSCRT_EhHandlerV4Flag_ContVOffMask) >> MSCRT_EhHandlerV4Flag_ContVOffShift;
if (handler->flags & MSCRT_EhHandlerV4Flag_ContIsVOff) {
@@ -109,14 +153,14 @@ mscrt_parse_handler_type_v4(String8 raw_data, U64 offset, U64 func_voff, MSCRT_E
case MSCRT_ContV4Type_NoMetadata: break;
case MSCRT_ContV4Type_OneFuncRelAddr: {
S32 v = 0;
cursor += str8_deserial_read_struct(raw_data, cursor, &v);
cursor += mscrt_v4_parse_s32(raw_data, cursor, &v);
handler->catch_funclet_cont_addr[0] = (U64)v;
handler->catch_funclet_cont_addr_count = 1;
} break;
case MSCRT_ContV4Type_TwoFuncRelAddr: {
S32 v1 = 0, v2 = 0;
cursor += str8_deserial_read_struct(raw_data, cursor, &v1);
cursor += str8_deserial_read_struct(raw_data, cursor, &v2);
cursor += mscrt_v4_parse_s32(raw_data, cursor, &v1);
cursor += mscrt_v4_parse_s32(raw_data, cursor, &v2);
handler->catch_funclet_cont_addr[0] = (U64)v1;
handler->catch_funclet_cont_addr[1] = (U64)v2;
handler->catch_funclet_cont_addr_count = 2;
@@ -128,14 +172,14 @@ mscrt_parse_handler_type_v4(String8 raw_data, U64 offset, U64 func_voff, MSCRT_E
} break;
case MSCRT_ContV4Type_OneFuncRelAddr: {
U32 v = 0;
cursor += str8_deserial_read_struct(raw_data, cursor, &v);
cursor += mscrt_v4_parse_u32(raw_data, cursor, &v);
handler->catch_funclet_cont_addr[0] = func_voff + (U64)v;
handler->catch_funclet_cont_addr_count = 1;
} break;
case MSCRT_ContV4Type_TwoFuncRelAddr: {
U32 v1 = 0, v2 = 0;
cursor += str8_deserial_read_struct(raw_data, cursor, &v1);
cursor += str8_deserial_read_struct(raw_data, cursor, &v2);
cursor += mscrt_v4_parse_u32(raw_data, cursor, &v1);
cursor += mscrt_v4_parse_u32(raw_data, cursor, &v2);
handler->catch_funclet_cont_addr[0] = func_voff + (U64)v1;
handler->catch_funclet_cont_addr[1] = func_voff + (U64)v2;
handler->catch_funclet_cont_addr_count = 2;
@@ -156,7 +200,7 @@ mscrt_parse_handler_type_v4_array(Arena *arena,
{
U64 cursor = offset;
U32 count = 0;
cursor += str8_deserial_read_struct(raw_data, cursor, &count);
cursor += mscrt_v4_parse_u32(raw_data, cursor, &count);
MSCRT_EhHandlerTypeV4 *handlers = 0;
if (count) {
@@ -179,7 +223,7 @@ mscrt_parse_unwind_v4_entry(String8 raw_data, U64 offset, MSCRT_UnwindEntryV4 *e
U64 cursor = offset;
U32 type_and_next_off = 0;
cursor += str8_deserial_read_struct(raw_data, cursor, &type_and_next_off);
cursor += mscrt_v4_parse_u32(raw_data, cursor, &type_and_next_off);
entry_out->type = type_and_next_off & 0x3;
entry_out->next_off = type_and_next_off >> 2;
@@ -187,11 +231,11 @@ mscrt_parse_unwind_v4_entry(String8 raw_data, U64 offset, MSCRT_UnwindEntryV4 *e
switch (entry_out->type) {
case MSCRT_UnwindMapV4Type_DtorWithObj:
case MSCRT_UnwindMapV4Type_DtorWithPtrToObj: {
cursor += str8_deserial_read_struct(raw_data, cursor, &entry_out->action);
cursor += str8_deserial_read_struct(raw_data, cursor, &entry_out->object);
cursor += mscrt_v4_parse_s32(raw_data, cursor, &entry_out->action);
cursor += mscrt_v4_parse_u32(raw_data, cursor, &entry_out->object);
} break;
case MSCRT_UnwindMapV4Type_VOFF: {
cursor += str8_deserial_read_struct(raw_data, cursor, &entry_out->action);
cursor += mscrt_v4_parse_s32(raw_data, cursor, &entry_out->action);
} break;
case MSCRT_UnwindMapV4Type_NoUW: {
// no action and/or object is associated with this type
@@ -209,7 +253,7 @@ internal U64
mscrt_parse_unwind_map_v4(Arena *arena, String8 raw_data, U64 off, MSCRT_UnwindMapV4 *map_out)
{
U64 cursor = off;
cursor += str8_deserial_read_struct(raw_data, cursor, &map_out->count);
cursor += mscrt_v4_parse_u32(raw_data, cursor, &map_out->count);
map_out->v = push_array(arena, MSCRT_UnwindEntryV4, map_out->count);
for (U32 i = 0; i < map_out->count; ++i) {
cursor += mscrt_parse_unwind_v4_entry(raw_data, cursor, &map_out->v[i]);
@@ -230,17 +274,17 @@ mscrt_parse_try_block_map_array_v4(Arena *arena,
U64 cursor = off;
U32 try_block_map_count = 0;
cursor += str8_deserial_read_struct(raw_data, cursor, &try_block_map_count);
cursor += mscrt_v4_parse_u32(raw_data, cursor, &try_block_map_count);
MSCRT_TryBlockMapV4 *try_block_map = push_array(arena, MSCRT_TryBlockMapV4, try_block_map_count);
for (U32 itry = 0; itry < try_block_map_count; ++itry) {
MSCRT_TryBlockMapV4 *try_block = &try_block_map[itry];
cursor += str8_deserial_read_struct(raw_data, cursor, &try_block->try_low);
cursor += str8_deserial_read_struct(raw_data, cursor, &try_block->try_high);
cursor += str8_deserial_read_struct(raw_data, cursor, &try_block->catch_high);
cursor += mscrt_v4_parse_u32(raw_data, cursor, &try_block->try_low);
cursor += mscrt_v4_parse_u32(raw_data, cursor, &try_block->try_high);
cursor += mscrt_v4_parse_u32(raw_data, cursor, &try_block->catch_high);
S32 handler_array_voff = 0;
cursor += str8_deserial_read_struct(raw_data, cursor, &handler_array_voff);
cursor += mscrt_v4_parse_s32(raw_data, cursor, &handler_array_voff);
U64 handler_array_foff = coff_foff_from_voff(sections, section_count, (U32)handler_array_voff);
mscrt_parse_handler_type_v4_array(arena, raw_data, handler_array_foff, func_voff, &try_block->handlers);
@@ -263,7 +307,7 @@ mscrt_parse_ip2state_map_v4(Arena *arena,
U64 cursor = off;
U32 count = 0;
cursor += str8_deserial_read_struct(raw_data, cursor, &count);
cursor += mscrt_v4_parse_u32(raw_data, cursor, &count);
U32 *voffs = push_array(arena, U32, count);
S32 *states = push_array(arena, S32, count);
@@ -271,13 +315,13 @@ mscrt_parse_ip2state_map_v4(Arena *arena,
U32 prev_voff = func_voff;
for (U32 i = 0; i < count; ++i) {
// virtual offsets are encoded as deltas
cursor += str8_deserial_read_struct(raw_data, cursor, &voffs[i]);
cursor += mscrt_v4_parse_u32(raw_data, cursor, &voffs[i]);
voffs[i] += prev_voff;
prev_voff = voffs[i];
// states are encoded with +1 to avoid encoding negative integers
U32 encoded_state = 0;
cursor += str8_deserial_read_struct(raw_data, cursor, &encoded_state);
cursor += mscrt_v4_parse_u32(raw_data, cursor, &encoded_state);
states[i] = (S32)encoded_state - 1;
}
@@ -303,22 +347,22 @@ mscrt_parse_func_info_v4(Arena *arena,
MSCRT_FuncInfo32V4 func_info = {0};
cursor += str8_deserial_read_struct(raw_data, cursor, &func_info.header);
if (func_info.header & MSCRT_FuncInfoV4Flag_IsBBT) {
cursor += str8_deserial_read_struct(raw_data, cursor, &func_info.bbt_flags);
cursor += mscrt_v4_parse_u32(raw_data, cursor, &func_info.bbt_flags);
}
if (func_info.header & MSCRT_FuncInfoV4Flag_UnwindMap) {
cursor += str8_deserial_read_struct(raw_data, cursor, &func_info.unwind_map_voff);
cursor += mscrt_v4_parse_s32(raw_data, cursor, &func_info.unwind_map_voff);
}
if (func_info.header & MSCRT_FuncInfoV4Flag_TryBlockMap) {
cursor += str8_deserial_read_struct(raw_data, cursor, &func_info.try_block_map_voff);
cursor += mscrt_v4_parse_s32(raw_data, cursor, &func_info.try_block_map_voff);
}
if (func_info.header & MSCRT_FuncInfoV4Flag_IsSeparated) {
// TODO: separted IP state map
NotImplemented;
} else {
cursor += str8_deserial_read_struct(raw_data, cursor, &func_info.ip_to_state_map_voff);
cursor += mscrt_v4_parse_s32(raw_data, cursor, &func_info.ip_to_state_map_voff);
}
if (func_info.header & MSCRT_FuncInfoV4Flag_IsCatch) {
cursor += str8_deserial_read_struct(raw_data, cursor, &func_info.wrt_frame_establisher_voff);
cursor += mscrt_v4_parse_s32(raw_data, cursor, &func_info.wrt_frame_establisher_voff);
}
MSCRT_UnwindMapV4 unwind_map = {0};
@@ -387,15 +431,15 @@ mscrt_catch_blocks_from_data_x8664(Arena *arena,
String8 handler_name = str8_zero();
/* TODO:
{
SYMS_UnitID uid = syms_group_uid_from_voff__accelerated(group, handler_voff);
SYMS_UnitAccel *unit = syms_group_unit_from_uid(group, uid);
UnitID uid = syms_group_uid_from_voff__accelerated(group, handler_voff);
UnitAccel *unit = syms_group_unit_from_uid(group, uid);
SYMS_SymbolID sid = syms_group_proc_sid_from_uid_voff__accelerated(group, uid, handler_voff);
handler_name = syms_group_symbol_name_from_sid(temp.arena, group, unit, sid);
}
*/
B32 is_handler_v3_or_below = str8_match(handler_name, str8_lit("__CxxFrameHandler3"), 0) ||
str8_match(handler_name, str8_lit("__GSHandlerCheck_EH"), 0);
B32 is_handler_v3_or_below = str8_match_lit("__CxxFrameHandler3", handler_name, 0) ||
str8_match_lit("__GSHandlerCheck_EH", handler_name, 0);
if (is_handler_v3_or_below) {
U64 func_info_foff = handler_data_foff + sizeof(handler_voff);
MSCRT_FuncInfo func_info = {0};
@@ -413,8 +457,8 @@ mscrt_catch_blocks_from_data_x8664(Arena *arena,
goto next;
}
B32 is_handler_v4 = str8_match(handler_name, str8_lit("__CxxFrameHandler4"), 0) ||
str8_match(handler_name, str8_lit("__GSHandlerCheck_EH4"), 0);
B32 is_handler_v4 = str8_match_lit("__CxxFrameHandler4", handler_name, 0) ||
str8_match_lit("__GSHandlerCheck_EH4", handler_name, 0);
if (is_handler_v4) {
U32 func_info_voff = *(U32 *)str8_deserial_get_raw_ptr(raw_data, handler_data_foff + sizeof(handler_voff), sizeof(func_info_voff));
U64 func_info_foff = coff_foff_from_voff(sections, section_count, func_info_voff);
+34
View File
@@ -0,0 +1,34 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
internal String8
mscrt_string_from_eh_adjectives(Arena *arena, MSCRT_EhHandlerTypeFlags adjectives)
{
Temp scratch = scratch_begin(&arena, 1);
String8List adj_list = {0};
if (adjectives & MSCRT_EhHandlerTypeFlag_IsConst) {
str8_list_pushf(scratch.arena, &adj_list, "Const");
}
if (adjectives & MSCRT_EhHandlerTypeFlag_IsVolatile) {
str8_list_pushf(scratch.arena, &adj_list, "Volatile");
}
if (adjectives & MSCRT_EhHandlerTypeFlag_IsUnaligned) {
str8_list_pushf(scratch.arena, &adj_list, "Unaligned");
}
if (adjectives & MSCRT_EhHandlerTypeFlag_IsReference) {
str8_list_pushf(scratch.arena, &adj_list, "Reference");
}
if (adjectives & MSCRT_EhHandlerTypeFlag_IsResumable) {
str8_list_pushf(scratch.arena, &adj_list, "Resumable");
}
if (adjectives & MSCRT_EhHandlerTypeFlag_IsStdDotDot) {
str8_list_pushf(scratch.arena, &adj_list, "StdDotDot");
}
if (adjectives & MSCRT_EhHandlerTypeFlag_IsComplusEH) {
str8_list_pushf(scratch.arena, &adj_list, "ComplusEH");
}
String8 result = str8_list_join(arena, &adj_list, &(StringJoin){.sep=str8_lit(", ")});
scratch_end(scratch);
return result;
}
+9
View File
@@ -0,0 +1,9 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef MSVC_CRT_ENUM_H
#define MSVC_CRT_ENUM_H
internal String8 mscrt_string_from_eh_adjectives(Arena *arena, MSCRT_EhHandlerTypeFlags adjectives);
#endif // MSVC_CRT_ENUM_H
+1 -1
View File
@@ -1326,5 +1326,5 @@ main(int argc, char **argv)
}
//- rjf: call into "real" entry point
main_thread_base_entry_point(arguments_count, arguments);
main_thread_base_entry_point(argc, argv);
}
+2 -2
View File
@@ -17,7 +17,7 @@ pdb_info_from_data(Arena *arena, String8 data){
PDB_Info *result = 0;
if (header != 0){
// read guid
COFF_Guid *auth_guid = 0;
Guid *auth_guid = 0;
U32 after_auth_guid_off = sizeof(*header);
switch (header->version){
case PDB_InfoVersion_VC70_DEP:
@@ -26,7 +26,7 @@ pdb_info_from_data(Arena *arena, String8 data){
case PDB_InfoVersion_VC110:
case PDB_InfoVersion_VC140:
{
auth_guid = (COFF_Guid*)(data.str + after_auth_guid_off);
auth_guid = (Guid*)(data.str + after_auth_guid_off);
after_auth_guid_off = sizeof(*header) + sizeof(*auth_guid);
}break;
+1 -1
View File
@@ -44,7 +44,7 @@ typedef struct PDB_Info
{
PDB_InfoNode *first;
PDB_InfoNode *last;
COFF_Guid auth_guid;
Guid auth_guid;
} PDB_Info;
typedef struct PDB_InfoHeader
+203 -146
View File
@@ -438,46 +438,46 @@ pe_bin_info_from_data(Arena *arena, String8 data)
}
// rjf: read coff header
U32 coff_header_off = dos_header.coff_file_offset + sizeof(pe_magic);
COFF_Header coff_header = {0};
U32 file_header_off = dos_header.coff_file_offset + sizeof(pe_magic);
COFF_FileHeader file_header = {0};
if(valid)
{
str8_deserial_read_struct(data, coff_header_off, &coff_header);
str8_deserial_read_struct(data, file_header_off, &file_header);
}
// rjf: range of optional extension header ("optional" for short)
U32 optional_size = coff_header.optional_header_size;
U64 after_coff_header_off = coff_header_off + sizeof(coff_header);
U64 after_optional_header_off = after_coff_header_off + optional_size;
Rng1U64 optional_range = {0};
U32 optional_size = file_header.optional_header_size;
U64 after_file_header_off = file_header_off + sizeof(COFF_FileHeader);
U64 after_optional_header_off = after_file_header_off + optional_size;
Rng1U64 optional_range = {0};
if(valid)
{
optional_range.min = ClampTop(after_coff_header_off, data.size);
optional_range.min = ClampTop(after_file_header_off, data.size);
optional_range.max = ClampTop(after_optional_header_off, data.size);
}
// rjf: get sections
U64 sec_array_off = optional_range.max;
U64 sec_array_raw_opl = sec_array_off + coff_header.section_count*sizeof(COFF_SectionHeader);
U64 sec_array_opl = ClampTop(sec_array_raw_opl, data.size);
U64 clamped_sec_count = (sec_array_opl - sec_array_off)/sizeof(COFF_SectionHeader);
COFF_SectionHeader *sections = (COFF_SectionHeader*)(data.str + sec_array_off);
U64 sec_array_off = optional_range.max;
U64 sec_array_raw_opl = sec_array_off + file_header.section_count*sizeof(COFF_SectionHeader);
U64 sec_array_opl = ClampTop(sec_array_raw_opl, data.size);
U64 clamped_sec_count = (sec_array_opl - sec_array_off)/sizeof(COFF_SectionHeader);
COFF_SectionHeader *sections = (COFF_SectionHeader*)(data.str + sec_array_off);
// rjf: get symbols
U64 symbol_array_off = coff_header.symbol_table_foff;
U64 symbol_count = coff_header.symbol_count;
U64 symbol_array_off = file_header.symbol_table_foff;
U64 symbol_count = file_header.symbol_count;
// rjf: get string table
U64 string_table_off = symbol_array_off + sizeof(COFF_Symbol16) * symbol_count;
// rjf: read optional header
U16 optional_magic = 0;
U64 image_base = 0;
U64 entry_point = 0;
U32 data_dir_count = 0;
U64 virt_section_align = 0;
U64 file_section_align = 0;
Rng1U64 *data_dir_franges = 0;
U16 optional_magic = 0;
U64 image_base = 0;
U64 entry_point = 0;
U32 data_dir_count = 0;
U64 virt_section_align = 0;
U64 file_section_align = 0;
Rng1U64 *data_dir_franges = 0;
if(valid && optional_size > 0)
{
// rjf: read magic number
@@ -491,24 +491,36 @@ pe_bin_info_from_data(Arena *arena, String8 data)
case PE_PE32_MAGIC:
{
PE_OptionalHeader32 pe_optional = {0};
str8_deserial_read_struct(data, optional_range.min, &pe_optional);
image_base = pe_optional.image_base;
entry_point = pe_optional.entry_point_va;
virt_section_align = pe_optional.section_alignment;
file_section_align = pe_optional.file_alignment;
reported_data_dir_offset = sizeof(pe_optional);
reported_data_dir_count = pe_optional.data_dir_count;
if(str8_deserial_read_struct(data, optional_range.min, &pe_optional) == sizeof(pe_optional))
{
image_base = pe_optional.image_base;
entry_point = pe_optional.entry_point_va;
virt_section_align = pe_optional.section_alignment;
file_section_align = pe_optional.file_alignment;
reported_data_dir_offset = sizeof(pe_optional);
reported_data_dir_count = pe_optional.data_dir_count;
}
else
{
Assert(!"unable to read PE Optional Header");
}
}break;
case PE_PE32PLUS_MAGIC:
{
PE_OptionalHeader32Plus pe_optional = {0};
str8_deserial_read_struct(data, optional_range.min, &pe_optional);
image_base = pe_optional.image_base;
entry_point = pe_optional.entry_point_va;
virt_section_align = pe_optional.section_alignment;
file_section_align = pe_optional.file_alignment;
reported_data_dir_offset = sizeof(pe_optional);
reported_data_dir_count = pe_optional.data_dir_count;
if(str8_deserial_read_struct(data, optional_range.min, &pe_optional) == sizeof(pe_optional))
{
image_base = pe_optional.image_base;
entry_point = pe_optional.entry_point_va;
virt_section_align = pe_optional.section_alignment;
file_section_align = pe_optional.file_alignment;
reported_data_dir_offset = sizeof(pe_optional);
reported_data_dir_count = pe_optional.data_dir_count;
}
else
{
Assert(!"unable to read PE Optional Plus Header");
}
}break;
}
@@ -520,56 +532,16 @@ pe_bin_info_from_data(Arena *arena, String8 data)
data_dir_franges = push_array(arena, Rng1U64, data_dir_count);
for(U32 dir_idx = 0; dir_idx < data_dir_count; dir_idx += 1)
{
U64 dir_offset = optional_range.min + reported_data_dir_offset + sizeof(PE_DataDirectory)*dir_idx;
PE_DataDirectory dir = {0};
str8_deserial_read_struct(data, dir_offset, &dir);
U64 file_off = coff_foff_from_voff(sections, clamped_sec_count, dir.virt_off);
data_dir_franges[dir_idx] = r1u64(file_off, file_off+dir.virt_size);
}
}
// rjf: read info about debug file
U32 dbg_time = 0;
U32 dbg_age = 0;
Guid dbg_guid = {0};
U64 dbg_path_off = 0;
U64 dbg_path_size = 0;
if(valid && PE_DataDirectoryIndex_DEBUG < data_dir_count)
{
// rjf: read debug directory
PE_DebugDirectory dbg_data = {0};
str8_deserial_read_struct(data, data_dir_franges[PE_DataDirectoryIndex_DEBUG].min, &dbg_data);
// rjf: extract external file info from codeview header
if(dbg_data.type == PE_DebugDirectoryType_CODEVIEW)
{
U64 cv_offset = dbg_data.foff;
U32 cv_magic = 0;
str8_deserial_read_struct(data, cv_offset, &cv_magic);
switch(cv_magic)
U64 dir_offset = optional_range.min + reported_data_dir_offset + sizeof(PE_DataDirectory)*dir_idx;
PE_DataDirectory dir = {0};
if(str8_deserial_read_struct(data, dir_offset, &dir) == sizeof(dir))
{
default:break;
case PE_CODEVIEW_PDB20_MAGIC:
{
PE_CvHeaderPDB20 cv = {0};
str8_deserial_read_struct(data, cv_offset, &cv);
dbg_time = cv.time_stamp;
dbg_age = cv.age;
dbg_path_off = cv_offset + sizeof(cv);
}break;
case PE_CODEVIEW_PDB70_MAGIC:
{
PE_CvHeaderPDB70 cv = {0};
str8_deserial_read_struct(data, cv_offset, &cv);
dbg_guid = cv.guid;
dbg_age = cv.age;
dbg_path_off = cv_offset + sizeof(cv);
}break;
U64 file_off = coff_foff_from_voff(sections, clamped_sec_count, dir.virt_off);
data_dir_franges[dir_idx] = r1u64(file_off, file_off+dir.virt_size);
}
if(dbg_path_off > 0)
else
{
U8 *dbg_path_cstring_base = data.str+dbg_path_off;
dbg_path_size = cstring8_length(dbg_path_cstring_base);
Assert(!"unable to read data directory");
}
}
}
@@ -579,23 +551,34 @@ pe_bin_info_from_data(Arena *arena, String8 data)
if(valid && PE_DataDirectoryIndex_TLS < data_dir_count)
{
Rng1U64 tls_header_frng = data_dir_franges[PE_DataDirectoryIndex_TLS];
switch(coff_header.machine)
switch(file_header.machine)
{
default:{}break;
case COFF_MachineType_X86:
default:{ NotImplemented; }break;
case COFF_Machine_Unknown: break;
case COFF_Machine_X86:
{
PE_TLSHeader32 tls_header32 = {0};
str8_deserial_read_struct(data, tls_header_frng.min, &tls_header32);
tls_header.raw_data_start = (U64)tls_header32.raw_data_start;
tls_header.raw_data_end = (U64)tls_header32.raw_data_end;
tls_header.index_address = (U64)tls_header32.index_address;
tls_header.callbacks_address = (U64)tls_header32.callbacks_address;
tls_header.zero_fill_size = (U64)tls_header32.zero_fill_size;
tls_header.characteristics = (U64)tls_header32.characteristics;
if(str8_deserial_read_struct(data, tls_header_frng.min, &tls_header32) == sizeof(tls_header32))
{
tls_header.raw_data_start = (U64)tls_header32.raw_data_start;
tls_header.raw_data_end = (U64)tls_header32.raw_data_end;
tls_header.index_address = (U64)tls_header32.index_address;
tls_header.callbacks_address = (U64)tls_header32.callbacks_address;
tls_header.zero_fill_size = (U64)tls_header32.zero_fill_size;
tls_header.characteristics = (U64)tls_header32.characteristics;
}
else
{
Assert(!"unable to read TLS Header 32");
}
}break;
case COFF_MachineType_X64:
case COFF_Machine_X64:
{
str8_deserial_read_struct(data, tls_header_frng.min, &tls_header);
if(str8_deserial_read_struct(data, tls_header_frng.min, &tls_header) != sizeof(tls_header))
{
MemoryZeroStruct(&tls_header);
Assert(!"unable to read TLS Header 64");
}
}break;
}
}
@@ -603,36 +586,110 @@ pe_bin_info_from_data(Arena *arena, String8 data)
// rjf: fill info
if(valid)
{
info.image_base = image_base;
info.entry_point = entry_point;
info.is_pe32 = (optional_magic == PE_PE32_MAGIC);
info.virt_section_align = virt_section_align;
info.file_section_align = file_section_align;
info.section_array_off = sec_array_off;
info.section_count = clamped_sec_count;
info.symbol_array_off = symbol_array_off;
info.symbol_count = symbol_count;
info.string_table_off = string_table_off;
info.dbg_path_off = dbg_path_off;
info.dbg_path_size = dbg_path_size;
info.dbg_guid = dbg_guid;
info.dbg_age = dbg_age;
info.dbg_time = dbg_time;
info.data_dir_franges = data_dir_franges;
info.data_dir_count = data_dir_count;
switch(coff_header.machine)
{
default:{}break;
case COFF_MachineType_X86: {info.arch = Arch_x86;}break;
case COFF_MachineType_X64: {info.arch = Arch_x64;}break;
case COFF_MachineType_ARM: {info.arch = Arch_arm32;}break;
case COFF_MachineType_ARM64: {info.arch = Arch_arm64;}break;
}
MemoryCopyStruct(&info.tls_header, &tls_header);
info.image_base = image_base;
info.entry_point = entry_point;
info.is_pe32 = (optional_magic == PE_PE32_MAGIC);
info.virt_section_align = virt_section_align;
info.file_section_align = file_section_align;
info.section_array_off = sec_array_off;
info.section_count = clamped_sec_count;
info.symbol_array_off = symbol_array_off;
info.symbol_count = symbol_count;
info.string_table_off = string_table_off;
info.data_dir_franges = data_dir_franges;
info.data_dir_count = data_dir_count;
info.arch = arch_from_coff_machine(file_header.machine);
info.tls_header = tls_header;
}
return info;
}
internal PE_DebugInfoList
pe_parse_debug_directory(Arena *arena, String8 raw_image, String8 raw_debug_dir)
{
PE_DebugInfoList result = {0};
PE_DebugDirectory *debug_entry = str8_deserial_get_raw_ptr(raw_debug_dir, 0, sizeof(*debug_entry));
PE_DebugDirectory *debug_entry_opl = debug_entry + raw_debug_dir.size/sizeof(*debug_entry_opl);
for (PE_DebugDirectory *entry = debug_entry; entry < debug_entry_opl; ++entry) {
switch (entry->type) {
default: {
PE_DebugInfoNode *n = push_array(arena, PE_DebugInfoNode, 1);
n->v.header = *entry;
n->v.u.raw_data = str8_substr(raw_image, rng_1u64(entry->foff, entry->foff + entry->size));
SLLQueuePush(result.first, result.last, n);
++result.count;
} break;
case PE_DebugDirectoryType_CODEVIEW: {
U32 cv_magic = 0;
str8_deserial_read_struct(raw_image, entry->foff, &cv_magic);
switch (cv_magic) {
case PE_CODEVIEW_PDB20_MAGIC: {
PE_CvHeaderPDB20 cv = {0};
U64 cv_read_size = str8_deserial_read_struct(raw_image, entry->foff, &cv);
if (cv_read_size == sizeof(cv)) {
String8 path = {0};
str8_deserial_read_cstr(raw_image, entry->foff+sizeof(cv), &path);
PE_DebugInfoNode *n = push_array(arena, PE_DebugInfoNode, 1);
n->v.header = *entry;
n->v.u.codeview.pdb20.header = cv;
n->v.u.codeview.pdb20.path = path;
SLLQueuePush(result.first, result.last, n);
++result.count;
} else {
Assert(!"unable to read PE_CvHeaderPDB20");
}
} break;
case PE_CODEVIEW_PDB70_MAGIC: {
PE_CvHeaderPDB70 cv = {0};
U64 cv_read_size = str8_deserial_read_struct(raw_image, entry->foff, &cv);
if (cv_read_size == sizeof(cv)) {
String8 path = {0};
str8_deserial_read_cstr(raw_image, entry->foff+sizeof(cv), &path);
PE_DebugInfoNode *n = push_array(arena, PE_DebugInfoNode, 1);
n->v.header = *entry;
n->v.u.codeview.pdb70.header = cv;
n->v.u.codeview.pdb70.path = path;
SLLQueuePush(result.first, result.last, n);
++result.count;
} else {
Assert(!"unable to read PE_CvHeaderPDB70");
}
} break;
case PE_CODEVIEW_RDI_MAGIC: {
PE_CvHeaderRDI cv = {0};
U64 cv_read_size = str8_deserial_read_struct(raw_image, entry->foff, &cv);
if (cv_read_size == sizeof(cv)) {
String8 path = {0};
str8_deserial_read_cstr(raw_image, entry->foff+sizeof(cv), &path);
PE_DebugInfoNode *n = push_array(arena, PE_DebugInfoNode, 1);
n->v.header = *entry;
n->v.u.codeview.rdi.header = cv;
n->v.u.codeview.rdi.path = path;
SLLQueuePush(result.first, result.last, n);
++result.count;
} else {
Assert(!"unable to read PE_CvHeaderRDI");
}
} break;
default: break;
}
} break;
}
}
return result;
}
////////////////////////////////
//~ rjf: Helpers
@@ -767,7 +824,7 @@ pe_foff_from_voff(String8 data, PE_BinInfo *bin, U64 voff)
COFF_SectionHeader *sect = &sections[sect_idx];
if(sect->voff <= voff && voff < sect->voff + sect->vsize)
{
if(!(sect->flags & COFF_SectionFlag_CNT_UNINITIALIZED_DATA))
if(!(sect->flags & COFF_SectionFlag_CntUninitializedData))
{
foff = sect->foff + (voff - sect->voff);
}
@@ -910,7 +967,7 @@ pe_get_entry_point_names(COFF_MachineType machine,
String8Array entry_point_names = {0};
if (file_characteristics & PE_ImageFileCharacteristic_FILE_DLL) {
if (machine == COFF_MachineType_X86) {
if (machine == COFF_Machine_X86) {
read_only static String8 dll_entry_point_arr[] = {
str8_lit_comp("__DllMainCRTStartup@12"),
};
@@ -1361,8 +1418,8 @@ pe_tls_from_data(Arena *arena,
U64 *callback_addrs = 0;
switch (machine) {
case COFF_MachineType_UNKNOWN: break;
case COFF_MachineType_X86: {
case COFF_Machine_Unknown: break;
case COFF_Machine_X86: {
PE_TLSHeader32 header32 = {0};
str8_deserial_read_struct(raw_tls, 0, &header32);
@@ -1387,7 +1444,7 @@ pe_tls_from_data(Arena *arena,
callback_addrs[i] = (U64)src[i];
}
} break;
case COFF_MachineType_X64: {
case COFF_Machine_X64: {
str8_deserial_read_struct(raw_tls, 0, &header64);
U64 callbacks_voff = header64.callbacks_address - image_base;
@@ -1430,9 +1487,9 @@ pe_resource_dir_push_dir_node(Arena *arena, PE_ResourceDir *dir, COFF_ResourceID
PE_ResourceList *list = 0;
switch (id.type) {
default:
case COFF_ResourceIDType_NULL: break;
case COFF_ResourceIDType_STRING: list = &dir->named_list; break;
case COFF_ResourceIDType_NUMBER: list = &dir->id_list; break;
case COFF_ResourceIDType_Null: break;
case COFF_ResourceIDType_String: list = &dir->named_list; break;
case COFF_ResourceIDType_Number: list = &dir->id_list; break;
}
PE_ResourceNode *res_node = push_array(arena, PE_ResourceNode, 1);
@@ -1459,9 +1516,9 @@ pe_resource_dir_push_entry_node(Arena *arena, PE_ResourceDir *dir, COFF_Resource
PE_ResourceList *list = NULL;
switch (id.type) {
default:
case COFF_ResourceIDType_NULL: break;
case COFF_ResourceIDType_STRING: list = &dir->named_list; break;
case COFF_ResourceIDType_NUMBER: list = &dir->id_list; break;
case COFF_ResourceIDType_Null: break;
case COFF_ResourceIDType_String: list = &dir->named_list; break;
case COFF_ResourceIDType_Number: list = &dir->id_list; break;
}
PE_ResourceNode *res_node = push_array(arena, PE_ResourceNode, 1);
@@ -1498,7 +1555,7 @@ internal PE_ResourceNode *
pe_resource_dir_search_node(PE_ResourceDir *dir, COFF_ResourceID id)
{
for (PE_ResourceNode *i = dir->id_list.first; i != NULL; i = i->next) {
if (coff_resource_id_is_equal(i->data.id, id)) {
if (coff_resource_id_compar(&i->data.id, &id)) {
return i;
}
}
@@ -1529,11 +1586,11 @@ pe_resource_dir_push_res_file(Arena *arena, PE_ResourceDir *root_dir, String8 re
{
// parse file into resource list
String8 res_data = str8_substr(res_file, rng_1u64(sizeof(PE_RES_MAGIC), res_file.size));
COFF_ResourceList list = coff_resource_list_from_data(arena, res_data);
COFF_ParsedResourceList list = coff_resource_list_from_data(arena, res_data);
// move resources to directories based on type
for (COFF_ResourceNode *res_node = list.first; res_node != NULL; res_node = res_node->next) {
COFF_Resource *res = &res_node->data;
for (COFF_ParsedResourceNode *res_node = list.first; res_node != NULL; res_node = res_node->next) {
COFF_ParsedResource *res = &res_node->data;
// search existing directories
PE_Resource *dir_res = pe_resource_dir_search(root_dir, res->type);
@@ -1555,7 +1612,7 @@ pe_resource_dir_push_res_file(Arena *arena, PE_ResourceDir *root_dir, String8 re
// push entry
PE_Resource *sub_dir_res = pe_resource_dir_push_dir(arena, dir, res->name, 0, 0, 0, 0);
COFF_ResourceID id;
id.type = COFF_ResourceIDType_NUMBER;
id.type = COFF_ResourceIDType_Number;
id.u.number = res->language_id;
pe_resource_dir_push_entry(arena, sub_dir_res->u.dir, id, res->type, res->data_version, res->version, res->memory_flags, res->data);
}
@@ -1616,7 +1673,7 @@ pe_resource_table_from_directory_data(Arena *arena, String8 data)
str8_deserial_read_struct(data, entry_offset, &coff_entry);
// NOTE: this is not documented on MSDN but high bit here is set for some reason
U32 name_offset = coff_entry.name.offset & ~COFF_RESOURCE_SUB_DIR_FLAG;
U32 name_offset = coff_entry.name.offset & ~COFF_Resource_SubDirFlag;
U16 name_size = 0;
str8_deserial_read_struct(data, name_offset, &name_size);
@@ -1624,15 +1681,15 @@ pe_resource_table_from_directory_data(Arena *arena, String8 data)
str8_deserial_read_block(data, name_offset + sizeof(name_size), name_size*sizeof(U16), &name_block);
String16 name16 = str16((U16*)name_block.str, name_size);
B32 is_dir = !!(coff_entry.id.data_entry_offset & COFF_RESOURCE_SUB_DIR_FLAG);
B32 is_dir = !!(coff_entry.id.data_entry_offset & COFF_Resource_SubDirFlag);
entry->id.type = COFF_ResourceIDType_STRING;
entry->id.type = COFF_ResourceIDType_String;
entry->id.u.string = str8_from_16(arena, name16);
entry->kind = is_dir ? PE_ResDataKind_DIR : PE_ResDataKind_COFF_LEAF;
if (is_dir) {
struct stack_s *frame = push_array(scratch.arena, struct stack_s, 1);
frame->table_offset = coff_entry.id.sub_dir_offset & ~COFF_RESOURCE_SUB_DIR_FLAG;
frame->table_offset = coff_entry.id.sub_dir_offset & ~COFF_Resource_SubDirFlag;
frame->directory_ptr = &entry->u.dir;
SLLStackPush(stack, frame);
goto yeild;
@@ -1653,15 +1710,15 @@ pe_resource_table_from_directory_data(Arena *arena, String8 data)
COFF_ResourceDirEntry coff_entry = {0};
str8_deserial_read_struct(data, entry_offset, &coff_entry);
B32 is_dir = !!(coff_entry.id.sub_dir_offset & COFF_RESOURCE_SUB_DIR_FLAG);
B32 is_dir = !!(coff_entry.id.sub_dir_offset & COFF_Resource_SubDirFlag);
entry->id.type = COFF_ResourceIDType_NUMBER;
entry->id.type = COFF_ResourceIDType_Number;
entry->id.u.number = coff_entry.name.id;
entry->kind = is_dir ? PE_ResDataKind_DIR : PE_ResDataKind_COFF_LEAF;
if (is_dir) {
struct stack_s *frame = push_array(scratch.arena, struct stack_s, 1);
frame->table_offset = coff_entry.id.sub_dir_offset & ~COFF_RESOURCE_SUB_DIR_FLAG;
frame->table_offset = coff_entry.id.sub_dir_offset & ~COFF_Resource_SubDirFlag;
frame->directory_ptr = &entry->u.dir;
SLLStackPush(stack, frame);
goto yeild;
@@ -1683,11 +1740,11 @@ internal String8
pe_make_manifest_resource(Arena *arena, U32 resource_id, String8 manifest_data)
{
COFF_ResourceID type = {0};
type.type = COFF_ResourceIDType_NUMBER;
type.type = COFF_ResourceIDType_Number;
type.u.number = PE_ResourceKind_MANIFEST;
COFF_ResourceID id = {0};
id.type = COFF_ResourceIDType_NUMBER;
id.type = COFF_ResourceIDType_Number;
id.u.number = resource_id;
String8 res = coff_write_resource(arena, type, id, 1, 0, 1033, 0, 0, manifest_data);
+42 -5
View File
@@ -1003,17 +1003,53 @@ struct PE_BinInfo
U64 symbol_array_off;
U64 symbol_count;
U64 string_table_off;
U64 dbg_path_off;
U64 dbg_path_size;
Guid dbg_guid;
U32 dbg_age;
U32 dbg_time;
Arch arch;
Rng1U64 *data_dir_franges;
U32 data_dir_count;
PE_TLSHeader64 tls_header;
};
typedef struct PE_DebugInfo
{
PE_DebugDirectory header;
union
{
union
{
U32 magic;
struct
{
PE_CvHeaderPDB20 header;
String8 path;
} pdb20;
struct
{
PE_CvHeaderPDB70 header;
String8 path;
} pdb70;
struct
{
PE_CvHeaderRDI header;
String8 path;
} rdi;
} codeview;
String8 raw_data;
} u;
} PE_DebugInfo;
typedef struct PE_DebugInfoNode
{
struct PE_DebugInfoNode *next;
PE_DebugInfo v;
} PE_DebugInfoNode;
typedef struct PE_DebugInfoList
{
PE_DebugInfoNode *first;
PE_DebugInfoNode *last;
U64 count;
} PE_DebugInfoList;
////////////////////////////////
//~ rjf: Basic Enum Functions
@@ -1038,6 +1074,7 @@ internal String8 pe_string_from_dll_characteristics(Arena *arena, PE_DllCharacte
internal PE_BinInfo pe_bin_info_from_data(Arena *arena, String8 data);
internal PE_DebugInfoList pe_parse_debug_directory(Arena *arena, String8 raw_image, String8 raw_debug_dir);
internal PE_ParsedStaticImportTable pe_static_imports_from_data(Arena *arena, B32 is_pe32, U64 section_count, COFF_SectionHeader *sections, String8 raw_data, Rng1U64 dir_file_range);
internal PE_ParsedDelayImportTable pe_delay_imports_from_data(Arena *arena, B32 is_pe32, U64 section_count, COFF_SectionHeader *sections, String8 raw_data, Rng1U64 dir_file_range);
internal PE_ParsedExportTable pe_exports_from_data(Arena *arena, U64 section_count, COFF_SectionHeader *sections, String8 raw_data, Rng1U64 dir_file_range, Rng1U64 dir_virt_range);
+526
View File
@@ -1031,6 +1031,327 @@ rd_name_release(String8 string)
SLLStackPush(rd_state->free_name_chunks[bucket_idx], node);
}
////////////////////////////////
//~ rjf: New Config/Entity Data Structure Functions
internal RD_Cfg *
rd_cfg_alloc(void)
{
RD_Cfg *result = rd_state->free_cfg;
if(result)
{
SLLStackPop(rd_state->free_cfg);
}
else
{
result = push_array_no_zero(rd_state->arena, RD_Cfg, 1);
}
U64 old_gen = result->gen;
MemoryZeroStruct(result);
result->first = result->last = result->next = result->prev = result->parent = &rd_nil_cfg;
result->gen = old_gen + 1;
return result;
}
internal void
rd_cfg_release(RD_Cfg *cfg)
{
Temp scratch = scratch_begin(0, 0);
rd_cfg_unhook(cfg->parent, cfg);
RD_CfgList nodes = {0};
for(RD_Cfg *c = cfg; c != &rd_nil_cfg; c = rd_cfg_rec__depth_first(cfg, c).next)
{
rd_cfg_list_push(scratch.arena, &nodes, c);
}
for(RD_CfgNode *n = nodes.first; n != 0; n = n->next)
{
RD_Cfg *c = n->v;
c->gen += 1;
rd_name_release(c->string);
SLLStackPush(rd_state->free_cfg, c);
}
scratch_end(scratch);
}
internal RD_Cfg *
rd_cfg_new(RD_Cfg *parent, String8 string)
{
RD_Cfg *cfg = rd_cfg_alloc();
rd_cfg_insert_child(parent, parent->last, cfg);
rd_cfg_equip_string(cfg, string);
return cfg;
}
internal RD_Cfg *
rd_cfg_newf(RD_Cfg *parent, char *fmt, ...)
{
Temp scratch = scratch_begin(0, 0);
va_list args;
va_start(args, fmt);
String8 string = push_str8fv(scratch.arena, fmt, args);
RD_Cfg *result = rd_cfg_new(parent, string);
va_end(args);
scratch_end(scratch);
return result;
}
internal void
rd_cfg_equip_string(RD_Cfg *cfg, String8 string)
{
if(cfg->string.size != 0)
{
rd_name_release(cfg->string);
}
cfg->string = rd_name_alloc(string);
}
internal void
rd_cfg_insert_child(RD_Cfg *parent, RD_Cfg *prev_child, RD_Cfg *new_child)
{
DLLInsert_NPZ(&rd_nil_cfg, parent->first, parent->last, prev_child, new_child, next, prev);
new_child->parent = parent;
}
internal void
rd_cfg_unhook(RD_Cfg *parent, RD_Cfg *child)
{
if(parent == child->parent && parent != &rd_nil_cfg)
{
DLLRemove_NPZ(&rd_nil_cfg, parent->first, parent->last, child, next, prev);
child->parent = &rd_nil_cfg;
}
}
internal RD_Cfg *
rd_cfg_child_from_string(RD_Cfg *parent, String8 string)
{
RD_Cfg *child = &rd_nil_cfg;
for(RD_Cfg *c = parent->first; c != &rd_nil_cfg; c = c->next)
{
if(str8_match(c->string, string, 0))
{
child = c;
break;
}
}
return child;
}
internal RD_CfgList
rd_cfg_child_list_from_string(Arena *arena, RD_Cfg *parent, String8 string)
{
RD_CfgList result = {0};
for(RD_Cfg *child = parent->first; child != &rd_nil_cfg; child = child->next)
{
if(str8_match(child->string, string, 0))
{
rd_cfg_list_push(arena, &result, child);
}
}
return result;
}
internal RD_CfgList
rd_cfg_top_level_list_from_string(Arena *arena, String8 string)
{
RD_CfgList result = {0};
for(RD_Cfg *bucket = rd_state->root_cfg->first; bucket != &rd_nil_cfg; bucket = bucket->next)
{
for(RD_Cfg *tln = bucket->first; tln != &rd_nil_cfg; tln = tln->next)
{
if(str8_match(tln->string, string, 0))
{
rd_cfg_list_push(arena, &result, tln);
}
}
}
return result;
}
internal RD_CfgList
rd_cfg_tree_list_from_string(Arena *arena, String8 string)
{
RD_CfgList result = {0};
Temp scratch = scratch_begin(&arena, 1);
MD_Node *root = md_tree_from_string(scratch.arena, string);
for MD_EachNode(tln, root->first)
{
RD_Cfg *dst_root_n = &rd_nil_cfg;
RD_Cfg *dst_active_parent_n = &rd_nil_cfg;
MD_NodeRec rec = {0};
for(MD_Node *src_n = tln; !md_node_is_nil(src_n); src_n = rec.next)
{
RD_Cfg *dst_n = rd_cfg_alloc();
rd_cfg_equip_string(dst_n, src_n->string);
if(dst_active_parent_n != &rd_nil_cfg)
{
rd_cfg_insert_child(dst_active_parent_n, dst_active_parent_n->last, dst_n);
}
rec = md_node_rec_depth_first_pre(src_n, tln);
if(rec.push_count > 0)
{
if(dst_active_parent_n == &rd_nil_cfg)
{
dst_root_n = dst_n;
}
dst_active_parent_n = dst_n;
}
else for(S32 pop_idx = 0; pop_idx < rec.pop_count; pop_idx += 1)
{
dst_active_parent_n = dst_active_parent_n->parent;
}
}
rd_cfg_list_push(arena, &result, dst_root_n);
}
scratch_end(scratch);
return result;
}
internal String8
rd_string_from_cfg_tree(Arena *arena, RD_Cfg *cfg)
{
Temp scratch = scratch_begin(&arena, 1);
String8List strings = {0};
{
typedef struct NestTask NestTask;
struct NestTask
{
NestTask *next;
RD_Cfg *cfg;
B32 is_simple;
};
NestTask *top_nest_task = 0;
RD_CfgRec rec = {0};
for(RD_Cfg *c = cfg; c != &rd_nil_cfg; c = rec.next)
{
// rjf: push name of this node
if(c->string.size != 0 || c->first == &rd_nil_cfg)
{
String8List c_name_strings = {0};
B32 name_can_be_pushed_standalone = 0;
{
Temp temp = temp_begin(scratch.arena);
MD_TokenizeResult c_name_tokenize = md_tokenize_from_text(temp.arena, c->string);
name_can_be_pushed_standalone = (c_name_tokenize.tokens.count == 1 && c_name_tokenize.tokens.v[0].flags & (MD_TokenFlag_Identifier|
MD_TokenFlag_Numeric|
MD_TokenFlag_StringLiteral|
MD_TokenFlag_Symbol));
temp_end(temp);
}
if(name_can_be_pushed_standalone)
{
str8_list_push(scratch.arena, &c_name_strings, c->string);
}
else
{
String8 c_name_escaped = escaped_from_raw_str8(scratch.arena, c->string);
str8_list_push(scratch.arena, &c_name_strings, str8_lit("\""));
str8_list_push(scratch.arena, &c_name_strings, c_name_escaped);
str8_list_push(scratch.arena, &c_name_strings, str8_lit("\""));
}
if(top_nest_task != 0 && top_nest_task->is_simple)
{
str8_list_push(scratch.arena, &strings, str8_lit(" "));
}
str8_list_concat_in_place(&strings, &c_name_strings);
}
// rjf: grab next recursion
rec = rd_cfg_rec__depth_first(cfg, c);
// rjf: determine if this node is simple, and can be encoded on a single line -
// if so, push a new nesting task onto the stack
if(c->first != &rd_nil_cfg)
{
B32 is_simple_children_list = 1;
for(RD_Cfg *child = c->first; child != &rd_nil_cfg; child = child->next)
{
if(child->first != &rd_nil_cfg && child != c->last)
{
is_simple_children_list = 0;
break;
}
}
NestTask *task = push_array(scratch.arena, NestTask, 1);
task->cfg = c;
task->is_simple = is_simple_children_list;
SLLStackPush(top_nest_task, task);
}
// rjf: tree navigations -> encode hierarchy
if(rec.push_count > 0)
{
if(top_nest_task->is_simple && c->string.size != 0)
{
str8_list_push(scratch.arena, &strings, str8_lit(":"));
}
else
{
if(c->string.size != 0)
{
str8_list_push(scratch.arena, &strings, str8_lit(":\n"));
}
str8_list_push(scratch.arena, &strings, str8_lit("{"));
}
}
else
{
for(S32 pop_idx = 0; pop_idx < rec.pop_count; pop_idx += 1, SLLStackPop(top_nest_task))
{
if(top_nest_task->is_simple)
{
if(top_nest_task->cfg->string.size == 0)
{
str8_list_push(scratch.arena, &strings, str8_lit(" }"));
}
}
else
{
str8_list_push(scratch.arena, &strings, str8_lit("\n}"));
}
}
}
if(!top_nest_task || top_nest_task->is_simple == 0)
{
str8_list_push(scratch.arena, &strings, str8_lit("\n"));
}
}
}
String8 result_unindented = str8_list_join(scratch.arena, &strings, 0);
String8 result = indented_from_string(arena, result_unindented);
scratch_end(scratch);
return result;
}
internal RD_CfgRec
rd_cfg_rec__depth_first(RD_Cfg *root, RD_Cfg *cfg)
{
RD_CfgRec rec = {&rd_nil_cfg};
if(cfg->first != &rd_nil_cfg)
{
rec.next = cfg->first;
rec.push_count = 1;
}
else for(RD_Cfg *p = cfg; p != root; p = p->parent, rec.pop_count += 1)
{
if(p->next != &rd_nil_cfg)
{
rec.next = p->next;
break;
}
}
return rec;
}
internal void
rd_cfg_list_push(Arena *arena, RD_CfgList *list, RD_Cfg *cfg)
{
RD_CfgNode *n = push_array(arena, RD_CfgNode, 1);
n->v = cfg;
SLLQueuePush(list->first, list->last, n);
list->count += 1;
}
////////////////////////////////
//~ rjf: Entity State Functions
@@ -11169,6 +11490,15 @@ rd_init(CmdLine *cmdln)
rd_state->top_regs = &rd_state->base_regs;
rd_clear_bindings();
// rjf: set up top-level config entity trees
{
rd_state->root_cfg = rd_cfg_alloc();
RD_Cfg *user_tree = rd_cfg_new(rd_state->root_cfg, str8_lit("user"));
RD_Cfg *project_tree = rd_cfg_new(rd_state->root_cfg, str8_lit("project"));
RD_Cfg *command_line_tree = rd_cfg_new(rd_state->root_cfg, str8_lit("command_line"));
RD_Cfg *transient = rd_cfg_new(rd_state->root_cfg, str8_lit("transient"));
}
// rjf: set up user / project paths
{
Temp scratch = scratch_begin(0, 0);
@@ -11332,6 +11662,12 @@ rd_frame(void)
local_persist S32 depth = 0;
log_scope_begin();
//- TODO(rjf): @cfg debugging: stringify the current cfg tree
{
String8 string = rd_string_from_cfg_tree(scratch.arena, rd_state->root_cfg);
int x = 0;
}
//////////////////////////////
//- rjf: do per-frame resets
//
@@ -12147,6 +12483,32 @@ rd_frame(void)
case RD_CmdKind_OpenUser:
case RD_CmdKind_OpenProject:
{
//- TODO(rjf): @cfg load & apply user/project data to the cfg data structure
{
String8 file_root_key = (kind == RD_CmdKind_OpenUser ? str8_lit("user") : str8_lit("project"));
RD_Cfg *file_root = rd_cfg_child_from_string(rd_state->root_cfg, file_root_key);
//- rjf: eliminate all old state under this file tree
for(RD_Cfg *tln = file_root->first, *next = &rd_nil_cfg;
tln != &rd_nil_cfg;
tln = next)
{
next = tln->next;
rd_cfg_release(tln);
}
//- rjf: load & parse the new file, generate cfg entities for it
String8 file_path = rd_regs()->file_path;
String8 file_data = os_data_from_file_path(scratch.arena, file_path);
RD_CfgList file_cfg_list = rd_cfg_tree_list_from_string(scratch.arena, file_data);
//- rjf: insert the new cfg entities into this file tree
for(RD_CfgNode *n = file_cfg_list.first; n != 0; n = n->next)
{
rd_cfg_insert_child(file_root, file_root->last, n->v);
}
}
// TODO(rjf): dear lord this is so overcomplicated, this needs to be collapsed down & simplified ASAP
B32 load_cfg[RD_CfgSrc_COUNT] = {0};
@@ -12320,6 +12682,32 @@ rd_frame(void)
//- rjf: keep track of recent projects
if(src == RD_CfgSrc_Project)
{
//- TODO(rjf): @cfg keep track of recent projects
{
RD_Cfg *user = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("user"));
RD_CfgList recent_projects = rd_cfg_child_list_from_string(scratch.arena, user, str8_lit("recent_project"));
RD_Cfg *recent_project = &rd_nil_cfg;
for(RD_CfgNode *n = recent_projects.first; n != 0; n = n->next)
{
if(path_match_normalized(n->v->string, cfg_path))
{
recent_project = n->v;
break;
}
}
if(recent_project == &rd_nil_cfg)
{
recent_project = rd_cfg_new(user, str8_lit("recent_project"));
rd_cfg_new(recent_project, path_normalized_from_string(scratch.arena, cfg_path));
}
rd_cfg_unhook(user, recent_project);
rd_cfg_insert_child(user, &rd_nil_cfg, recent_project);
recent_projects = rd_cfg_child_list_from_string(scratch.arena, user, str8_lit("recent_project"));
if(recent_projects.count > 32)
{
rd_cfg_release(recent_projects.last->v);
}
}
RD_EntityList recent_projects = rd_query_cached_entity_list_with_kind(RD_EntityKind_RecentProject);
RD_Entity *recent_project = &rd_nil_entity;
for(RD_EntityNode *n = recent_projects.first; n != 0; n = n->next)
@@ -13548,6 +13936,15 @@ rd_frame(void)
String8 map_dst = str8_list_join(scratch.arena, &map_dst_parts, &map_join);
//- rjf: store as file path map entity
//- TODO(rjf): @cfg store as file path map entity
{
RD_Cfg *user = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("user"));
RD_Cfg *map = rd_cfg_new(user, str8_lit("file_path_map"));
RD_Cfg *src = rd_cfg_new(map, str8_lit("source"));
RD_Cfg *dst = rd_cfg_new(map, str8_lit("dest"));
rd_cfg_new(src, map_src);
rd_cfg_new(dst, map_dst);
}
RD_Entity *map = rd_entity_alloc(rd_entity_root(), RD_EntityKind_FilePathMap);
RD_Entity *src = rd_entity_alloc(map, RD_EntityKind_Source);
RD_Entity *dst = rd_entity_alloc(map, RD_EntityKind_Dest);
@@ -13880,6 +14277,34 @@ rd_frame(void)
if(rd_regs()->file_path.size != 0)
{
String8 path = path_normalized_from_string(scratch.arena, rd_regs()->file_path);
//- TODO(rjf): @cfg record file in project
{
RD_Cfg *project = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("project"));
RD_CfgList recent_files = rd_cfg_child_list_from_string(scratch.arena, project, str8_lit("recent_files"));
RD_Cfg *recent_file = &rd_nil_cfg;
for(RD_CfgNode *n = recent_files.first; n != 0; n = n->next)
{
if(path_match_normalized(n->v->string, path))
{
recent_file = n->v;
break;
}
}
if(recent_file == &rd_nil_cfg)
{
recent_file = rd_cfg_new(project, str8_lit("recent_file"));
rd_cfg_new(recent_file, path);
}
rd_cfg_unhook(project, recent_file);
rd_cfg_insert_child(project, &rd_nil_cfg, recent_file);
recent_files = rd_cfg_child_list_from_string(scratch.arena, project, str8_lit("recent_files"));
if(recent_files.count > 256)
{
rd_cfg_release(recent_files.last->v);
}
}
RD_EntityList recent_files = rd_query_cached_entity_list_with_kind(RD_EntityKind_RecentFile);
if(recent_files.count >= 256)
{
@@ -15075,6 +15500,49 @@ rd_frame(void)
U64 vaddr = rd_regs()->vaddr;
if(file_path.size != 0 || string.size != 0 || vaddr != 0)
{
//- TODO(rjf): @cfg add/toggle breakpoint
{
B32 removed_already_existing = 0;
if(kind == RD_CmdKind_ToggleBreakpoint)
{
RD_CfgList bps = rd_cfg_top_level_list_from_string(scratch.arena, str8_lit("breakpoint"));
for(RD_CfgNode *n = bps.first; n != 0; n = n->next)
{
RD_Cfg *bp = n->v;
RD_Cfg *loc = rd_cfg_child_from_string(bp, str8_lit("location"));
S64 loc_line = 0;
U64 loc_vaddr = 0;
B32 loc_matches_file_pt = (file_path.size != 0 && path_match_normalized(loc->first->string, file_path) && try_s64_from_str8_c_rules(loc->first->first->string, &loc_line) && loc_line == pt.line);
B32 loc_matches_string = (string.size != 0 && str8_match(loc->first->string, string, 0));
B32 loc_matches_vaddr = (vaddr != 0 && try_u64_from_str8_c_rules(loc->first->string, &loc_vaddr) && loc_vaddr == vaddr);
if(loc_matches_file_pt || loc_matches_string || loc_matches_vaddr)
{
rd_cfg_release(bp);
removed_already_existing = 1;
break;
}
}
}
if(!removed_already_existing)
{
RD_Cfg *project = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("project"));
RD_Cfg *bp = rd_cfg_new(project, str8_lit("breakpoint"));
RD_Cfg *loc = rd_cfg_new(bp, str8_lit("location"));
if(vaddr != 0)
{
rd_cfg_newf(loc, "0x%I64x", vaddr);
}
else if(string.size != 0)
{
rd_cfg_new(loc, string);
}
else if(file_path.size != 0)
{
RD_Cfg *file_path_cfg = rd_cfg_new(loc, file_path);
rd_cfg_newf(file_path_cfg, "%I64d", pt.line);
}
}
}
B32 removed_already_existing = 0;
if(kind == RD_CmdKind_ToggleBreakpoint)
{
@@ -15131,6 +15599,48 @@ rd_frame(void)
TxtPt pt = rd_regs()->cursor;
String8 string = rd_regs()->string;
U64 vaddr = rd_regs()->vaddr;
//- TODO(rjf): @cfg add/toggle watch pin
{
B32 removed_already_existing = 0;
if(kind == RD_CmdKind_ToggleWatchPin)
{
RD_CfgList wps = rd_cfg_top_level_list_from_string(scratch.arena, str8_lit("watch_pin"));
for(RD_CfgNode *n = wps.first; n != 0; n = n->next)
{
RD_Cfg *wp = n->v;
RD_Cfg *name = rd_cfg_child_from_string(wp, str8_lit("name"));
RD_Cfg *loc = rd_cfg_child_from_string(wp, str8_lit("location"));
S64 loc_line = 0;
U64 loc_vaddr = 0;
B32 loc_matches_file_pt = (file_path.size != 0 && path_match_normalized(loc->first->string, file_path) && try_s64_from_str8_c_rules(loc->first->first->string, &loc_line) && loc_line == pt.line);
B32 loc_matches_vaddr = (vaddr != 0 && try_u64_from_str8_c_rules(loc->first->string, &loc_vaddr) && loc_vaddr == vaddr);
B32 loc_matches_expr = (string.size != 0 && str8_match(name->first->string, string, 0));
if(loc_matches_expr && (loc_matches_file_pt || loc_matches_vaddr))
{
rd_cfg_release(wp);
removed_already_existing = 1;
break;
}
}
}
if(!removed_already_existing)
{
RD_Cfg *project = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("project"));
RD_Cfg *wp = rd_cfg_new(project, str8_lit("watch_pin"));
RD_Cfg *name = rd_cfg_new(wp, str8_lit("name"));
RD_Cfg *loc = rd_cfg_new(wp, str8_lit("location"));
rd_cfg_new(name, string);
if(vaddr != 0)
{
rd_cfg_newf(loc, "0x%I64x", vaddr);
}
else if(file_path.size != 0)
{
RD_Cfg *file_path_cfg = rd_cfg_new(loc, file_path);
rd_cfg_newf(file_path_cfg, "%I64d", pt.line);
}
}
}
B32 removed_already_existing = 0;
if(kind == RD_CmdKind_ToggleWatchPin)
{
@@ -15251,6 +15761,22 @@ rd_frame(void)
//- rjf: targets
case RD_CmdKind_AddTarget:
{
//- TODO(rjf): @cfg add new target
{
String8 file_path = rd_regs()->file_path;
RD_Cfg *project = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("project"));
RD_Cfg *target = rd_cfg_new(project, str8_lit("target"));
RD_Cfg *exe = rd_cfg_new(target, str8_lit("executable"));
rd_cfg_new(exe, file_path);
String8 working_directory = str8_chop_last_slash(file_path);
if(working_directory.size != 0)
{
RD_Cfg *wdir = rd_cfg_new(target, str8_lit("working_directory"));
rd_cfg_newf(wdir, "%S/", working_directory);
}
// TODO(rjf): (select target here)
}
// rjf: build target
RD_Entity *entity = &rd_nil_entity;
entity = rd_entity_alloc(rd_entity_root(), RD_EntityKind_Target);
+70 -1
View File
@@ -376,6 +376,44 @@ struct RD_CfgTable
RD_CfgVal *last_val;
};
////////////////////////////////
//~ rjf: New Config/Entity Data Structure
typedef struct RD_Cfg RD_Cfg;
struct RD_Cfg
{
RD_Cfg *first;
RD_Cfg *last;
RD_Cfg *next;
RD_Cfg *prev;
RD_Cfg *parent;
U64 gen;
String8 string;
};
typedef struct RD_CfgNode RD_CfgNode;
struct RD_CfgNode
{
RD_CfgNode *next;
RD_Cfg *v;
};
typedef struct RD_CfgList RD_CfgList;
struct RD_CfgList
{
RD_CfgNode *first;
RD_CfgNode *last;
U64 count;
};
typedef struct RD_CfgRec RD_CfgRec;
struct RD_CfgRec
{
RD_Cfg *next;
S32 push_count;
S32 pop_count;
};
////////////////////////////////
//~ rjf: Entity Types
@@ -836,12 +874,16 @@ struct RD_State
RD_RegSlot drag_drop_regs_slot;
RD_DragDropState drag_drop_state;
// rjf: cfg state
RD_NameChunkNode *free_name_chunks[8];
RD_Cfg *free_cfg;
RD_Cfg *root_cfg;
//-
// TODO(rjf): TO BE ELIMINATED OR REPLACED VVVVVVVVVVVVVVVV
//-
// rjf: entity state
RD_NameChunkNode *free_name_chunks[8];
Arena *entities_arena;
RD_Entity *entities_base;
U64 entities_count;
@@ -914,6 +956,15 @@ struct RD_State
read_only global RD_CfgTree d_nil_cfg_tree = {&d_nil_cfg_tree, RD_CfgSrc_User, &md_nil_node};
read_only global RD_CfgVal d_nil_cfg_val = {&d_nil_cfg_val, &d_nil_cfg_val, &d_nil_cfg_tree, &d_nil_cfg_tree};
read_only global RD_Cfg rd_nil_cfg =
{
&rd_nil_cfg,
&rd_nil_cfg,
&rd_nil_cfg,
&rd_nil_cfg,
&rd_nil_cfg,
};
read_only global RD_Entity rd_nil_entity =
{
&rd_nil_entity,
@@ -1097,6 +1148,24 @@ internal U64 rd_name_bucket_idx_from_string_size(U64 size);
internal String8 rd_name_alloc(String8 string);
internal void rd_name_release(String8 string);
////////////////////////////////
//~ rjf: New Config/Entity Data Structure Functions
internal RD_Cfg *rd_cfg_alloc(void);
internal void rd_cfg_release(RD_Cfg *cfg);
internal RD_Cfg *rd_cfg_new(RD_Cfg *parent, String8 string);
internal RD_Cfg *rd_cfg_newf(RD_Cfg *parent, char *fmt, ...);
internal void rd_cfg_equip_string(RD_Cfg *cfg, String8 string);
internal void rd_cfg_insert_child(RD_Cfg *parent, RD_Cfg *prev_child, RD_Cfg *new_child);
internal void rd_cfg_unhook(RD_Cfg *parent, RD_Cfg *child);
internal RD_Cfg *rd_cfg_child_from_string(RD_Cfg *parent, String8 string);
internal RD_CfgList rd_cfg_child_list_from_string(Arena *arena, RD_Cfg *parent, String8 string);
internal RD_CfgList rd_cfg_top_level_list_from_string(Arena *arena, String8 string);
internal RD_CfgList rd_cfg_tree_list_from_string(Arena *arena, String8 string);
internal String8 rd_string_from_cfg_tree(Arena *arena, RD_Cfg *cfg);
internal RD_CfgRec rd_cfg_rec__depth_first(RD_Cfg *root, RD_Cfg *cfg);
internal void rd_cfg_list_push(Arena *arena, RD_CfgList *list, RD_Cfg *cfg);
////////////////////////////////
//~ rjf: Entity Stateful Functions
+86 -2
View File
@@ -1,6 +1,31 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ rjf: feature cleanup, code dedup, code elimination pass:
//
// [ ] frontend config entities, serialization/deserialization, remove hacks,
// etc. - the entity structure should be dramatically simplified & made
// to reflect a more flexible string-tree data structure which can be
// more trivially derived from config, and more flexibly rearranged.
// drag/drop watch rows -> tabs, tabs -> watch rows, etc.
// [ ] frontend entities need to be the "upstream state" for windows, panels,
// tabs, etc. - entities can be mapped to caches of window/panel/view state
// in purely immediate-mode fashion, so the only *state* part of the
// equation only has to do with the string tree.
// [ ] config hot-reloading using the wins from the previous points
// [ ] undo/redo, using the wins from the previous points
// [ ] watch table UI - hidden table boundaries, special-cased control hacks
// [ ] hash store -> need to somehow hold on to hash blobs which are still
// depended upon by usage layers, e.g. extra dependency refcount, e.g.
// text cache can explicitly correllate nodes in its cache to hashes,
// bump their refcount - this would keep the hash correllated to its key
// and it would prevent it from being evicted (output debug string perf)
// [ ] autocompletion lister, file lister, function lister, command lister,
// etc., all need to be merged, and optionally contextualized/filtered.
// right-clicking a tab should be equivalent to spawning a command lister,
// but only with commands that are directly
////////////////////////////////
//~ rjf: post-0.9.12 TODO notes
//
@@ -315,9 +340,10 @@
#include "mutable_text/mutable_text.h"
#include "path/path.h"
#include "coff/coff.h"
#include "coff/coff_parse.h"
#include "pe/pe.h"
#include "codeview/codeview.h"
#include "codeview/codeview_stringize.h"
#include "codeview/codeview_parse.h"
#include "msf/msf.h"
#include "msf/msf_parse.h"
#include "pdb/pdb.h"
@@ -356,9 +382,10 @@
#include "mutable_text/mutable_text.c"
#include "path/path.c"
#include "coff/coff.c"
#include "coff/coff_parse.c"
#include "pe/pe.c"
#include "codeview/codeview.c"
#include "codeview/codeview_stringize.c"
#include "codeview/codeview_parse.c"
#include "msf/msf.c"
#include "msf/msf_parse.c"
#include "pdb/pdb.c"
@@ -574,6 +601,63 @@ entry_point(CmdLine *cmd_line)
String8List args = cmd_line->inputs;
if(args.node_count > 0 && args.first->string.size != 0)
{
//- TODO(rjf): @cfg setup initial target from command line arguments
{
Temp scratch = scratch_begin(0, 0);
//- rjf: unpack command line inputs
String8 executable_name_string = {0};
String8 arguments_string = {0};
String8 working_directory_string = {0};
{
// rjf: unpack full executable path
if(args.first->string.size != 0)
{
String8 current_path = os_get_current_path(scratch.arena);
String8 exe_name = args.first->string;
PathStyle style = path_style_from_str8(exe_name);
if(style == PathStyle_Relative)
{
exe_name = push_str8f(scratch.arena, "%S/%S", current_path, exe_name);
exe_name = path_normalized_from_string(scratch.arena, exe_name);
}
executable_name_string = exe_name;
}
// rjf: unpack working directory
if(args.first->string.size != 0)
{
String8 path_part_of_arg = str8_chop_last_slash(args.first->string);
if(path_part_of_arg.size != 0)
{
String8 path = push_str8f(scratch.arena, "%S/", path_part_of_arg);
working_directory_string = path;
}
}
// rjf: unpack arguments
String8List passthrough_args_list = {0};
for(String8Node *n = args.first->next; n != 0; n = n->next)
{
str8_list_push(scratch.arena, &passthrough_args_list, n->string);
}
StringJoin join = {str8_lit(""), str8_lit(" "), str8_lit("")};
arguments_string = str8_list_join(scratch.arena, &passthrough_args_list, &join);
}
//- rjf: build config tree
RD_Cfg *command_line_root = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("command_line"));
RD_Cfg *target = rd_cfg_new(command_line_root, str8_lit("target"));
RD_Cfg *exe = rd_cfg_new(target, str8_lit("executable"));
RD_Cfg *args = rd_cfg_new(target, str8_lit("arguments"));
RD_Cfg *wdir = rd_cfg_new(target, str8_lit("working_directory"));
rd_cfg_new(exe, executable_name_string);
rd_cfg_new(args, arguments_string);
rd_cfg_new(wdir, working_directory_string);
scratch_end(scratch);
}
Temp scratch = scratch_begin(0, 0);
RD_Entity *target = rd_entity_alloc(rd_entity_root(), RD_EntityKind_Target);
rd_entity_equip_cfg_src(target, RD_CfgSrc_CommandLine);
File diff suppressed because it is too large Load Diff
+276
View File
@@ -0,0 +1,276 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef RADDUMP_H
#define RADDUMP_H
#define RD_INDENT_WIDTH 2
#define RD_INDENT_MAX 4096
#define rd_printf(f, ...) str8_list_pushf(arena, out, "%S" f, indent, __VA_ARGS__)
#define rd_newline() str8_list_pushf(arena, out, "");
#define rd_errorf(f, ...) rd_stderr("ERROR: "f, __VA_ARGS__)
#define rd_warningf(f, ...) rd_stderr("WARNING: "f, __VA_ARGS__)
#define rd_indent() do { if (indent.size + RD_INDENT_WIDTH <= RD_INDENT_MAX) { indent.size += RD_INDENT_WIDTH; } else { Assert(!"indent overflow"); } } while (0)
#define rd_unindent() do { if (indent.size >= RD_INDENT_WIDTH) { indent.size -= RD_INDENT_WIDTH; } else { Assert(!"unbalanced indent"); } } while (0)
typedef U64 RD_Option;
#define RD_Option_Help (1ull << 0)
#define RD_Option_Version (1ull << 1)
#define RD_Option_Headers (1ull << 2)
#define RD_Option_Sections (1ull << 3)
#define RD_Option_Debug (1ull << 4)
#define RD_Option_Imports (1ull << 5)
#define RD_Option_Exports (1ull << 6)
#define RD_Option_Disasm (1ull << 7)
#define RD_Option_Rawdata (1ull << 8)
#define RD_Option_Tls (1ull << 9)
#define RD_Option_Codeview (1ull << 10)
#define RD_Option_Symbols (1ull << 11)
#define RD_Option_Relocs (1ull << 12)
#define RD_Option_Exceptions (1ull << 13)
#define RD_Option_LoadConfig (1ull << 14)
#define RD_Option_Resources (1ull << 15)
#define RD_Option_LongNames (1ull << 16)
// DWARF
#define RD_Option_DebugInfo (1ull << 17)
#define RD_Option_DebugAbbrev (1ull << 18)
#define RD_Option_DebugLine (1ull << 19)
#define RD_Option_DebugStr (1ull << 20)
#define RD_Option_DebugLoc (1ull << 21)
#define RD_Option_DebugRanges (1ull << 22)
#define RD_Option_DebugARanges (1ull << 23)
#define RD_Option_DebugAddr (1ull << 24)
#define RD_Option_DebugLocLists (1ull << 25)
#define RD_Option_DebugRngLists (1ull << 26)
#define RD_Option_DebugPubNames (1ull << 27)
#define RD_Option_DebugPubTypes (1ull << 28)
#define RD_Option_DebugLineStr (1ull << 29)
#define RD_Option_DebugStrOffsets (1ull << 30)
#define RD_Option_Dwarf \
(RD_Option_DebugInfo | \
RD_Option_DebugAbbrev | \
RD_Option_DebugLine | \
RD_Option_DebugStr | \
RD_Option_DebugLoc | \
RD_Option_DebugRanges | \
RD_Option_DebugARanges | \
RD_Option_DebugAddr | \
RD_Option_DebugLocLists | \
RD_Option_DebugRngLists | \
RD_Option_DebugPubNames | \
RD_Option_DebugPubTypes | \
RD_Option_DebugLineStr | \
RD_Option_DebugStrOffsets)
#define RD_Option_RelaxDwarfParser (1ull << 31ull)
// RDI
#define RD_Option_NoRdi (1ull << 32ull)
#define RD_Option_RdiDataSections (1ull << 33ull)
#define RD_Option_RdiTopLevelInfo (1ull << 34ull)
#define RD_Option_RdiBinarySections (1ull << 35ull)
#define RD_Option_RdiFilePaths (1ull << 36ull)
#define RD_Option_RdiSourceFiles (1ull << 37ull)
#define RD_Option_RdiLineTables (1ull << 38ull)
#define RD_Option_RdiSourceLineMaps (1ull << 39ull)
#define RD_Option_RdiUnits (1ull << 40ull)
#define RD_Option_RdiUnitVMap (1ull << 41ull)
#define RD_Option_RdiTypeNodes (1ull << 42ull)
#define RD_Option_RdiUserDefinedTypes (1ull << 43ull)
#define RD_Option_RdiGlobalVars (1ull << 44ull)
#define RD_Option_RdiGlobalVarsVMap (1ull << 45ull)
#define RD_Option_RdiThreadVars (1ull << 46ull)
#define RD_Option_RdiProcedures (1ull << 48ull)
#define RD_Option_RdiScopes (1ull << 49ull)
#define RD_Option_RdiScopeVMap (1ull << 50ull)
#define RD_Option_RdiInlineSites (1ull << 51ull)
#define RD_Option_RdiNameMaps (1ull << 52ull)
#define RD_Option_RdiStrings (1ull << 53ull)
typedef struct RD_Marker
{
U64 off;
String8 string;
} RD_Marker;
typedef struct RD_MarkerArray
{
U64 count;
RD_Marker *v;
} RD_MarkerArray;
typedef struct MarkerNode
{
struct MarkerNode *next;
RD_Marker v;
} RD_MarkerNode;
typedef struct RD_MarkerList
{
U64 count;
RD_MarkerNode *first;
RD_MarkerNode *last;
} RD_MarkerList;
typedef struct RD_DisasmResult
{
String8 text;
U64 size;
} RD_DisasmResult;
typedef struct RD_Section
{
String8 name;
String8 raw_data;
} RD_Section;
typedef struct RD_SectionArray
{
U64 count;
RD_Section *v;
} RD_SectionArray;
typedef struct RD_Line
{
String8 file_path;
U32 line_num;
} RD_Line;
////////////////////////////////
// raddump
internal B32 rd_is_pe (String8 raw_data);
internal B32 rd_is_rdi(String8 raw_data);
internal String8 rd_string_from_flags(Arena *arena, String8List list, U64 remaining_flags);
internal void rd_format_preamble(Arena *arena, String8List *out, String8 indent, String8 input_path, String8 raw_data);
// Markers
internal RD_MarkerArray * rd_section_markers_from_coff_symbol_table(Arena *arena, String8 raw_data, U64 string_table_off, U64 section_count, COFF_Symbol32Array symbols);
// Sections
internal RD_SectionArray rd_sections_from_coff_section_table(Arena *arnea, String8 raw_image, U64 string_table_off, U64 section_count, COFF_SectionHeader *sections);
// Disasm
internal RD_DisasmResult rd_disasm_next_instruction(Arena *arena, Arch arch, U64 addr, String8 raw_code);
internal void rd_print_disasm (Arena *arena, String8List *out, String8 indent, Arch arch, U64 image_base, U64 sect_off, U64 marker_count, RD_Marker *markers, String8 raw_code);
// Raw Data
internal String8 rd_format_hex_array(Arena *arena, U8 *ptr, U64 size);
internal void rd_print_raw_data (Arena *arena, String8List *out, String8 indent, U64 bytes_per_row, U64 marker_count, RD_Marker *markers, String8 raw_data);
// RDI
internal String8 rdi_string_from_data_section_kind(Arena *arena, RDI_SectionKind v);
internal String8 rdi_string_from_arch (Arena *arena, RDI_Arch v);
internal String8 rdi_string_from_language (Arena *arena, RDI_Language v);
internal String8 rdi_string_from_local_kind (Arena *arena, RDI_LocalKind v);
internal String8 rdi_string_from_type_kind (Arena *arena, RDI_TypeKind v);
internal String8 rdi_string_from_member_kind (Arena *arena, RDI_MemberKind v);
internal String8 rdi_string_from_binary_section_flags(Arena *arena, RDI_BinarySectionFlags flags);
internal String8 rdi_string_from_type_modifier (Arena *arena, RDI_TypeModifierFlags flags);
internal String8 rdi_string_from_udt_flags (Arena *arena, RDI_UDTFlags flags);
internal String8 rdi_string_from_link_flags (Arena *arena, RDI_LinkFlags flags);
internal void rdi_print_data_sections (Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi);
internal void rdi_print_top_level_info (Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_TopLevelInfo *tli);
internal void rdi_print_binary_section (Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_BinarySection *bin_section);
internal void rdi_print_file_path (Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_FilePathNode *file_path);
internal void rdi_print_source_file (Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_SourceFile *source_file);
internal void rdi_print_line_table (Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_LineTable *line_table);
internal void rdi_print_source_line_map(Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_SourceLineMap *map);
internal void rdi_print_unit (Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_Unit *unit);
internal void rdi_print_type_node (Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_TypeNode *type);
internal void rdi_print_udt (Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_UDT *udt);
internal void rdi_print_global_variable(Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_GlobalVariable *gvar);
internal void rdi_print_thread_variable(Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_ThreadVariable *tvar);
internal void rdi_print_procedure (Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_Procedure *proc);
internal void rdi_print_scope (Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_Scope *scope, RDI_Arch arch);
internal void rdi_print_inline_site (Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_InlineSite *inline_site);
internal void rdi_print_vmap_entry (Arena *arena, String8List *out, String8 indent, RDI_VMapEntry *v);
// DWARF
internal String8List dw_string_list_from_expression (Arena *arena, String8 raw_data, U64 address_size, Arch arch, DW_Version ver, DW_Ext ext, B32 is_dwarf64);
internal String8 dw_format_expression_single_line(Arena *arena, String8 raw_data, U64 address_size, Arch arch, DW_Version ver, DW_Ext ext, B32 is_dwarf64);
internal String8 dw_format_eh_ptr_enc (Arena *arena, DW_EhPtrEnc enc);
internal void dw_print_cfi_program (Arena *arena, String8List *out, String8 indent, String8 raw_data, DW_CIEUnpacked *cie, DW_EhPtrCtx *ptr_ctx, Arch arch, DW_Version ver, DW_Ext ext, B32 is_dwarf64);
internal void dw_print_eh_frame (Arena *arena, String8List *out, String8 indent, String8 raw_eh_frame, Arch arch, DW_Version ver, DW_Ext ext, DW_EhPtrCtx *ptr_ctx);
internal void dw_print_debug_info (Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections, Arch arch, ImageType image_type, B32 relaxed);
internal void dw_print_debug_abbrev (Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections);
internal void dw_print_debug_line (Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections, B32 relaxed);
internal void dw_print_debug_str (Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections);
internal void dw_print_debug_loc (Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections, Arch arch, ImageType image_type, B32 relaxed);
internal void dw_print_debug_ranges (Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections, Arch arch, ImageType image_type, B32 relaxed);
internal void dw_print_debug_aranges (Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections);
internal void dw_print_debug_addr (Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections);
internal void dw_print_debug_loclists (Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections, Rng1U64Array segment_vranges, Arch arch);
internal void dw_print_debug_rnglists (Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections, Rng1U64Array segment_vranges);
internal void dw_print_debug_pubnames (Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections);
internal void dw_print_debug_pubtypes (Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections);
internal void dw_print_debug_line_str (Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections);
internal void dw_print_debug_str_offsets(Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections);
// CodeView
internal void cv_print_binary_annots (Arena *arena, String8List *out, String8 indent, CV_Arch arch, String8 raw_data);
internal void cv_print_lvar_addr_range(Arena *arena, String8List *out, String8 indent, CV_LvarAddrRange range);
internal void cv_print_lvar_addr_gap (Arena *arena, String8List *out, String8 indent, String8 raw_data);
internal void cv_print_lvar_attr (Arena *arena, String8List *out, String8 indent, CV_LocalVarAttr attr);
internal void cv_print_symbol (Arena *arena, String8List *out, String8 indent, CV_Arch arch, CV_TypeIndex min_itype, CV_SymKind type, String8 raw_symbol);
internal U64 cv_print_leaf (Arena *arena, String8List *out, String8 indent, CV_TypeIndex min_itype, CV_LeafKind kind, String8 raw_leaf);
internal void cv_print_debug_t (Arena *arena, String8List *out, String8 indent, CV_DebugT debug_t);
internal void cv_print_symbols_c13 (Arena *arena, String8List *out, String8 indent, CV_Arch arch, String8 raw_data);
internal void cv_print_lines_c13 (Arena *arena, String8List *out, String8 indent, String8 raw_lines);
internal void cv_print_file_checksums (Arena *arena, String8List *out, String8 indent, String8 raw_chksums);
internal void cv_print_string_table (Arena *arena, String8List *out, String8 indent, String8 raw_strtab);
internal void cv_print_inlinee_lines (Arena *arena, String8List *out, String8 indent, String8 raw_data);
internal void cv_print_symbols_section(Arena *arena, String8List *out, String8 indent, CV_Arch arch, String8 raw_ss);
// COFF
internal void coff_print_archive_member_header(Arena *arena, String8List *out, String8 indent, COFF_ParsedArchiveMemberHeader header, String8 long_names);
internal void coff_print_seciton_table (Arena *arena, String8List *out, String8 indent, String8 raw_data, U64 string_table_off, COFF_Symbol32Array symbols, U64 sect_count, COFF_SectionHeader *sect_headers);
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);
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 *sections);
internal void coff_print_relocs (Arena *arena, String8List *out, String8 indent, String8 raw_data, U64 string_table_off, COFF_MachineType machine, U64 sect_count, COFF_SectionHeader *sect_headers, COFF_Symbol32Array symbols);
internal void coff_print_symbol_table (Arena *arena, String8List *out, String8 indent, String8 raw_data, B32 is_big_obj, U64 string_table_off, COFF_Symbol32Array symbols);
internal void coff_print_big_obj_header (Arena *arena, String8List *out, String8 indent, COFF_BigObjHeader *header);
internal void coff_print_file_header (Arena *arena, String8List *out, String8 indent, COFF_FileHeader *header);
internal void coff_print_import (Arena *arena, String8List *out, String8 indent, COFF_ParsedArchiveImportHeader *header);
internal void coff_print_big_obj (Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Option opts);
internal void coff_print_obj (Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Option opts);
internal void coff_print_archive (Arena *arena, String8List *out, String8 indent, String8 raw_archive, RD_Option opts);
// MSVC CRT
internal void mscrt_print_eh_handler_type32(Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, MSCRT_EhHandlerType32 *handler);
// PE
internal void pe_print_data_directory_ranges(Arena *arena, String8List *out, String8 indent, U64 count, PE_DataDirectory *dirs);
internal void pe_print_optional_header32 (Arena *arena, String8List *out, String8 indent, PE_OptionalHeader32 *opt_header, PE_DataDirectory *dirs);
internal void pe_print_optional_header32plus(Arena *arena, String8List *out, String8 indent, PE_OptionalHeader32Plus *opt_header, PE_DataDirectory *dirs);
internal void pe_print_load_config32 (Arena *arena, String8List *out, String8 indent, PE_LoadConfig32 *lc);
internal void pe_print_load_config64 (Arena *arena, String8List *out, String8 indent, PE_LoadConfig64 *lc);
internal void pe_print_tls (Arena *arena, String8List *out, String8 indent, PE_ParsedTLS tls);
internal void pe_print_debug_diretory (Arena *arena, String8List *out, String8 indent, String8 raw_data, String8 raw_dir);
internal void pe_print_export_table (Arena *arena, String8List *out, String8 indent, PE_ParsedExportTable exptab);
internal void pe_print_static_import_table (Arena *arena, String8List *out, String8 indent, U64 image_base, PE_ParsedStaticImportTable imptab);
internal void pe_print_delay_import_table (Arena *arena, String8List *out, String8 indent, U64 image_base, PE_ParsedDelayImportTable imptab);
internal void pe_print_resources (Arena *arena, String8List *out, String8 indent, PE_ResourceDir *root);
internal void pe_print_exceptions_x8664 (Arena *arena, String8List *out, String8 indent, U64 section_count, COFF_SectionHeader *sections, String8 raw_data, Rng1U64 except_frange, RDI_Parsed *rdi);
internal void pe_print_exceptions (Arena *arena, String8List *out, String8 indent, COFF_MachineType machine, U64 section_count, COFF_SectionHeader *sections, String8 raw_data, Rng1U64 except_frange, RDI_Parsed *rdi);
internal void pe_print_base_relocs (Arena *arena, String8List *out, String8 indent, COFF_MachineType machine, U64 image_base, U64 section_count, COFF_SectionHeader *sections, String8 raw_data, Rng1U64 base_reloc_franges, RDI_Parsed *rdi);
internal void pe_print (Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Option opts, RDI_Parsed *rdi);
#endif // RADDUMP_H
+289
View File
@@ -0,0 +1,289 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#define BUILD_CONSOLE_INTERFACE 1
#define BUILD_TITLE "Epic Games Tools (R) RAD Dumper"
////////////////////////////////
#include "linker/base_ext/base_blake3.h"
#include "linker/base_ext/base_blake3.c"
#include "third_party/xxHash/xxhash.c"
#include "third_party/xxHash/xxhash.h"
#include "third_party/radsort/radsort.h"
#include "third_party/md5/md5.c"
#include "third_party/md5/md5.h"
#include "third_party/zydis/zydis.h"
#include "third_party/zydis/zydis.c"
#include "third_party/rad_lzb_simple/rad_lzb_simple.h"
#include "third_party/rad_lzb_simple/rad_lzb_simple.c"
////////////////////////////////
#include "base/base_inc.h"
#include "os/os_inc.h"
#include "async/async.h"
#include "rdi_format/rdi_format_local.h"
#include "rdi_make/rdi_make_local.h"
#include "path/path.h"
#include "coff/coff.h"
#include "coff/coff_enum.h"
#include "coff/coff_parse.h"
#include "pe/pe.h"
#include "msvc_crt/msvc_crt.h"
#include "msvc_crt/msvc_crt_enum.h"
#include "codeview/codeview.h"
#include "codeview/codeview_parse.h"
#include "codeview/codeview_enum.h"
#include "msf/msf.h"
#include "msf/msf_parse.h"
#include "pdb/pdb.h"
#include "pdb/pdb_parse.h"
#include "rdi_from_pdb/rdi_from_pdb.h"
#include "dwarf/dwarf.h"
#include "dwarf/dwarf_parse.h"
#include "dwarf/dwarf_expr.h"
#include "dwarf/dwarf_unwind.h"
#include "dwarf/dwarf_enum.h"
#include "base/base_inc.c"
#include "os/os_inc.c"
#include "async/async.c"
#include "rdi_format/rdi_format_local.c"
#include "rdi_make/rdi_make_local.c"
#include "path/path.c"
#include "coff/coff.c"
#include "coff/coff_enum.c"
#include "coff/coff_parse.c"
#include "pe/pe.c"
#include "msvc_crt/msvc_crt.c"
#include "msvc_crt/msvc_crt_enum.c"
#include "codeview/codeview.c"
#include "codeview/codeview_parse.c"
#include "codeview/codeview_enum.c"
#include "msf/msf.c"
#include "msf/msf_parse.c"
#include "pdb/pdb.c"
#include "pdb/pdb_parse.c"
#include "rdi_from_pdb/rdi_from_pdb.c"
#include "dwarf/dwarf.c"
#include "dwarf/dwarf_parse.c"
#include "dwarf/dwarf_expr.c"
#include "dwarf/dwarf_unwind.c"
#include "dwarf/dwarf_enum.c"
#include "linker/base_ext/base_inc.h"
#include "linker/base_ext/base_inc.c"
#include "linker/path_ext/path.h"
#include "linker/path_ext/path.c"
#include "linker/thread_pool/thread_pool.h"
#include "linker/thread_pool/thread_pool.c"
#include "linker/codeview_ext/codeview.h"
#include "linker/codeview_ext/codeview.c"
#include "linker/hash_table.h"
#include "linker/hash_table.c"
#include "linker/rdi/rdi.h"
#include "linker/rdi/rdi.c"
#include "raddump/raddump.h"
#include "raddump/raddump.c"
////////////////////////////////
global read_only struct
{
RD_Option opt;
char *name;
char *help;
} g_rd_dump_option_map[] = {
{ RD_Option_Help, "help", "Print help and exit" },
{ RD_Option_Version, "version", "Print version and exit" },
{ RD_Option_NoRdi, "nordi", "Don't load RAD Debug Info" },
{ RD_Option_Headers, "headers", "Dump DOS header, file header, optional header, and/or archive header" },
{ RD_Option_Sections, "sections", "Dump section headers as table" },
{ RD_Option_Rawdata, "rawdata", "Dump raw section data" },
{ RD_Option_Codeview, "cv", "Dump CodeView" },
{ RD_Option_Disasm, "disasm", "Disassemble code sections" },
{ RD_Option_Symbols, "symtab", "Dump COFF symbol table" },
{ RD_Option_Relocs, "relocs", "Dump relocations" },
{ RD_Option_Exceptions, "exceptions", "Dump exceptions" },
{ RD_Option_Tls, "tls", "Dump Thread Local Storage directory" },
{ RD_Option_Debug, "debug", "Dump debug directory" },
{ RD_Option_Imports, "imports", "Dump import table" },
{ RD_Option_Exports, "exports", "Dump export table" },
{ RD_Option_LoadConfig, "loadconfig", "Dump load config" },
{ RD_Option_Resources, "resources", "Dump resource directory" },
{ RD_Option_LongNames, "longnames", "Dump archive long names" },
{ RD_Option_DebugInfo, "debug_info", "Dump .debug_info" },
{ RD_Option_DebugAbbrev, "debug_abbrev", "Dump .debug_abbrev" },
{ RD_Option_DebugLine, "debug_line", "Dump .debug_line" },
{ RD_Option_DebugStr, "debug_str", "Dump .debug_str" },
{ RD_Option_DebugLoc, "debug_loc", "Dump .debug_loc" },
{ RD_Option_DebugRanges, "debug_ranges", "Dump .debug_ranges" },
{ RD_Option_DebugARanges, "debug_aranges", "Dump .debug_aranges" },
{ RD_Option_DebugAddr, "debug_addr", "Dump .debug_addr" },
{ RD_Option_DebugLocLists, "debug_loclists", "Dump .debug_loclists" },
{ RD_Option_DebugRngLists, "debug_rnglists", "Dump .debug_rnglists" },
{ RD_Option_DebugPubNames, "debug_pubnames", "Dump .debug_pubnames" },
{ RD_Option_DebugPubTypes, "debug_pubtypes", "Dump .debug_putypes" },
{ RD_Option_DebugLineStr, "debug_linestr", "Dump .debug_linestr" },
{ RD_Option_DebugStrOffsets, "debug_stroffsets", "Dump .debug_stroffsets" },
{ RD_Option_Dwarf, "dwarf", "Dump all DWARF sections" },
{ RD_Option_RelaxDwarfParser, "relax_dwarf_parser", "Relaxes version requirement on attribute and form encodings" },
{ RD_Option_RdiDataSections, "rdi_data_sections", "Dump data sections" },
{ RD_Option_RdiTopLevelInfo, "rdi_top_level_info", "Dump top level info" },
{ RD_Option_RdiBinarySections, "rdi_binary_sections", "Dump binary sections" },
{ RD_Option_RdiFilePaths, "rdi_file_paths", "Dump file paths" },
{ RD_Option_RdiSourceFiles, "rdi_source_files", "Dump source files" },
{ RD_Option_RdiLineTables, "rdi_line_tables", "Dump line tables" },
{ RD_Option_RdiSourceLineMaps, "rdi_source_line_maps", "Dump source line maps" },
{ RD_Option_RdiUnits, "rdi_units", "Dump units" },
{ RD_Option_RdiUnitVMap, "rdi_units_virtual_map", "Dump units virtual map" },
{ RD_Option_RdiTypeNodes, "rdi_type_nodes", "Dump type nodes" },
{ RD_Option_RdiUserDefinedTypes, "rdi_udt", "Dump user defined types" },
{ RD_Option_RdiGlobalVars, "rdi_global_vars", "Dump global variables" },
{ RD_Option_RdiThreadVars, "rdi_thread_vars", "Dump thread variables" },
{ RD_Option_RdiScopes, "rdi_scopes", "Dump scopes" },
{ RD_Option_RdiScopeVMap, "rdi_scope_virtual_map", "Dump scope virtual map" },
{ RD_Option_RdiInlineSites, "rdi_inline_sites", "Dump inline sites" },
{ RD_Option_RdiNameMaps, "rdi_name_maps", "Dump name maps" },
{ RD_Option_RdiStrings, "rdi_strings", "Dump strings" },
{ RD_Option_Help, "h", "Alias for -help" },
{ RD_Option_Version, "v", "Alias for -version" },
{ RD_Option_Sections, "s", "Alias for -sections" },
{ RD_Option_Exceptions, "e", "Alias for -exceptions" },
{ RD_Option_Imports, "i", "Alias for -imports" },
{ RD_Option_Exports, "x", "Alias for -exports" },
{ RD_Option_LoadConfig, "l", "Alias for -loadconifg" },
{ RD_Option_Resources, "c", "Alias for -resources" },
{ RD_Option_Relocs, "r", "Alias for -relocs" },
};
internal void
entry_point(CmdLine *cmdline)
{
Arena *arena = arena_alloc();
// make indent
String8List *out = push_array(arena, String8List, 1);
String8 indent;
{
U64 indent_buffer_size = RD_INDENT_WIDTH * RD_INDENT_MAX;
U8 *indent_buffer = push_array(arena, U8, indent_buffer_size);
MemorySet(indent_buffer, ' ', indent_buffer_size);
indent = str8(indent_buffer, 0);
}
// parse options
RD_Option opts = 0;
{
for (CmdLineOpt *cmd = cmdline->options.first; cmd != 0; cmd = cmd->next) {
RD_Option opt = 0;
for (U64 opt_idx = 0; opt_idx < ArrayCount(g_rd_dump_option_map); ++opt_idx) {
String8 opt_name = str8_cstring(g_rd_dump_option_map[opt_idx].name);
if (str8_match(cmd->string, opt_name, StringMatchFlag_CaseInsensitive)) {
opt = g_rd_dump_option_map[opt_idx].opt;
break;
} else if (str8_match_lit("all", cmd->string, StringMatchFlag_CaseInsensitive)) {
opt = ~0ull & ~(RD_Option_Help|RD_Option_Version);
break;
}
}
if (opt == 0) {
rd_errorf("Unknown argument: \"%S\"", cmd->string);
goto exit;
}
opts |= opt;
}
}
// print help
if (opts & RD_Option_Help) {
int longest_cmd_switch = 0;
for (U64 opt_idx = 0; opt_idx < ArrayCount(g_rd_dump_option_map); ++opt_idx) {
longest_cmd_switch = Max(longest_cmd_switch, strlen(g_rd_dump_option_map[opt_idx].name));
}
rd_printf(BUILD_TITLE_STRING_LITERAL);
rd_newline();
rd_printf("# Help");
rd_indent();
for (U64 opt_idx = 0; opt_idx < ArrayCount(g_rd_dump_option_map); ++opt_idx) {
char *name = g_rd_dump_option_map[opt_idx].name;
char *help = g_rd_dump_option_map[opt_idx].help;
int indent_size = longest_cmd_switch - strlen(name) + 1;
rd_printf("-%s%.*s%s", g_rd_dump_option_map[opt_idx].name, indent_size, indent.str, g_rd_dump_option_map[opt_idx].help);
}
rd_unindent();
goto exit;
}
// print version
if (opts & RD_Option_Version) {
rd_printf(BUILD_TITLE_STRING_LITERAL);
rd_printf("\traddump <options> <inputs>");
goto exit;
}
// input check
if (cmdline->inputs.node_count == 0) {
rd_errorf("No input file specified");
goto exit;
} else if (cmdline->inputs.node_count > 1) {
rd_errorf("Too many inputs specified, expected one");
goto exit;
}
// read input
String8 file_path = str8_list_first(&cmdline->inputs);
String8 raw_data = os_data_from_file_path(arena, file_path);
// is read ok?
if (raw_data.size == 0) {
rd_errorf("Unable to read input file \"%S\"", file_path);
goto exit;
}
// format input
rd_format_preamble(arena, out, indent, file_path, raw_data);
if (rd_is_rdi(raw_data)) {
RDI_Parsed rdi = {0};
RDI_ParseStatus parse_status = rdi_parse(raw_data.str, raw_data.size, &rdi);
switch (parse_status) {
case RDI_ParseStatus_Good: rdi_print(arena, out, indent, &rdi, opts); break;
case RDI_ParseStatus_HeaderDoesNotMatch: rd_errorf("RDI Parse: header does not match"); break;
case RDI_ParseStatus_UnsupportedVersionNumber: rd_errorf("RDI Parse: unsupported version"); break;
case RDI_ParseStatus_InvalidDataSecionLayout: rd_errorf("RDI Parse: invalid data section layout"); break;
case RDI_ParseStatus_MissingRequiredSection: rd_errorf("RDI Parse: missing required section"); break;
default: rd_errorf("RDI Parse: unknown parse status %u", parse_status); break;
}
} else if (coff_is_regular_archive(raw_data) || coff_is_thin_archive(raw_data)) {
coff_print_archive(arena, out, indent, raw_data, opts);
} else if (coff_is_big_obj(raw_data)) {
coff_print_big_obj(arena, out, indent, raw_data, opts);
} else if (coff_is_obj(raw_data)) {
coff_print_obj(arena, out, indent, raw_data, opts);
} else if (rd_is_pe(raw_data)) {
RDI_Parsed *rdi = 0;
if (!(opts & RD_Option_NoRdi)) {
rdi = rd_rdi_from_pe(arena, file_path, raw_data);
}
pe_print(arena, out, indent, raw_data, opts, rdi);
} else if (pe_is_res(raw_data)) {
//tool_out_coff_res(stdout, file_data);
}
exit:;
// print formatted string
String8 out_string = str8_list_join(arena, out, &(StringJoin){ .sep = str8_lit("\n"),});
fprintf(stdout, "%.*s", str8_varg(out_string));
arena_release(arena);
}
+142 -273
View File
@@ -161,15 +161,15 @@ internal RDI_BinarySectionFlags
p2r_rdi_binary_section_flags_from_coff_section_flags(COFF_SectionFlags flags)
{
RDI_BinarySectionFlags result = 0;
if(flags & COFF_SectionFlag_MEM_READ)
if(flags & COFF_SectionFlag_MemRead)
{
result |= RDI_BinarySectionFlag_Read;
}
if(flags & COFF_SectionFlag_MEM_WRITE)
if(flags & COFF_SectionFlag_MemWrite)
{
result |= RDI_BinarySectionFlag_Write;
}
if(flags & COFF_SectionFlag_MEM_EXECUTE)
if(flags & COFF_SectionFlag_MemExecute)
{
result |= RDI_BinarySectionFlag_Execute;
}
@@ -787,185 +787,58 @@ ASYNC_WORK_DEF(p2r_units_convert_work)
}
// rjf: build line table, fill with parsed binary annotations
RDIM_LineTable *line_table = 0;
if(inlinee_lines_parsed != 0)
{
// rjf: state machine registers
CV_InlineRangeKind range_kind = 0;
U32 code_length = 0;
U32 code_offset = 0;
U32 last_code_offset = code_offset;
String8 file_name = inlinee_lines_parsed->file_name;
String8 last_file_name = file_name;
S32 line = (S32)inlinee_lines_parsed->first_source_ln;
S32 last_line = line;
S32 column = 1;
S32 last_column = column;
// rjf: grab checksums sub-section
CV_C13SubSectionNode *file_chksms = unit_c13->file_chksms_sub_section;
// rjf: gathered lines
typedef struct LineChunk LineChunk;
struct LineChunk
{
LineChunk *next;
U64 cap;
U64 count;
U64 *voffs; // [line_count + 1] (sorted)
U32 *line_nums; // [line_count]
U16 *col_nums; // [2*line_count]
U64 cap;
U64 count;
U64 *voffs; // [line_count + 1] (sorted)
U32 *line_nums; // [line_count]
U16 *col_nums; // [2*line_count]
};
LineChunk *first_line_chunk = 0;
LineChunk *last_line_chunk = 0;
U64 total_line_chunk_line_count = 0;
// rjf: grab checksums sub-section
CV_C13SubSectionNode *file_chksms = unit_c13->file_chksms_sub_section;
// rjf: decode loop
U64 read_off = 0;
U64 read_off_opl = binary_annots.size;
for(B32 good = 1; read_off < read_off_opl && good;)
LineChunk *first_line_chunk = 0;
LineChunk *last_line_chunk = 0;
U64 total_line_chunk_line_count = 0;
U32 last_file_off = max_U32;
U32 curr_file_off = max_U32;
RDIM_LineTable* line_table = 0;
CV_C13InlineSiteDecoder decoder = cv_c13_inline_site_decoder_init(inlinee_lines_parsed->file_off, inlinee_lines_parsed->first_source_ln, base_voff);
for(;;)
{
// rjf: decode next annotation op
U32 op = CV_InlineBinaryAnnotation_Null;
read_off += cv_decode_inline_annot_u32(binary_annots, read_off, &op);
// rjf: apply op
switch(op)
CV_C13InlineSiteDecoderStep step = cv_c13_inline_site_decoder_step(&decoder, binary_annots);
if(step.flags & CV_C13InlineSiteDecoderStepFlag_EmitFile)
{
default:{good = 0;}break;
case CV_InlineBinaryAnnotation_Null:
{
good = 0;
}break;
case CV_InlineBinaryAnnotation_CodeOffset:
{
read_off += cv_decode_inline_annot_u32(binary_annots, read_off, &code_offset);
}break;
case CV_InlineBinaryAnnotation_ChangeCodeOffsetBase:
{
good = 0;
// TODO(rjf): currently untested/unknown - first guess below:
//
// U32 delta = 0;
// read_off += cv_decode_inline_annot_u32(binary_annots, read_off, &delta);
// code_offset_base = code_offset;
// code_offset_end = code_offset + delta;
// code_offset += delta;
}break;
case CV_InlineBinaryAnnotation_ChangeCodeOffset:
{
U32 delta = 0;
read_off += cv_decode_inline_annot_u32(binary_annots, read_off, &delta);
code_offset += delta;
}break;
case CV_InlineBinaryAnnotation_ChangeCodeLength:
{
code_length = 0;
read_off += cv_decode_inline_annot_u32(binary_annots, read_off, &code_length);
}break;
case CV_InlineBinaryAnnotation_ChangeFile:
{
U32 new_file_off = 0;
read_off += cv_decode_inline_annot_u32(binary_annots, read_off, &new_file_off);
String8 new_file_name = {0};
if(new_file_off + sizeof(CV_C13Checksum) <= file_chksms->size)
{
CV_C13Checksum *checksum = (CV_C13Checksum*)(unit_c13->data.str + file_chksms->off + new_file_off);
U32 name_off = checksum->name_off;
new_file_name = pdb_strtbl_string_from_off(in->pdb_strtbl, name_off);
}
file_name = new_file_name;
}break;
case CV_InlineBinaryAnnotation_ChangeLineOffset:
{
S32 delta = 0;
read_off += cv_decode_inline_annot_s32(binary_annots, read_off, &delta);
line += delta;
}break;
case CV_InlineBinaryAnnotation_ChangeLineEndDelta:
{
good = 0;
// TODO(rjf): currently untested/unknown - first guess below:
//
// S32 end_delta = 1;
// read_off += cv_decode_inline_annot_s32(binary_annots, read_off, &end_delta);
// line += end_delta;
}break;
case CV_InlineBinaryAnnotation_ChangeRangeKind:
{
good = 0;
// TODO(rjf): currently untested/unknown - first guess below:
//
// read_off += cv_decode_inline_annot_u32(binary_annots, read_off, &range_kind);
}break;
case CV_InlineBinaryAnnotation_ChangeColumnStart:
{
good = 0;
// TODO(rjf): currently untested/unknown - first guess below:
//
// S32 delta = 0;
// read_off += cv_decode_inline_annot_s32(binary_annots, read_off, &delta);
// column += delta;
}break;
case CV_InlineBinaryAnnotation_ChangeColumnEndDelta:
{
// TODO(rjf): currently untested/unknown - first guess below:
//
// S32 end_delta = 0;
// read_off += cv_decode_inline_annot_s32(binary_annots, read_off, &end_delta);
// column += end_delta;
}break;
case CV_InlineBinaryAnnotation_ChangeCodeOffsetAndLineOffset:
{
U32 code_offset_and_line_offset = 0;
read_off += cv_decode_inline_annot_u32(binary_annots, read_off, &code_offset_and_line_offset);
U32 code_delta = (code_offset_and_line_offset & 0xf);
S32 line_delta = cv_inline_annot_signed_from_unsigned_operand(code_offset_and_line_offset >> 4);
code_offset += code_delta;
line += line_delta;
}break;
case CV_InlineBinaryAnnotation_ChangeCodeLengthAndCodeOffset:
{
U32 offset_delta = 0;
read_off += cv_decode_inline_annot_u32(binary_annots, read_off, &code_length);
read_off += cv_decode_inline_annot_u32(binary_annots, read_off, &offset_delta);
code_offset += offset_delta;
}break;
case CV_InlineBinaryAnnotation_ChangeColumnEnd:
{
// TODO(rjf): currently untested/unknown - first guess below:
//
// U32 column_end = 0;
// read_off += cv_decode_inline_annot_u32(binary_annots, read_off, &column_end);
}break;
last_file_off = curr_file_off;
curr_file_off = step.file_off;
}
// rjf: gather new lines
if(!good || line != last_line || code_offset != last_code_offset)
if(step.flags == 0 && total_line_chunk_line_count > 0)
{
LineChunk *chunk = last_line_chunk;
if(chunk == 0 || chunk->count+1 >= chunk->cap)
last_file_off = curr_file_off;
curr_file_off = max_U32;
}
if((last_file_off != max_U32 && last_file_off != curr_file_off))
{
String8 seq_file_name = {0};
if(last_file_off + sizeof(CV_C13Checksum) <= file_chksms->size)
{
chunk = push_array(scratch.arena, LineChunk, 1);
SLLQueuePush(first_line_chunk, last_line_chunk, chunk);
chunk->cap = 256;
chunk->voffs = push_array_no_zero(scratch.arena, U64, chunk->cap);
chunk->line_nums = push_array_no_zero(scratch.arena, U32, chunk->cap);
CV_C13Checksum *checksum = (CV_C13Checksum*)(unit_c13->data.str + file_chksms->off + last_file_off);
U32 name_off = checksum->name_off;
seq_file_name = pdb_strtbl_string_from_off(in->pdb_strtbl, name_off);
}
chunk->voffs[chunk->count] = base_voff + code_offset;
chunk->voffs[chunk->count+1] = base_voff + code_offset + code_length;
chunk->line_nums[chunk->count] = (U32)line;
chunk->count += 1;
total_line_chunk_line_count += 1;
}
// rjf: push line sequence to line table & source file
if(!good || (op == CV_InlineBinaryAnnotation_ChangeFile && !str8_match(last_file_name, file_name, 0)))
{
String8 seq_file_name = last_file_name; // NOTE(rjf): `file_name` is possibly changed to the next sequence, so use previous
// rjf: file name -> normalized file path
String8 file_path = seq_file_name;
String8 file_path = seq_file_name;
String8 file_path_normalized = lower_from_str8(scratch.arena, str8_skip_chop_whitespace(file_path));
for(U64 idx = 0; idx < file_path_normalized.size; idx += 1)
{
@@ -976,9 +849,9 @@ ASYNC_WORK_DEF(p2r_units_convert_work)
}
// rjf: normalized file path -> source file node
U64 file_path_normalized_hash = rdi_hash(file_path_normalized.str, file_path_normalized.size);
U64 src_file_slot = file_path_normalized_hash%src_file_map.slots_count;
P2R_SrcFileNode *src_file_node = 0;
U64 file_path_normalized_hash = rdi_hash(file_path_normalized.str, file_path_normalized.size);
U64 src_file_slot = file_path_normalized_hash%src_file_map.slots_count;
P2R_SrcFileNode *src_file_node = 0;
for(P2R_SrcFileNode *n = src_file_map.slots[src_file_slot]; n != 0; n = n->next)
{
if(str8_match(n->src_file->normal_full_path, file_path_normalized, 0))
@@ -991,23 +864,22 @@ ASYNC_WORK_DEF(p2r_units_convert_work)
{
src_file_node = push_array(scratch.arena, P2R_SrcFileNode, 1);
SLLStackPush(src_file_map.slots[src_file_slot], src_file_node);
src_file_node->src_file = rdim_src_file_chunk_list_push(arena, &out->src_files, 4096);
src_file_node->src_file = rdim_src_file_chunk_list_push(arena, &out->src_files, 4096);
src_file_node->src_file->normal_full_path = push_str8_copy(arena, file_path_normalized);
}
// rjf: gather all lines
RDI_U64 *voffs = push_array_no_zero(arena, RDI_U64, total_line_chunk_line_count+1);
RDI_U32 *line_nums = push_array_no_zero(arena, RDI_U32, total_line_chunk_line_count);
RDI_U64 line_count = total_line_chunk_line_count;
RDI_U64 *voffs = push_array_no_zero(arena, RDI_U64, total_line_chunk_line_count+1);
RDI_U32 *line_nums = push_array_no_zero(arena, RDI_U32, total_line_chunk_line_count);
RDI_U64 line_count = total_line_chunk_line_count;
{
U64 dst_idx = 0;
for(LineChunk *chunk = first_line_chunk; chunk != 0; chunk = chunk->next)
{
MemoryCopy(voffs+dst_idx, chunk->voffs, sizeof(U64)*chunk->count);
MemoryCopy(voffs+dst_idx, chunk->voffs, sizeof(U64)*(chunk->count+1));
MemoryCopy(line_nums+dst_idx, chunk->line_nums, sizeof(U32)*chunk->count);
dst_idx += chunk->count;
}
voffs[dst_idx] = 0xffffffffffffffffull;
}
// rjf: push
@@ -1026,15 +898,32 @@ ASYNC_WORK_DEF(p2r_units_convert_work)
}
// rjf: clear line chunks for subsequent sequences
first_line_chunk = last_line_chunk = 0;
first_line_chunk = last_line_chunk = 0;
total_line_chunk_line_count = 0;
}
// rjf: update prev/current states
last_file_name = file_name;
last_line = line;
last_column = column;
last_code_offset = code_offset;
if(step.flags & CV_C13InlineSiteDecoderStepFlag_EmitLine)
{
LineChunk *chunk = last_line_chunk;
if(chunk == 0 || chunk->count+1 >= chunk->cap)
{
chunk = push_array(scratch.arena, LineChunk, 1);
SLLQueuePush(first_line_chunk, last_line_chunk, chunk);
chunk->cap = 256;
chunk->voffs = push_array_no_zero(scratch.arena, U64, chunk->cap);
chunk->line_nums = push_array_no_zero(scratch.arena, U32, chunk->cap);
}
chunk->voffs[chunk->count] = step.line_voff;
chunk->voffs[chunk->count+1] = step.line_voff_end;
chunk->line_nums[chunk->count] = step.ln;
chunk->count += 1;
total_line_chunk_line_count += 1;
}
if(step.flags == 0)
{
break;
}
}
}
}break;
@@ -1792,7 +1681,7 @@ ASYNC_WORK_DEF(p2r_udt_convert_work)
method_read_ptr = next_method_read_ptr)
{
CV_LeafMethodListMember *method = (CV_LeafMethodListMember*)method_read_ptr;
CV_MethodProp prop = CV_FieldAttribs_ExtractMethodProp(method->attribs);
CV_MethodProp prop = CV_FieldAttribs_Extract_MethodProp(method->attribs);
RDIM_Type *method_type = p2r_type_ptr_from_itype(method->itype);
next_method_read_ptr = (U8 *)(method+1);
@@ -1867,7 +1756,7 @@ ASYNC_WORK_DEF(p2r_udt_convert_work)
// rjf: unpack leaf
CV_LeafOneMethod *lf = (CV_LeafOneMethod *)field_leaf_first;
CV_MethodProp prop = CV_FieldAttribs_ExtractMethodProp(lf->attribs);
CV_MethodProp prop = CV_FieldAttribs_Extract_MethodProp(lf->attribs);
U8 *vbaseoff_ptr = (U8 *)(lf+1);
U8 *vbaseoff_opl_ptr = vbaseoff_ptr;
U32 vbaseoff = 0;
@@ -2976,98 +2865,30 @@ ASYNC_WORK_DEF(p2r_symbol_stream_convert_work)
// rjf: parse offset ranges of this inline site - attach to scope
{
U32 code_length = 0;
U32 code_offset = 0;
U32 last_code_offset = code_offset;
U32 last_code_length = code_length;
U64 read_off = 0;
U64 read_off_opl = binary_annots.size;
for(B32 good = 1; read_off < read_off_opl && good;)
CV_C13InlineSiteDecoder decoder = cv_c13_inline_site_decoder_init(0, 0, procedure_base_voff);
for(;;)
{
// rjf: decode next annotation op
U32 op = CV_InlineBinaryAnnotation_Null;
read_off += cv_decode_inline_annot_u32(binary_annots, read_off, &op);
// rjf: apply op
switch(op)
CV_C13InlineSiteDecoderStep step = cv_c13_inline_site_decoder_step(&decoder, binary_annots);
if(step.flags & CV_C13InlineSiteDecoderStepFlag_EmitRange)
{
default:{good = 1;}break;
case CV_InlineBinaryAnnotation_Null:
{
good = 0;
}break;
case CV_InlineBinaryAnnotation_CodeOffset:
{
read_off += cv_decode_inline_annot_u32(binary_annots, read_off, &code_offset);
}break;
case CV_InlineBinaryAnnotation_ChangeCodeOffsetBase:
{
good = 0;
// TODO(rjf): currently untested/unknown - first guess below:
//
// U32 delta = 0;
// read_off += cv_decode_inline_annot_u32(binary_annots, read_off, &delta);
// code_offset_base = code_offset;
// code_offset_end = code_offset + delta;
// code_offset += delta;
}break;
case CV_InlineBinaryAnnotation_ChangeCodeOffset:
{
U32 delta = 0;
read_off += cv_decode_inline_annot_u32(binary_annots, read_off, &delta);
code_offset += delta;
}break;
case CV_InlineBinaryAnnotation_ChangeCodeLength:
{
code_length = 0;
read_off += cv_decode_inline_annot_u32(binary_annots, read_off, &code_length);
}break;
case CV_InlineBinaryAnnotation_ChangeCodeOffsetAndLineOffset:
{
U32 code_offset_and_line_offset = 0;
read_off += cv_decode_inline_annot_u32(binary_annots, read_off, &code_offset_and_line_offset);
U32 code_delta = (code_offset_and_line_offset & 0xf);
code_offset += code_delta;
}break;
case CV_InlineBinaryAnnotation_ChangeCodeLengthAndCodeOffset:
{
U32 offset_delta = 0;
read_off += cv_decode_inline_annot_u32(binary_annots, read_off, &code_length);
read_off += cv_decode_inline_annot_u32(binary_annots, read_off, &offset_delta);
code_offset += offset_delta;
}break;
// rjf: build new range & add to scope
RDIM_Rng1U64 voff_range = { step.range.min, step.range.max };
rdim_scope_push_voff_range(arena, &sym_scopes, scope, voff_range);
}
// rjf: gather new ranges
if(last_code_length != code_length)
if(step.flags & CV_C13InlineSiteDecoderStepFlag_ExtendLastRange)
{
// rjf: convert current state machine state to [first_voff, opl_voff) range
RDIM_Rng1U64 voff_range =
if(scope->voff_ranges.last != 0)
{
procedure_base_voff + code_offset,
procedure_base_voff + code_offset + code_length,
};
// rjf: attempt to extend last-added range to cover this range, if possible
if(scope->voff_ranges.last != 0 && scope->voff_ranges.last->v.max == voff_range.min)
{
scope->voff_ranges.last->v.max = voff_range.max;
scope->voff_ranges.last->v.max = step.range.max;
}
// rjf: cannot add to previous range? -> build new range & add to scope
else
{
rdim_scope_push_voff_range(arena, &sym_scopes, scope, voff_range);
}
// rjf: advance
code_offset += code_length;
code_length = 0;
}
// rjf: update prev/current states
last_code_offset = code_offset;
last_code_length = code_length;
if(step.flags == 0)
{
break;
}
}
}
}break;
@@ -3127,7 +2948,7 @@ p2r_convert(Arena *arena, P2R_User2Convert *in)
//- rjf: parse PDB auth_guid & named streams table
//
PDB_NamedStreamTable *named_streams = 0;
COFF_Guid auth_guid = {0};
Guid auth_guid = {0};
if(msf != 0) ProfScope("parse PDB auth_guid & named streams table")
{
Temp scratch = scratch_begin(&arena, 1);
@@ -3694,9 +3515,9 @@ p2r_convert(Arena *arena, P2R_User2Convert *in)
// rjf: unpack leaf
CV_LeafPointer *lf = (CV_LeafPointer *)itype_leaf_first;
RDIM_Type *direct_type = p2r_type_ptr_from_itype(lf->itype);
CV_PointerKind ptr_kind = CV_PointerAttribs_ExtractKind(lf->attribs);
CV_PointerMode ptr_mode = CV_PointerAttribs_ExtractMode(lf->attribs);
U32 ptr_size = CV_PointerAttribs_ExtractSize(lf->attribs);
CV_PointerKind ptr_kind = CV_PointerAttribs_Extract_Kind(lf->attribs);
CV_PointerMode ptr_mode = CV_PointerAttribs_Extract_Mode(lf->attribs);
U32 ptr_size = CV_PointerAttribs_Extract_Size(lf->attribs);
// rjf: cv -> rdi modifier flags
RDI_TypeModifierFlags modifier_flags = 0;
@@ -4231,6 +4052,23 @@ ASYNC_WORK_DEF(p2r_bake_symbols_strings_work)
return 0;
}
ASYNC_WORK_DEF(p2r_bake_inline_site_strings_work)
{
ProfBeginFunction();
Arena *arena = p2r_state->work_thread_arenas[thread_idx];
P2R_BakeInlineSiteStringsIn *in = input;
p2r_make_string_map_if_needed();
ProfScope("bake inline site strings")
{
for(P2R_BakeInlineSiteStringsInNode *n = in->first; n != 0; n = n->next)
{
rdim_bake_string_map_loose_push_inline_site_slice(arena, in->top, in->maps[thread_idx], n->v, n->count);
}
}
ProfEnd();
return 0;
}
ASYNC_WORK_DEF(p2r_bake_scopes_strings_work)
{
ProfBeginFunction();
@@ -4697,6 +4535,37 @@ p2r_bake(Arena *arena, P2R_Convert2Bake *in)
}
}
}
ProfScope("kick off inline site string map build task")
{
U64 items_per_task = 4096;
U64 num_tasks = CeilIntegerDiv(in_params->inline_sites.total_count, items_per_task);
RDIM_InlineSiteChunkNode *chunk = in_params->inline_sites.first;
U64 chunk_off = 0;
for(U64 task_idx = 0; task_idx < num_tasks; task_idx += 1)
{
P2R_BakeInlineSiteStringsIn *in = push_array(scratch.arena, P2R_BakeInlineSiteStringsIn, 1);
in->top = &bake_string_map_topology;
in->maps = bake_string_maps__in_progress;
U64 items_left = items_per_task;
for(;chunk != 0 && items_left > 0;)
{
U64 items_in_this_chunk = Min(items_per_task, chunk->count-chunk_off);
P2R_BakeInlineSiteStringsInNode *n = push_array(scratch.arena, P2R_BakeInlineSiteStringsInNode, 1);
SLLQueuePush(in->first, in->last, n);
n->v = chunk->v + chunk_off;
n->count = items_in_this_chunk;
chunk_off += items_in_this_chunk;
items_left -= items_in_this_chunk;
if(chunk_off >= chunk->count)
{
chunk = chunk->next;
chunk_off = 0;
}
}
async_task_list_push(scratch.arena, &bake_string_map_build_tasks, async_task_launch(scratch.arena, p2r_bake_inline_site_strings_work, .input = in));
}
}
// rjf: scope chunks
ProfScope("kick off scope chunks string map build tasks")
+17
View File
@@ -353,6 +353,23 @@ struct P2R_BakeSymbolsStringsIn
P2R_BakeSymbolsStringsInNode *last;
};
typedef struct P2R_BakeInlineSiteStringsInNode P2R_BakeInlineSiteStringsInNode;
struct P2R_BakeInlineSiteStringsInNode
{
P2R_BakeInlineSiteStringsInNode *next;
RDIM_InlineSite *v;
RDI_U64 count;
};
typedef struct P2R_BakeInlineSiteStringsIn P2R_BakeInlineSiteStringsIn;
struct P2R_BakeInlineSiteStringsIn
{
RDIM_BakeStringMapTopology *top;
RDIM_BakeStringMapLoose **maps;
P2R_BakeInlineSiteStringsInNode *first;
P2R_BakeInlineSiteStringsInNode *last;
};
typedef struct P2R_BakeScopesStringsInNode P2R_BakeScopesStringsInNode;
struct P2R_BakeScopesStringsInNode
{
+4 -2
View File
@@ -22,8 +22,9 @@
#include "async/async.h"
#include "rdi_make/rdi_make_local.h"
#include "coff/coff.h"
#include "coff/coff_parse.h"
#include "codeview/codeview.h"
#include "codeview/codeview_stringize.h"
#include "codeview/codeview_parse.h"
#include "msf/msf.h"
#include "msf/msf_parse.h"
#include "pdb/pdb.h"
@@ -37,8 +38,9 @@
#include "async/async.c"
#include "rdi_make/rdi_make_local.c"
#include "coff/coff.c"
#include "coff/coff_parse.c"
#include "codeview/codeview.c"
#include "codeview/codeview_stringize.c"
#include "codeview/codeview_parse.c"
#include "msf/msf.c"
#include "msf/msf_parse.c"
#include "pdb/pdb.c"
+8 -9
View File
@@ -4,17 +4,18 @@
#include "os/os_inc.h"
#include "coff/coff.h"
#include "codeview/codeview.h"
#include "codeview/codeview_stringize.h"
#include "codeview/codeview_parse.h"
#include "msf/msf.h"
#include "msf/msf_parse.h"
#include "pdb/pdb.h"
#include "pdb/pdb_parse.h"
#include "pdb/pdb_stringize.h"
#include "base/base_inc.c"
#include "os/os_inc.c"
#include "coff/coff.c"
#include "codeview/codeview.c"
#include "codeview/codeview_stringize.c"
#include "codeview/codeview_parse.c"
#include "msf/msf.c"
#include "msf/msf_parse.c"
#include "pdb/pdb.c"
@@ -25,23 +26,21 @@
#include "linker/base_ext/base_blake3.h"
#include "linker/base_ext/base_blake3.c"
#include "linker/third_party_ext/md5/md5.c"
#include "linker/third_party_ext/md5/md5.h"
#include "linker/third_party_ext/xxHash/xxhash.c"
#include "linker/third_party_ext/xxHash/xxhash.h"
#include "third_party/md5/md5.c"
#include "third_party/md5/md5.h"
#include "third_party/xxHash/xxhash.c"
#include "third_party/xxHash/xxhash.h"
#include "linker/base_ext/base_inc.h"
#include "linker/path_ext/path.h"
#include "linker/hash_table.h"
#include "linker/thread_pool/thread_pool.h"
#include "linker/os_ext/os_inc.h"
#include "linker/codeview_ext/codeview.h"
#include "linker/base_ext/base_inc.c"
#include "linker/path_ext/path.c"
#include "linker/hash_table.c"
#include "linker/thread_pool/thread_pool.c"
#include "linker/os_ext/os_inc.c"
#include "linker/codeview_ext/codeview.c"
internal void
@@ -116,7 +115,7 @@ print_inline_binary_annotations(String8 binary_annots)
case CV_InlineBinaryAnnotation_ChangeCodeOffsetAndLineOffset: {
U32 code_offset_and_line_offset = 0;
cursor += cv_decode_inline_annot_u32(binary_annots, cursor, &code_offset_and_line_offset);
S32 line_delta = cv_inline_annot_convert_to_signed_operand(code_offset_and_line_offset >> 4);
S32 line_delta = cv_inline_annot_signed_from_unsigned_operand(code_offset_and_line_offset >> 4);
U32 code_delta = code_offset_and_line_offset & 0xF;
line_offset += line_delta;
code_offset += code_delta;