mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-06-17 01:22:24 -07:00
Merge remote-tracking branch 'EpicGamesExt/dev'
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
+1317
-1542
File diff suppressed because it is too large
Load Diff
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
+401
-727
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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 = §_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 = §_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
@@ -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
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
+86
-28
@@ -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
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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, ...)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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, §_name_arr[sect_idx], §_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
@@ -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
@@ -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;
|
||||
|
||||
@@ -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 = §_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 = §_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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 = §->data;
|
||||
if (coff_header->flags & COFF_SectionFlag_MEM_READ) {
|
||||
COFF_SectionHeader *section_header = §->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
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -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
@@ -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
@@ -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 = §ions[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
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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")
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user