mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-06-12 23:31:38 -07:00
Merge remote-tracking branch 'EpicGamesExt/master'
This commit is contained in:
@@ -31,4 +31,22 @@ jobs:
|
||||
shell: cmd
|
||||
run: |
|
||||
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64
|
||||
call build ${{ matrix.target }} ${{ matrix.compiler }} ${{ matrix.mode }} || exit /b 1
|
||||
call build %${{ matrix.target }}% %${{ matrix.compiler }}% %${{ matrix.mode }}% || exit /b 1
|
||||
|
||||
run-torture:
|
||||
runs-on: windows-2022
|
||||
steps:
|
||||
# - name: Install ASAN
|
||||
# shell: cmd
|
||||
# run: |
|
||||
# "C:\Program Files (x86)\Microsoft Visual Studio\Installer\vs_installer.exe" modify --installPath "C:\Program Files\Microsoft Visual Studio\2022\Enterprise" --quiet --force --norestart --add Microsoft.VisualStudio.Component.VC.ASAN
|
||||
- name: checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: run-torture
|
||||
shell: cmd
|
||||
run: |
|
||||
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64
|
||||
call build radlink asan debug no_meta || exit /b 1
|
||||
call build torture debug no_meta || exit /b 1
|
||||
cd build
|
||||
torture -l:radlink || exit /b 1
|
||||
|
||||
@@ -123,6 +123,7 @@ if "%strip_lib_debug%"=="1" set didbuild=1 && %compile% ..\src\strip_
|
||||
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
|
||||
if "%torture%"=="1" set didbuild=1 && %compile% ..\src\torture\torture.c %compile_link% %out%torture.exe || exit /b1
|
||||
if "%mule_peb_trample%"=="1" (
|
||||
set didbuild=1
|
||||
if exist mule_peb_trample.exe move mule_peb_trample.exe mule_peb_trample_old_%random%.exe
|
||||
|
||||
Binary file not shown.
Binary file not shown.
+10
-2
@@ -46,7 +46,14 @@ load_paths =
|
||||
commands =
|
||||
{
|
||||
//- rjf: [raddbg]
|
||||
// .f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
||||
.f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
||||
// .f1 = { .win = "raddbg_stable --ipc kill_all && build radbin", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
||||
|
||||
//- rjf: [raddbg wsl]
|
||||
// .f1 = { .win = "wsl ./build.sh raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
||||
|
||||
//- rjf: [scratch]
|
||||
.f2 = { .win = "build radbin", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
||||
|
||||
//- rjf: [textperf]
|
||||
// .f1 = { .win = "raddbg_stable --ipc kill_all && build no_meta telemetry textperf && raddbg_stable --ipc bring_to_front && raddbg_stable --ipc run", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
||||
@@ -55,10 +62,11 @@ commands =
|
||||
// .f1 = { .win = "raddbg_stable --ipc kill_all && build no_meta tester", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
||||
|
||||
//- rjf: [radbin]
|
||||
.f1 = { .win = "raddbg_stable --ipc kill_all && build radbin", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
||||
// .f1 = { .win = "raddbg_stable --ipc kill_all && build radbin", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
||||
|
||||
//- rjf: running target
|
||||
.f3 = { .win = "raddbg_stable --ipc run", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
||||
// .f3 = { .win = "wsl ./build/raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
||||
// .f3 = { .win = "pushd build && raddbg --user:dev.raddbg_user && popd", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
||||
// .f3 = { .win = "C:/devel/raddebugger/build/raddbg.exe --capture --user:C:/devel/raddebugger/build/local_dev.raddbg_user --project:C:/devel/raddebugger/build/local_dev.raddbg_project", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
||||
// .f3 = { .win = "wsl_launch /mnt/c/devel/raddebugger/build/raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
||||
|
||||
@@ -159,7 +159,7 @@
|
||||
#endif
|
||||
|
||||
#if !defined(BUILD_VERSION_PATCH)
|
||||
# define BUILD_VERSION_PATCH 20
|
||||
# define BUILD_VERSION_PATCH 21
|
||||
#endif
|
||||
|
||||
#define BUILD_VERSION_STRING_LITERAL Stringify(BUILD_VERSION_MAJOR) "." Stringify(BUILD_VERSION_MINOR) "." Stringify(BUILD_VERSION_PATCH)
|
||||
|
||||
@@ -636,3 +636,26 @@ u64_array_bsearch(U64 *arr, U64 count, U64 value)
|
||||
return max_U64;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal U64
|
||||
index_of_zero_u32(U32 *ptr, U64 count)
|
||||
{
|
||||
for (U64 i = 0; i < count; i += 1) {
|
||||
if (ptr[i] == 0) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return max_U64;
|
||||
}
|
||||
|
||||
internal U64
|
||||
index_of_zero_u64(U64 *ptr, U64 count)
|
||||
{
|
||||
for (U64 i = 0; i < count; i += 1) {
|
||||
if (ptr[i] == 0) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return max_U64;
|
||||
}
|
||||
|
||||
@@ -148,6 +148,7 @@
|
||||
#define MemoryCopyStruct(d,s) MemoryCopy((d),(s),sizeof(*(d)))
|
||||
#define MemoryCopyArray(d,s) MemoryCopy((d),(s),sizeof(d))
|
||||
#define MemoryCopyTyped(d,s,c) MemoryCopy((d),(s),sizeof(*(d))*(c))
|
||||
#define MemoryCopyStr8(dst, s) MemoryCopy(dst, (s).str, (s).size)
|
||||
|
||||
#define MemoryZero(s,z) memset((s),0,(z))
|
||||
#define MemoryZeroStruct(s) MemoryZero((s),sizeof(*(s)))
|
||||
@@ -314,7 +315,6 @@ CheckNil(nil,p) ? \
|
||||
#endif
|
||||
|
||||
#if ASAN_ENABLED
|
||||
#pragma comment(lib, "clang_rt.asan-x86_64.lib")
|
||||
C_LINKAGE void __asan_poison_memory_region(void const volatile *addr, size_t size);
|
||||
C_LINKAGE void __asan_unpoison_memory_region(void const volatile *addr, size_t size);
|
||||
# define AsanPoisonMemoryRegion(addr, size) __asan_poison_memory_region((addr), (size))
|
||||
@@ -348,7 +348,8 @@ C_LINKAGE void __asan_unpoison_memory_region(void const volatile *addr, size_t s
|
||||
#endif
|
||||
#define PtrFromInt(i) (void*)(i)
|
||||
|
||||
#define Compose64Bit(a,b) ((((U64)a) << 32) | ((U64)b));
|
||||
#define Compose64Bit(a,b) ((((U64)a) << 32) | ((U64)b))
|
||||
#define Compose32Bit(a,b) ((((U32)a) << 16) | ((U32)b))
|
||||
#define AlignPow2(x,b) (((x) + (b) - 1)&(~((b) - 1)))
|
||||
#define AlignDownPow2(x,b) ((x)&(~((b) - 1)))
|
||||
#define AlignPadPow2(x,b) ((0-(x)) & ((b) - 1))
|
||||
@@ -924,4 +925,9 @@ internal U64 ring_read(U8 *ring_base, U64 ring_size, U64 ring_pos, void *dst_dat
|
||||
|
||||
internal U64 u64_array_bsearch(U64 *arr, U64 count, U64 value);
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal U64 index_of_zero_u32(U32 *ptr, U64 count);
|
||||
internal U64 index_of_zero_u64(U64 *ptr, U64 count);
|
||||
|
||||
#endif // BASE_CORE_H
|
||||
|
||||
@@ -81,6 +81,14 @@ internal F32 length_3f32(Vec3F32 v) {F32 c = sqrt_f3
|
||||
internal Vec3F32 normalize_3f32(Vec3F32 v) {v = scale_3f32(v, 1.f/length_3f32(v)); return v;}
|
||||
internal Vec3F32 mix_3f32(Vec3F32 a, Vec3F32 b, F32 t) {Vec3F32 c = {mix_1f32(a.x, b.x, t), mix_1f32(a.y, b.y, t), mix_1f32(a.z, b.z, t)}; return c;}
|
||||
internal Vec3F32 cross_3f32(Vec3F32 a, Vec3F32 b) {Vec3F32 c = {a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x}; return c;}
|
||||
internal Vec3F32 xform_3f32(Vec3F32 v, Mat3x3F32 m)
|
||||
{
|
||||
Vec3F32 result;
|
||||
result.x = v.x*m.v[0][0] + v.y*m.v[1][0] + v.z*m.v[2][0];
|
||||
result.y = v.x*m.v[0][1] + v.y*m.v[1][1] + v.z*m.v[2][1];
|
||||
result.z = v.x*m.v[0][2] + v.y*m.v[1][2] + v.z*m.v[2][2];
|
||||
return result;
|
||||
}
|
||||
|
||||
internal Vec3S32 vec_3s32(S32 x, S32 y, S32 z) {Vec3S32 v = {x, y, z}; return v;}
|
||||
internal Vec3S32 add_3s32(Vec3S32 a, Vec3S32 b) {Vec3S32 c = {a.x+b.x, a.y+b.y, a.z+b.z}; return c;}
|
||||
@@ -750,7 +758,7 @@ rng1u64_array_from_list(Arena *arena, Rng1U64List *list)
|
||||
internal U64
|
||||
rng_1u64_array_bsearch(Rng1U64Array arr, U64 value)
|
||||
{
|
||||
if(arr.count > 0 && arr.v[0].min <= value && value < arr.v[arr.count-1].max)
|
||||
if(arr.count > 0 && arr.v[0].min < value && value < arr.v[arr.count-1].max)
|
||||
{
|
||||
U64 l = 0;
|
||||
U64 r = arr.count - 1;
|
||||
|
||||
@@ -485,6 +485,7 @@ internal F32 length_3f32(Vec3F32 v);
|
||||
internal Vec3F32 normalize_3f32(Vec3F32 v);
|
||||
internal Vec3F32 mix_3f32(Vec3F32 a, Vec3F32 b, F32 t);
|
||||
internal Vec3F32 cross_3f32(Vec3F32 a, Vec3F32 b);
|
||||
internal Vec3F32 xform_3f32(Vec3F32 v, Mat3x3F32 m);
|
||||
|
||||
#define v3s32(x, y, z) vec_3s32((x), (y), (z))
|
||||
internal Vec3S32 vec_3s32(S32 x, S32 y, S32 z);
|
||||
|
||||
+368
-35
@@ -480,28 +480,30 @@ str8_skip_chop_slashes(String8 string)
|
||||
//~ rjf: String Formatting & Copying
|
||||
|
||||
internal String8
|
||||
push_str8_cat(Arena *arena, String8 s1, String8 s2){
|
||||
str8_cat(Arena *arena, String8 s1, String8 s2)
|
||||
{
|
||||
String8 str;
|
||||
str.size = s1.size + s2.size;
|
||||
str.str = push_array_no_zero(arena, U8, str.size + 1);
|
||||
MemoryCopy(str.str, s1.str, s1.size);
|
||||
MemoryCopy(str.str + s1.size, s2.str, s2.size);
|
||||
str.str[str.size] = 0;
|
||||
return(str);
|
||||
return str;
|
||||
}
|
||||
|
||||
internal String8
|
||||
push_str8_copy(Arena *arena, String8 s){
|
||||
str8_copy(Arena *arena, String8 s)
|
||||
{
|
||||
String8 str;
|
||||
str.size = s.size;
|
||||
str.str = push_array_no_zero(arena, U8, str.size + 1);
|
||||
MemoryCopy(str.str, s.str, s.size);
|
||||
str.str[str.size] = 0;
|
||||
return(str);
|
||||
return str;
|
||||
}
|
||||
|
||||
internal String8
|
||||
push_str8fv(Arena *arena, char *fmt, va_list args){
|
||||
str8fv(Arena *arena, char *fmt, va_list args){
|
||||
va_list args2;
|
||||
va_copy(args2, args);
|
||||
U32 needed_bytes = raddbg_vsnprintf(0, 0, fmt, args) + 1;
|
||||
@@ -510,16 +512,28 @@ push_str8fv(Arena *arena, char *fmt, va_list args){
|
||||
result.size = raddbg_vsnprintf((char*)result.str, needed_bytes, fmt, args2);
|
||||
result.str[result.size] = 0;
|
||||
va_end(args2);
|
||||
return(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String8
|
||||
push_str8f(Arena *arena, char *fmt, ...){
|
||||
str8f(Arena *arena, char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
String8 result = push_str8fv(arena, fmt, args);
|
||||
va_end(args);
|
||||
return(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String8
|
||||
push_cstr(Arena *arena, String8 str)
|
||||
{
|
||||
U64 buffer_size = str.size + 1;
|
||||
U8 *buffer = push_array_no_zero(arena, U8, buffer_size);
|
||||
MemoryCopy(buffer, str.str, str.size);
|
||||
buffer[str.size] = 0;
|
||||
String8 result = str8(buffer, buffer_size);
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
@@ -605,36 +619,35 @@ s32_from_str8(String8 string, U32 radix)
|
||||
internal B32
|
||||
try_u64_from_str8_c_rules(String8 string, U64 *x)
|
||||
{
|
||||
B32 is_integer = 0;
|
||||
if(str8_is_integer(string, 10) && !str8_match(str8_prefix(string, 1), str8_lit("0"), 0))
|
||||
U64 radix, prefix_size;
|
||||
// hex
|
||||
if(str8_match(str8_prefix(string, 2), str8_lit("0x"), StringMatchFlag_CaseInsensitive))
|
||||
{
|
||||
is_integer = 1;
|
||||
*x = u64_from_str8(string, 10);
|
||||
radix = 0x10, prefix_size = 2;
|
||||
}
|
||||
// binary
|
||||
else if(str8_match(str8_prefix(string, 2), str8_lit("0b"), StringMatchFlag_CaseInsensitive))
|
||||
{
|
||||
radix = 2, prefix_size = 2;
|
||||
}
|
||||
// octal
|
||||
else if(str8_match(str8_prefix(string, 1), str8_lit("0"), StringMatchFlag_CaseInsensitive) && string.size > 1)
|
||||
{
|
||||
radix = 010, prefix_size = 1;
|
||||
}
|
||||
// decimal
|
||||
else
|
||||
{
|
||||
String8 hex_string = str8_skip(string, 2);
|
||||
if(str8_match(str8_prefix(string, 2), str8_lit("0x"), 0) &&
|
||||
str8_is_integer(hex_string, 0x10))
|
||||
{
|
||||
is_integer = 1;
|
||||
*x = u64_from_str8(hex_string, 0x10);
|
||||
}
|
||||
else if(str8_match(str8_prefix(string, 2), str8_lit("0b"), 0) && str8_is_integer(hex_string, 2))
|
||||
{
|
||||
is_integer = 1;
|
||||
*x = u64_from_str8(hex_string, 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
String8 oct_string = str8_skip(string, 1);
|
||||
if(str8_match(str8_prefix(string, 1), str8_lit("0"), 0) && str8_is_integer(hex_string, 010))
|
||||
{
|
||||
is_integer = 1;
|
||||
*x = u64_from_str8(oct_string, 010);
|
||||
}
|
||||
}
|
||||
radix = 10, prefix_size = 0;
|
||||
}
|
||||
|
||||
String8 integer = str8_skip(string, prefix_size);
|
||||
B32 is_integer = str8_is_integer(integer, radix);
|
||||
if(is_integer)
|
||||
{
|
||||
*x = u64_from_str8(integer, radix);
|
||||
}
|
||||
|
||||
return is_integer;
|
||||
}
|
||||
|
||||
@@ -971,6 +984,15 @@ str8_list_push(Arena *arena, String8List *list, String8 string){
|
||||
return(node);
|
||||
}
|
||||
|
||||
internal String8Node *
|
||||
str8_list_push_cstr(Arena *arena, String8List *list, String8 string)
|
||||
{
|
||||
String8Node *node = str8_list_push(arena, list, string);
|
||||
local_persist String8 null = str8_lit_comp("\0");
|
||||
str8_list_push(arena, list, null);
|
||||
return node;
|
||||
}
|
||||
|
||||
internal String8Node*
|
||||
str8_list_push_front(Arena *arena, String8List *list, String8 string){
|
||||
String8Node *node = push_array_no_zero(arena, String8Node, 1);
|
||||
@@ -1147,6 +1169,23 @@ str8_list_from_flags(Arena *arena, String8List *list,
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Data Structure Stringification Helpers
|
||||
|
||||
internal String8List
|
||||
numeric_str8_list_from_data(Arena *arena, U32 radix, String8 data, U64 stride)
|
||||
{
|
||||
String8List strs = {0};
|
||||
U64 count = data.size/stride;
|
||||
for EachIndex(idx, count)
|
||||
{
|
||||
U64 val = 0;
|
||||
MemoryCopy(&val, data.str + idx*stride, stride);
|
||||
str8_list_push(arena, &strs, str8_from_u64(arena, val, radix, 0, 0));
|
||||
}
|
||||
return strs;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf; String Arrays
|
||||
|
||||
@@ -1171,6 +1210,16 @@ str8_array_from_list(Arena *arena, String8List *list)
|
||||
return array;
|
||||
}
|
||||
|
||||
internal String8Array *
|
||||
str8_array_from_list_arr(Arena *arena, String8List *lists, U64 count)
|
||||
{
|
||||
String8Array *result = push_array(arena, String8Array, count);
|
||||
for (U64 idx = 0; idx < count; idx += 1) {
|
||||
result[idx] = str8_array_from_list(arena, &lists[idx]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String8Array
|
||||
str8_array_reserve(Arena *arena, U64 count)
|
||||
{
|
||||
@@ -1424,7 +1473,8 @@ str8_path_list_resolve_dots_in_place(String8List *path, PathStyle style)
|
||||
}
|
||||
|
||||
internal String8
|
||||
str8_path_list_join_by_style(Arena *arena, String8List *path, PathStyle style){
|
||||
str8_path_list_join_by_style(Arena *arena, String8List *path, PathStyle style)
|
||||
{
|
||||
StringJoin params = {0};
|
||||
switch(style)
|
||||
{
|
||||
@@ -1497,6 +1547,228 @@ str8_txt_pt_pair_from_string(String8 string)
|
||||
return pair;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Relative <-> Absolute Path
|
||||
|
||||
internal String8
|
||||
path_relative_dst_from_absolute_dst_src(Arena *arena, String8 dst, String8 src)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
|
||||
// rjf: gather path parts
|
||||
String8 dst_name = str8_skip_last_slash(dst);
|
||||
String8 src_folder = src;
|
||||
String8 dst_folder = str8_chop_last_slash(dst);
|
||||
String8List src_folders = str8_split_path(scratch.arena, src_folder);
|
||||
String8List dst_folders = str8_split_path(scratch.arena, dst_folder);
|
||||
|
||||
// rjf: count # of backtracks to get from src -> dest
|
||||
U64 num_backtracks = src_folders.node_count;
|
||||
for(String8Node *src_n = src_folders.first, *bp_n = dst_folders.first;
|
||||
src_n != 0 && bp_n != 0;
|
||||
src_n = src_n->next, bp_n = bp_n->next)
|
||||
{
|
||||
if(str8_match(src_n->string, bp_n->string, path_match_flags_from_os(operating_system_from_context())))
|
||||
{
|
||||
num_backtracks -= 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: only build relative string if # of backtracks is not the entire `src`.
|
||||
// if getting to `dst` from `src` requires erasing the entire `src`, then the
|
||||
// only possible way to get to `dst` from `src` is via absolute path.
|
||||
String8 dst_path = {0};
|
||||
if(num_backtracks >= src_folders.node_count)
|
||||
{
|
||||
dst_path = dst;
|
||||
}
|
||||
else
|
||||
{
|
||||
// rjf: build backtrack parts
|
||||
String8List dst_path_strs = {0};
|
||||
for(U64 idx = 0; idx < num_backtracks; idx += 1)
|
||||
{
|
||||
str8_list_push(scratch.arena, &dst_path_strs, str8_lit(".."));
|
||||
}
|
||||
|
||||
// rjf: build parts of dst which are unique from src
|
||||
{
|
||||
B32 unique_from_src = 0;
|
||||
for(String8Node *src_n = src_folders.first, *bp_n = dst_folders.first;
|
||||
bp_n != 0;
|
||||
bp_n = bp_n->next)
|
||||
{
|
||||
if(!unique_from_src && (src_n == 0 || !str8_match(src_n->string, bp_n->string, path_match_flags_from_os(operating_system_from_context()))))
|
||||
{
|
||||
unique_from_src = 1;
|
||||
}
|
||||
if(unique_from_src)
|
||||
{
|
||||
str8_list_push(scratch.arena, &dst_path_strs, bp_n->string);
|
||||
}
|
||||
if(src_n != 0)
|
||||
{
|
||||
src_n = src_n->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: build file name
|
||||
str8_list_push(scratch.arena, &dst_path_strs, dst_name);
|
||||
|
||||
// rjf: join
|
||||
StringJoin join = {0};
|
||||
{
|
||||
join.sep = str8_lit("/");
|
||||
}
|
||||
dst_path = str8_list_join(arena, &dst_path_strs, &join);
|
||||
}
|
||||
scratch_end(scratch);
|
||||
return dst_path;
|
||||
}
|
||||
|
||||
internal String8
|
||||
path_absolute_dst_from_relative_dst_src(Arena *arena, String8 dst, String8 src)
|
||||
{
|
||||
String8 result = dst;
|
||||
PathStyle dst_style = path_style_from_str8(dst);
|
||||
if(dst.size != 0 && dst_style == PathStyle_Relative)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
String8 dst_from_src_absolute = push_str8f(scratch.arena, "%S/%S", src, dst);
|
||||
String8List dst_from_src_absolute_parts = str8_split_path(scratch.arena, dst_from_src_absolute);
|
||||
PathStyle dst_from_src_absolute_style = path_style_from_str8(src);
|
||||
str8_path_list_resolve_dots_in_place(&dst_from_src_absolute_parts, dst_from_src_absolute_style);
|
||||
result = str8_path_list_join_by_style(arena, &dst_from_src_absolute_parts, dst_from_src_absolute_style);
|
||||
scratch_end(scratch);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Path Normalization
|
||||
|
||||
internal String8List
|
||||
path_normalized_list_from_string(Arena *arena, String8 path_string, PathStyle *style_out)
|
||||
{
|
||||
// rjf: analyze path
|
||||
PathStyle path_style = path_style_from_str8(path_string);
|
||||
String8List path = str8_split_path(arena, path_string);
|
||||
|
||||
// rjf: resolve dots
|
||||
str8_path_list_resolve_dots_in_place(&path, path_style);
|
||||
|
||||
// rjf: return
|
||||
if(style_out != 0)
|
||||
{
|
||||
*style_out = path_style;
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
internal String8
|
||||
path_normalized_from_string(Arena *arena, String8 path_string)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
PathStyle style = PathStyle_Relative;
|
||||
String8List path = path_normalized_list_from_string(scratch.arena, path_string, &style);
|
||||
String8 result = str8_path_list_join_by_style(arena, &path, style);
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal B32
|
||||
path_match_normalized(String8 left, String8 right)
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
String8 left_normalized = path_normalized_from_string(scratch.arena, left);
|
||||
String8 right_normalized = path_normalized_from_string(scratch.arena, right);
|
||||
B32 result = str8_match(left_normalized, right_normalized, StringMatchFlag_CaseInsensitive);
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Misc. Path Helpers
|
||||
|
||||
internal PathStyle
|
||||
path_style_from_string(String8 string)
|
||||
{
|
||||
for (U64 i = 0; i < ArrayCount(g_path_style_map); ++i)
|
||||
{
|
||||
if(str8_match(g_path_style_map[i].string, string, StringMatchFlag_CaseInsensitive))
|
||||
{
|
||||
return g_path_style_map[i].path_style;
|
||||
}
|
||||
}
|
||||
return PathStyle_Null;
|
||||
}
|
||||
|
||||
internal String8
|
||||
string_from_path_style(PathStyle style)
|
||||
{
|
||||
Assert(style < ArrayCount(g_path_style_map));
|
||||
return g_path_style_map[style].string;
|
||||
}
|
||||
|
||||
internal String8
|
||||
path_separator_string_from_style(PathStyle style)
|
||||
{
|
||||
String8 result = str8_zero();
|
||||
switch (style)
|
||||
{
|
||||
case PathStyle_Null: break;
|
||||
case PathStyle_Relative: break;
|
||||
case PathStyle_WindowsAbsolute: result = str8_lit("\\"); break;
|
||||
case PathStyle_UnixAbsolute: result = str8_lit("/"); break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal StringMatchFlags
|
||||
path_match_flags_from_os(OperatingSystem os)
|
||||
{
|
||||
StringMatchFlags flags = StringMatchFlag_SlashInsensitive;
|
||||
switch(os)
|
||||
{
|
||||
default:{}break;
|
||||
case OperatingSystem_Windows:
|
||||
{
|
||||
flags |= StringMatchFlag_CaseInsensitive;
|
||||
}break;
|
||||
case OperatingSystem_Linux:
|
||||
case OperatingSystem_Mac:
|
||||
{
|
||||
// NOTE(rjf): no-op
|
||||
}break;
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
|
||||
internal String8
|
||||
path_convert_slashes(Arena *arena, String8 path, PathStyle path_style)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
String8List list = str8_split_path(scratch.arena, path);
|
||||
StringJoin join = {0};
|
||||
join.sep = path_separator_string_from_style(path_style);
|
||||
String8 result = str8_list_join(arena, &list, &join);
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String8
|
||||
path_replace_file_extension(Arena *arena, String8 file_name, String8 ext)
|
||||
{
|
||||
String8 file_name_no_ext = str8_chop_last_dot(file_name);
|
||||
String8 result = push_str8f(arena, "%S.%S", file_name_no_ext, ext);
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: UTF-8 & UTF-16 Decoding/Encoding
|
||||
|
||||
@@ -2219,7 +2491,7 @@ fuzzy_match_find(Arena *arena, String8 needle, String8 haystack)
|
||||
U64 find_pos = 0;
|
||||
for(;find_pos < haystack.size;)
|
||||
{
|
||||
find_pos = str8_find_needle(haystack, find_pos, needle_n->string, StringMatchFlag_CaseInsensitive);
|
||||
find_pos = str8_find_needle(haystack, find_pos, needle_n->string, StringMatchFlag_CaseInsensitive|StringMatchFlag_SlashInsensitive);
|
||||
B32 is_in_gathered_ranges = 0;
|
||||
for(FuzzyMatchRangeNode *n = result.first; n != 0; n = n->next)
|
||||
{
|
||||
@@ -2486,6 +2758,67 @@ str8_deserial_read_block(String8 string, U64 off, U64 size, String8 *block_out)
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal int
|
||||
str8_compar(String8 a, String8 b, B32 ignore_case)
|
||||
{
|
||||
int cmp = 0;
|
||||
U64 size = Min(a.size, b.size);
|
||||
if (ignore_case) {
|
||||
for (U64 i = 0; i < size; ++i) {
|
||||
U8 la = char_to_lower(a.str[i]);
|
||||
U8 lb = char_to_lower(b.str[i]);
|
||||
if (la < lb) {
|
||||
cmp = -1;
|
||||
break;
|
||||
} else if (la > lb) {
|
||||
cmp = +1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (U64 i = 0; i < size; ++i) {
|
||||
if (a.str[i] < b.str[i]) {
|
||||
cmp = -1;
|
||||
break;
|
||||
} else if (a.str[i] > b.str[i]) {
|
||||
cmp = +1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cmp == 0) {
|
||||
// shorter prefix must precede longer prefixes
|
||||
if (a.size > b.size) {
|
||||
cmp = +1;
|
||||
} else if (b.size > a.size) {
|
||||
cmp = -1;
|
||||
}
|
||||
}
|
||||
|
||||
return cmp;
|
||||
}
|
||||
|
||||
internal int
|
||||
str8_compar_ignore_case(const void *a, const void *b)
|
||||
{
|
||||
return str8_compar(*(String8*)a, *(String8*)b, 1);
|
||||
}
|
||||
|
||||
internal int
|
||||
str8_compar_case_sensitive(const void *a, const void *b)
|
||||
{
|
||||
return str8_compar(*(String8*)a, *(String8*)b, 0);
|
||||
}
|
||||
|
||||
internal int
|
||||
str8_is_before_case_sensitive(const void *a, const void *b)
|
||||
{
|
||||
int cmp = str8_compar_case_sensitive(a, b);
|
||||
return cmp < 0;
|
||||
}
|
||||
|
||||
//~ rjf: Basic String Hashes
|
||||
|
||||
#if !defined(XXH_IMPLEMENTATION)
|
||||
|
||||
+39
-4
@@ -228,10 +228,16 @@ internal String8 str8_skip_chop_slashes(String8 string);
|
||||
////////////////////////////////
|
||||
//~ rjf: String Formatting & Copying
|
||||
|
||||
internal String8 push_str8_cat(Arena *arena, String8 s1, String8 s2);
|
||||
internal String8 push_str8_copy(Arena *arena, String8 s);
|
||||
internal String8 push_str8fv(Arena *arena, char *fmt, va_list args);
|
||||
internal String8 push_str8f(Arena *arena, char *fmt, ...);
|
||||
internal String8 str8_cat(Arena *arena, String8 s1, String8 s2);
|
||||
internal String8 str8_copy(Arena *arena, String8 s);
|
||||
internal String8 str8fv(Arena *arena, char *fmt, va_list args);
|
||||
internal String8 str8f(Arena *arena, char *fmt, ...);
|
||||
// TODO(rjf): remove these once we're ready to convert all usages:
|
||||
#define push_str8_cat(arena, s1, s2) str8_cat((arena), (s1), (s2))
|
||||
#define push_str8_copy(arena, s) str8_copy((arena), (s))
|
||||
#define push_str8fv(arena, fmt, args) str8fv((arena), (fmt), (args))
|
||||
#define push_str8f(arena, ...) str8f((arena), __VA_ARGS__)
|
||||
internal String8 push_cstr(Arena *arena, String8 str); // TODO(rjf): this is unnecessary - this is implied by `push_str8_copy`. need to remove.
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String <=> Integer Conversions
|
||||
@@ -285,6 +291,11 @@ internal String8List str8_list_split_by_string_chars(Arena *arena, String8List
|
||||
internal String8 str8_list_join(Arena *arena, String8List *list, StringJoin *optional_params);
|
||||
internal void str8_list_from_flags(Arena *arena, String8List *list, U32 flags, String8 *flag_string_table, U32 flag_string_count);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Data Stringification Helpers
|
||||
|
||||
internal String8List numeric_str8_list_from_data(Arena *arena, U32 radix, String8 data, U64 stride);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf; String Arrays
|
||||
|
||||
@@ -328,6 +339,29 @@ internal String8 str8_path_list_join_by_style(Arena *arena, String8List *pat
|
||||
|
||||
internal String8TxtPtPair str8_txt_pt_pair_from_string(String8 string);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Relative <-> Absolute Path
|
||||
|
||||
internal String8 path_relative_dst_from_absolute_dst_src(Arena *arena, String8 dst, String8 src);
|
||||
internal String8 path_absolute_dst_from_relative_dst_src(Arena *arena, String8 dst, String8 src);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Path Normalization
|
||||
|
||||
internal String8List path_normalized_list_from_string(Arena *arena, String8 path, PathStyle *style_out);
|
||||
internal String8 path_normalized_from_string(Arena *arena, String8 path);
|
||||
internal B32 path_match_normalized(String8 left, String8 right);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Misc. Path Helpers
|
||||
|
||||
internal PathStyle path_style_from_string(String8 string);
|
||||
internal String8 string_from_path_style(PathStyle style);
|
||||
internal String8 path_separator_string_from_style(PathStyle style);
|
||||
internal StringMatchFlags path_match_flags_from_os(OperatingSystem os);
|
||||
internal String8 path_convert_slashes(Arena *arena, String8 path, PathStyle path_style);
|
||||
internal String8 path_replace_file_extension(Arena *arena, String8 file_name, String8 ext);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: UTF-8 & UTF-16 Decoding/Encoding
|
||||
|
||||
@@ -418,6 +452,7 @@ internal void str8_serial_push_u16(Arena *arena, String8List *srl, U16 x);
|
||||
internal void str8_serial_push_u8(Arena *arena, String8List *srl, U8 x);
|
||||
internal void str8_serial_push_cstr(Arena *arena, String8List *srl, String8 str);
|
||||
internal void str8_serial_push_string(Arena *arena, String8List *srl, String8 str);
|
||||
internal void str8_serial_push_cstr(Arena *arena, String8List *srl, String8 str);
|
||||
#define str8_serial_push_array(arena, srl, ptr, count) str8_serial_push_data(arena, srl, ptr, sizeof(*(ptr)) * (count))
|
||||
#define str8_serial_push_struct(arena, srl, ptr) str8_serial_push_array(arena, srl, ptr, 1)
|
||||
|
||||
|
||||
@@ -166,6 +166,9 @@ cv_map_encoded_base_pointer(CV_Arch arch, U32 encoded_frame_reg)
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Enum -> String
|
||||
|
||||
internal String8
|
||||
cv_string_from_inline_range_kind(CV_InlineRangeKind kind)
|
||||
{
|
||||
@@ -176,3 +179,934 @@ cv_string_from_inline_range_kind(CV_InlineRangeKind kind)
|
||||
return str8_zero();
|
||||
}
|
||||
|
||||
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_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 push_str8f(arena, "%#x", 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_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);
|
||||
}
|
||||
|
||||
|
||||
@@ -2971,7 +2971,51 @@ internal CV_EncodedFramePtrReg cv_pick_fp_encoding(CV_SymFrameproc *frameproc, B
|
||||
internal CV_Reg cv_decode_fp_reg(CV_Arch arch, CV_EncodedFramePtrReg encoded_reg);
|
||||
internal U32 cv_map_encoded_base_pointer(CV_Arch arch, U32 encoded_frame_reg);
|
||||
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Enum -> String
|
||||
|
||||
internal String8 cv_string_from_inline_range_kind(CV_InlineRangeKind kind);
|
||||
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_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_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_H
|
||||
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef CODEVIEW_DUMP_H
|
||||
#define CODEVIEW_DUMP_H
|
||||
|
||||
internal String8 cv_string_from_numeric(Arena *arena, CV_NumericParsed num);
|
||||
|
||||
#endif // CODEVIEW_DUMP_H
|
||||
@@ -1,962 +0,0 @@
|
||||
// Copyright (c) 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_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);
|
||||
}
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
// Copyright (c) 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_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
|
||||
|
||||
|
||||
@@ -615,7 +615,8 @@ cv_get_symbol_type_index_offsets(Arena *arena, CV_SymKind kind, String8 data)
|
||||
case CV_SymKind_UDT: {
|
||||
cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_SymUDT, itype));
|
||||
} break;
|
||||
case CV_SymKind_GTHREAD32: {
|
||||
case CV_SymKind_GTHREAD32:
|
||||
case CV_SymKind_LTHREAD32: {
|
||||
cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_SymThread32, itype));
|
||||
} break;
|
||||
case CV_SymKind_FILESTATIC: {
|
||||
|
||||
+651
-72
@@ -8,7 +8,6 @@ coff_align_size_from_section_flags(COFF_SectionFlags flags)
|
||||
U32 align_index = COFF_SectionFlags_ExtractAlign(flags);
|
||||
switch (align_index) {
|
||||
default: break;
|
||||
case 0: align = 1; break; // alignment isn't specified, default to 1
|
||||
case COFF_SectionAlign_1Bytes: align = 1; break;
|
||||
case COFF_SectionAlign_2Bytes: align = 2; break;
|
||||
case COFF_SectionAlign_4Bytes: align = 4; break;
|
||||
@@ -32,20 +31,21 @@ coff_section_flag_from_align_size(U64 align)
|
||||
{
|
||||
COFF_SectionFlags flags = 0;
|
||||
switch (align) {
|
||||
case 1: flags = COFF_SectionAlign_1Bytes; break;
|
||||
case 2: flags = COFF_SectionAlign_2Bytes; break;
|
||||
case 4: flags = COFF_SectionAlign_4Bytes; break;
|
||||
case 8: flags = COFF_SectionAlign_8Bytes; break;
|
||||
case 16: flags = COFF_SectionAlign_16Bytes; break;
|
||||
case 32: flags = COFF_SectionAlign_32Bytes; break;
|
||||
case 64: flags = COFF_SectionAlign_64Bytes; break;
|
||||
case 128: flags = COFF_SectionAlign_128Bytes; break;
|
||||
case 256: flags = COFF_SectionAlign_256Bytes; break;
|
||||
case 512: flags = COFF_SectionAlign_512Bytes; break;
|
||||
case 1024: flags = COFF_SectionAlign_1024Bytes; break;
|
||||
case 2048: flags = COFF_SectionAlign_2048Bytes; break;
|
||||
case 4096: flags = COFF_SectionAlign_4096Bytes; break;
|
||||
case 8192: flags = COFF_SectionAlign_8192Bytes; break;
|
||||
case 0: flags = COFF_SectionAlign_None; break;
|
||||
case 1: flags = COFF_SectionAlign_1Bytes; break;
|
||||
case 2: flags = COFF_SectionAlign_2Bytes; break;
|
||||
case 4: flags = COFF_SectionAlign_4Bytes; break;
|
||||
case 8: flags = COFF_SectionAlign_8Bytes; break;
|
||||
case 16: flags = COFF_SectionAlign_16Bytes; break;
|
||||
case 32: flags = COFF_SectionAlign_32Bytes; break;
|
||||
case 64: flags = COFF_SectionAlign_64Bytes; break;
|
||||
case 128: flags = COFF_SectionAlign_128Bytes; break;
|
||||
case 256: flags = COFF_SectionAlign_256Bytes; break;
|
||||
case 512: flags = COFF_SectionAlign_512Bytes; break;
|
||||
case 1024: flags = COFF_SectionAlign_1024Bytes; break;
|
||||
case 2048: flags = COFF_SectionAlign_2048Bytes; break;
|
||||
case 4096: flags = COFF_SectionAlign_4096Bytes; break;
|
||||
case 8192: flags = COFF_SectionAlign_8192Bytes; break;
|
||||
}
|
||||
flags <<= COFF_SectionFlag_AlignShift;
|
||||
return flags;
|
||||
@@ -79,14 +79,7 @@ coff_parse_section_name(String8 full_name, String8 *name_out, String8 *postfix_o
|
||||
for (U64 i = 0; i < full_name.size; ++i) {
|
||||
if (full_name.str[i] == '$') {
|
||||
*name_out = str8(full_name.str, i);
|
||||
*postfix_out = str8(full_name.str + i + 1, full_name.size - i - 1);
|
||||
|
||||
// TLS sections don't have a postfix but we still have to sort them based
|
||||
// on dollar sign so they are sloted between CRT's _tls_start and _tls_end sections.
|
||||
if (str8_match_lit(".tls", *name_out, 0) && postfix_out->size == 0) {
|
||||
*postfix_out = str8_lit("$");
|
||||
}
|
||||
|
||||
*postfix_out = str8(full_name.str + i, full_name.size - i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -179,6 +172,105 @@ coff_apply_size_from_reloc(COFF_MachineType machine, COFF_RelocType x)
|
||||
return 0;
|
||||
}
|
||||
|
||||
internal COFF_RelocValue
|
||||
coff_pick_reloc_value_x64(COFF_Reloc_X64 type,
|
||||
U64 image_base,
|
||||
U64 reloc_virtual_offset,
|
||||
U32 symbol_section_number,
|
||||
U32 symbol_section_offset,
|
||||
S64 symbol_virtual_offset)
|
||||
{
|
||||
U64 reloc_value_size = 0;
|
||||
S64 reloc_value = 0;
|
||||
|
||||
switch (type) {
|
||||
case COFF_Reloc_X64_Abs: {} break;
|
||||
case COFF_Reloc_X64_Addr64: {
|
||||
reloc_value_size = 8;
|
||||
reloc_value = symbol_virtual_offset + (S64)image_base;
|
||||
} break;
|
||||
case COFF_Reloc_X64_Addr32: {
|
||||
reloc_value_size = 4;
|
||||
reloc_value = safe_cast_s32(symbol_virtual_offset + (S64)image_base);
|
||||
} break;
|
||||
case COFF_Reloc_X64_Addr32Nb: {
|
||||
reloc_value_size = 4;
|
||||
reloc_value = symbol_virtual_offset;
|
||||
} break;
|
||||
case COFF_Reloc_X64_Rel32: {
|
||||
reloc_value_size = 4;
|
||||
reloc_value = safe_cast_s32(symbol_virtual_offset - reloc_virtual_offset - (4 + 0));
|
||||
} break;
|
||||
case COFF_Reloc_X64_Rel32_1: {
|
||||
reloc_value_size = 4;
|
||||
reloc_value = safe_cast_s32(symbol_virtual_offset - reloc_virtual_offset - (4 + 1));
|
||||
} break;
|
||||
case COFF_Reloc_X64_Rel32_2: {
|
||||
reloc_value_size = 4;
|
||||
reloc_value = safe_cast_s32(symbol_virtual_offset - reloc_virtual_offset - (4 + 2));
|
||||
} break;
|
||||
case COFF_Reloc_X64_Rel32_3: {
|
||||
reloc_value_size = 4;
|
||||
reloc_value = safe_cast_s32(symbol_virtual_offset - reloc_virtual_offset - (4 + 3));
|
||||
} break;
|
||||
case COFF_Reloc_X64_Rel32_4: {
|
||||
reloc_value_size = 4;
|
||||
reloc_value = safe_cast_s32(symbol_virtual_offset - reloc_virtual_offset - (4 + 4));
|
||||
} break;
|
||||
case COFF_Reloc_X64_Rel32_5: {
|
||||
reloc_value_size = 4;
|
||||
reloc_value = safe_cast_s32(symbol_virtual_offset - reloc_virtual_offset - (4 + 5));
|
||||
} break;
|
||||
case COFF_Reloc_X64_Section: {
|
||||
reloc_value_size = 4;
|
||||
reloc_value = symbol_section_number;
|
||||
} break;
|
||||
case COFF_Reloc_X64_SecRel: {
|
||||
reloc_value_size = 4;
|
||||
reloc_value = symbol_section_offset;
|
||||
} break;
|
||||
case COFF_Reloc_X64_SecRel7:
|
||||
case COFF_Reloc_X64_Token:
|
||||
case COFF_Reloc_X64_SRel32:
|
||||
case COFF_Reloc_X64_Pair:
|
||||
case COFF_Reloc_X64_SSpan32:
|
||||
case COFF_Reloc_X64_Unknown_11: {
|
||||
NotImplemented;
|
||||
} break;
|
||||
}
|
||||
|
||||
COFF_RelocValue result = {0};
|
||||
result.size = reloc_value_size;
|
||||
result.value = reloc_value;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String8
|
||||
coff_make_lib_member_header(Arena *arena, String8 name, COFF_TimeStamp time_stamp, U16 user_id, U16 group_id, U16 mode, U32 size)
|
||||
{
|
||||
Assert(name.size < 16);
|
||||
Assert(user_id < 10000);
|
||||
Assert(group_id < 10000);
|
||||
Assert(mode < 10000);
|
||||
Assert(size < 1000000000);
|
||||
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
String8List list = {0};
|
||||
str8_list_pushf(scratch.arena, &list, "%-16.*s", str8_varg(name));
|
||||
str8_list_pushf(scratch.arena, &list, "%-12u", time_stamp);
|
||||
str8_list_pushf(scratch.arena, &list, "%-6u", user_id);
|
||||
str8_list_pushf(scratch.arena, &list, "%-6u", group_id);
|
||||
str8_list_pushf(scratch.arena, &list, "%-8u", mode);
|
||||
str8_list_pushf(scratch.arena, &list, "%-10u", size);
|
||||
str8_list_pushf(scratch.arena, &list, "`\n");
|
||||
String8 result = str8_list_join(arena, &list, 0);
|
||||
|
||||
Assert(result.size == sizeof(COFF_ArchiveMemberHeader));
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String8
|
||||
coff_make_import_lookup(Arena *arena, U16 hint, String8 name)
|
||||
{
|
||||
@@ -206,18 +298,40 @@ coff_make_ordinal64(U16 hint)
|
||||
}
|
||||
|
||||
internal String8
|
||||
coff_make_import_header_by_name(Arena *arena,
|
||||
String8 dll_name,
|
||||
COFF_MachineType machine,
|
||||
COFF_TimeStamp time_stamp,
|
||||
String8 name,
|
||||
U16 hint,
|
||||
COFF_ImportType type)
|
||||
coff_ordinal_data_from_hint(Arena *arena, COFF_MachineType machine, U16 hint)
|
||||
{
|
||||
String8 ordinal_data = {0};
|
||||
switch (machine) {
|
||||
case COFF_MachineType_Unknown: break;
|
||||
case COFF_MachineType_X64: {
|
||||
U64 *ordinal = push_array(arena, U64, 1);
|
||||
*ordinal = coff_make_ordinal64(hint);
|
||||
ordinal_data = str8_struct(ordinal);
|
||||
} break;
|
||||
case COFF_MachineType_X86: {
|
||||
U32 *ordinal = push_array(arena, U32, 1);
|
||||
*ordinal = coff_make_ordinal32(hint);
|
||||
ordinal_data = str8_struct(ordinal);
|
||||
} break;
|
||||
default: { NotImplemented; } break;
|
||||
}
|
||||
return ordinal_data;
|
||||
}
|
||||
|
||||
internal String8
|
||||
coff_make_import_header(Arena *arena,
|
||||
COFF_MachineType machine,
|
||||
COFF_TimeStamp time_stamp,
|
||||
String8 dll_name,
|
||||
COFF_ImportByType import_by,
|
||||
String8 name,
|
||||
U16 hint_or_ordinal,
|
||||
COFF_ImportType type)
|
||||
{
|
||||
COFF_ImportHeaderFlags flags = 0;
|
||||
flags |= (type & COFF_ImportHeader_TypeMask) << COFF_ImportHeader_TypeShift;
|
||||
flags |= COFF_ImportBy_Name << COFF_ImportHeader_ImportByShift;
|
||||
|
||||
flags |= import_by << COFF_ImportHeader_ImportByShift;
|
||||
|
||||
COFF_ImportHeader header = {0};
|
||||
header.sig1 = COFF_MachineType_Unknown;
|
||||
header.sig2 = max_U16;
|
||||
@@ -225,7 +339,7 @@ coff_make_import_header_by_name(Arena *arena,
|
||||
header.machine = machine;
|
||||
header.time_stamp = time_stamp;
|
||||
header.data_size = safe_cast_u32(name.size + dll_name.size + 2);
|
||||
header.hint_or_ordinal = hint;
|
||||
header.hint_or_ordinal = hint_or_ordinal;
|
||||
header.flags = flags;
|
||||
|
||||
// alloc memory
|
||||
@@ -249,46 +363,33 @@ coff_make_import_header_by_name(Arena *arena,
|
||||
return import_data;
|
||||
}
|
||||
|
||||
internal String8
|
||||
coff_make_import_header_by_ordinal(Arena *arena,
|
||||
String8 dll_name,
|
||||
COFF_MachineType machine,
|
||||
COFF_TimeStamp time_stamp,
|
||||
U16 ordinal,
|
||||
COFF_ImportType type)
|
||||
internal U8
|
||||
coff_code_align_byte_from_machine(COFF_MachineType machine)
|
||||
{
|
||||
COFF_ImportHeaderFlags flags = 0;
|
||||
flags |= (type & COFF_ImportHeader_TypeMask) << COFF_ImportHeader_TypeShift;
|
||||
flags |= COFF_ImportBy_Ordinal << COFF_ImportHeader_ImportByShift;
|
||||
|
||||
COFF_ImportHeader header = {0};
|
||||
header.sig1 = COFF_MachineType_Unknown;
|
||||
header.sig2 = max_U16;
|
||||
header.version = 0;
|
||||
header.machine = machine;
|
||||
header.time_stamp = time_stamp;
|
||||
header.data_size = safe_cast_u32(dll_name.size + 2);
|
||||
header.hint_or_ordinal = ordinal;
|
||||
header.flags = flags;
|
||||
|
||||
// alloc memory
|
||||
U64 buffer_size = sizeof(header) + header.data_size;
|
||||
U8 *buffer = push_array_no_zero(arena, U8, buffer_size);
|
||||
|
||||
// copy header
|
||||
MemoryCopyStruct(buffer, &header);
|
||||
|
||||
// no function name write zero
|
||||
U8 *func_name = buffer + sizeof(header);
|
||||
func_name[0] = 0;
|
||||
|
||||
// copy dll name
|
||||
U8 *dll_name_buffer = buffer + sizeof(header) + /* name.size */ + 1;
|
||||
MemoryCopy(dll_name_buffer, dll_name.str, dll_name.size);
|
||||
dll_name_buffer[dll_name.size] = 0;
|
||||
|
||||
String8 import_data = str8(buffer, buffer_size);
|
||||
return import_data;
|
||||
U8 align_byte = 0;
|
||||
switch (machine) {
|
||||
case COFF_MachineType_Unknown: break;
|
||||
case COFF_MachineType_X64:
|
||||
case COFF_MachineType_X86: {
|
||||
align_byte = 0xCC;
|
||||
} break;
|
||||
default: { NotImplemented; } break;
|
||||
}
|
||||
return align_byte;
|
||||
}
|
||||
|
||||
internal U16
|
||||
coff_default_align_from_machine(COFF_MachineType machine)
|
||||
{
|
||||
U16 align = 0;
|
||||
switch (machine) {
|
||||
case COFF_MachineType_Unknown: break;
|
||||
case COFF_MachineType_X64: {
|
||||
align = 16;
|
||||
} break;
|
||||
default: { NotImplemented; } break;
|
||||
}
|
||||
return align;
|
||||
}
|
||||
|
||||
internal U64
|
||||
@@ -358,3 +459,481 @@ coff_foff_from_voff(COFF_SectionHeader *sections, U64 section_count, U64 voff)
|
||||
return foff;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Enum -> String
|
||||
|
||||
internal String8
|
||||
coff_string_from_time_stamp(Arena *arena, COFF_TimeStamp time_stamp)
|
||||
{
|
||||
String8 result;
|
||||
if (time_stamp == 0) {
|
||||
result = str8_lit("0");
|
||||
} else if (time_stamp >= max_U32) {
|
||||
result = str8_lit("-1");
|
||||
} else {
|
||||
DateTime dt = date_time_from_unix_time(time_stamp);
|
||||
result = push_date_time_string(arena, &dt);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
read_only struct
|
||||
{
|
||||
String8 string;
|
||||
COFF_MachineType machine;
|
||||
} g_coff_machine_map[] = {
|
||||
{ str8_lit_comp(""), COFF_MachineType_Unknown },
|
||||
{ str8_lit_comp("X86"), COFF_MachineType_X86 },
|
||||
{ str8_lit_comp("Amd64"), COFF_MachineType_X64 },
|
||||
{ str8_lit_comp("X64"), COFF_MachineType_X64 },
|
||||
{ str8_lit_comp("Am33"), COFF_MachineType_Am33 },
|
||||
{ str8_lit_comp("Arm"), COFF_MachineType_Arm },
|
||||
{ str8_lit_comp("Arm64"), COFF_MachineType_Arm64 },
|
||||
{ str8_lit_comp("ArmNt"), COFF_MachineType_ArmNt },
|
||||
{ str8_lit_comp("Ebc"), COFF_MachineType_Ebc },
|
||||
{ str8_lit_comp("Ia64"), COFF_MachineType_Ia64 },
|
||||
{ str8_lit_comp("M32r"), COFF_MachineType_M32R },
|
||||
{ str8_lit_comp("Mips16"), COFF_MachineType_Mips16 },
|
||||
{ str8_lit_comp("MipsFpu"), COFF_MachineType_MipsFpu },
|
||||
{ str8_lit_comp("MipsFpu16"), COFF_MachineType_MipsFpu16 },
|
||||
{ str8_lit_comp("PowerPc"), COFF_MachineType_PowerPc },
|
||||
{ str8_lit_comp("PowerPcFp"), COFF_MachineType_PowerPcFp },
|
||||
{ str8_lit_comp("R4000"), COFF_MachineType_R4000 },
|
||||
{ str8_lit_comp("RiscV32"), COFF_MachineType_RiscV32 },
|
||||
{ str8_lit_comp("RiscV64"), COFF_MachineType_RiscV64 },
|
||||
{ str8_lit_comp("Sh3"), COFF_MachineType_Sh3 },
|
||||
{ str8_lit_comp("Sh3Dsp"), COFF_MachineType_Sh3Dsp },
|
||||
{ str8_lit_comp("Sh4"), COFF_MachineType_Sh4 },
|
||||
{ str8_lit_comp("Sh5"), COFF_MachineType_Sh5 },
|
||||
{ str8_lit_comp("Thumb"), COFF_MachineType_Thumb },
|
||||
{ str8_lit_comp("WceMipsV2"), COFF_MachineType_WceMipsV2 },
|
||||
};
|
||||
|
||||
read_only static struct {
|
||||
char * name;
|
||||
COFF_ImportType type;
|
||||
} g_coff_import_header_type_map[] = {
|
||||
{ "Code", COFF_ImportHeader_Code },
|
||||
{ "Data", COFF_ImportHeader_Data },
|
||||
{ "Const", COFF_ImportHeader_Const },
|
||||
};
|
||||
|
||||
internal String8
|
||||
coff_string_from_comdat_select_type(COFF_ComdatSelectType type)
|
||||
{
|
||||
String8 result = str8_zero();
|
||||
switch (type) {
|
||||
case COFF_ComdatSelect_Null: result = str8_lit("Null"); break;
|
||||
case COFF_ComdatSelect_NoDuplicates: result = str8_lit("NoDuplicates"); break;
|
||||
case COFF_ComdatSelect_Any: result = str8_lit("Any"); break;
|
||||
case COFF_ComdatSelect_SameSize: result = str8_lit("SameSize"); break;
|
||||
case COFF_ComdatSelect_ExactMatch: result = str8_lit("ExactMatch"); break;
|
||||
case COFF_ComdatSelect_Associative: result = str8_lit("Associative"); break;
|
||||
case COFF_ComdatSelect_Largest: result = str8_lit("Largest"); break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String8
|
||||
coff_string_from_machine_type(COFF_MachineType machine)
|
||||
{
|
||||
for (U64 i = 0; i < ArrayCount(g_coff_machine_map); ++i) {
|
||||
if (g_coff_machine_map[i].machine == machine) {
|
||||
return g_coff_machine_map[i].string;
|
||||
}
|
||||
}
|
||||
return str8_zero();
|
||||
}
|
||||
|
||||
internal String8
|
||||
coff_string_from_flags(Arena *arena, COFF_FileHeaderFlags flags)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
String8List list = {0};
|
||||
|
||||
if (flags & COFF_FileHeaderFlag_RelocStripped) {
|
||||
str8_list_pushf(scratch.arena, &list, "Relocs Stripped");
|
||||
}
|
||||
if (flags & COFF_FileHeaderFlag_ExecutableImage) {
|
||||
str8_list_pushf(scratch.arena, &list, "Executable");
|
||||
}
|
||||
if (flags & COFF_FileHeaderFlag_LineNumbersStripped) {
|
||||
str8_list_pushf(scratch.arena, &list, "Line Numbers Stripped");
|
||||
}
|
||||
if (flags & COFF_FileHeaderFlag_SymbolsStripped) {
|
||||
str8_list_pushf(scratch.arena, &list, "Symbols Stripped");
|
||||
}
|
||||
if (flags & COFF_FileHeaderFlag_LargeAddressAware) {
|
||||
str8_list_pushf(scratch.arena, &list, "Large Address Aware");
|
||||
}
|
||||
if (flags & COFF_FileHeaderFlag_32BitMachine) {
|
||||
str8_list_pushf(scratch.arena, &list, "32-Bit Machine");
|
||||
}
|
||||
if (flags & COFF_FileHeaderFlag_DebugStripped) {
|
||||
str8_list_pushf(scratch.arena, &list, "Debug Stripped");
|
||||
}
|
||||
if (flags & COFF_FileHeaderFlag_RemovableRunFromSwap) {
|
||||
str8_list_pushf(scratch.arena, &list, "Removeable Run From Swap");
|
||||
}
|
||||
if (flags & COFF_FileHeaderFlag_NetRunFromSwap) {
|
||||
str8_list_pushf(scratch.arena, &list, "Net Run From Swap");
|
||||
}
|
||||
if (flags & COFF_FileHeaderFlag_System) {
|
||||
str8_list_pushf(scratch.arena, &list, "System");
|
||||
}
|
||||
if (flags & COFF_FileHeaderFlag_Dll) {
|
||||
str8_list_pushf(scratch.arena, &list, "DLL");
|
||||
}
|
||||
if (flags & COFF_FileHeaderFlag_UpSystemOnly) {
|
||||
str8_list_pushf(scratch.arena, &list, "Up System Only");
|
||||
}
|
||||
|
||||
String8 result = str8_list_join(arena, &list, &(StringJoin){.sep=str8_lit(", ")});
|
||||
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String8
|
||||
coff_string_from_section_flags(Arena *arena, COFF_SectionFlags flags)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
String8List list = {0};
|
||||
|
||||
if (flags & COFF_SectionFlag_TypeNoPad) {
|
||||
str8_list_pushf(scratch.arena, &list, "TypeNoPad");
|
||||
}
|
||||
if (flags & COFF_SectionFlag_CntCode) {
|
||||
str8_list_pushf(scratch.arena, &list, "CntCode");
|
||||
}
|
||||
if (flags & COFF_SectionFlag_CntInitializedData) {
|
||||
str8_list_pushf(scratch.arena, &list, "CntInitializedData");
|
||||
}
|
||||
if (flags & COFF_SectionFlag_CntUninitializedData) {
|
||||
str8_list_pushf(scratch.arena, &list, "CntUninitializedData");
|
||||
}
|
||||
if (flags & COFF_SectionFlag_LnkOther) {
|
||||
str8_list_pushf(scratch.arena, &list, "LnkOther");
|
||||
}
|
||||
if (flags & COFF_SectionFlag_LnkInfo) {
|
||||
str8_list_pushf(scratch.arena, &list, "LnkInfo");
|
||||
}
|
||||
if (flags & COFF_SectionFlag_LnkCOMDAT) {
|
||||
str8_list_pushf(scratch.arena, &list, "LnkCOMDAT");
|
||||
}
|
||||
if (flags & COFF_SectionFlag_GpRel) {
|
||||
str8_list_pushf(scratch.arena, &list, "GpRel");
|
||||
}
|
||||
if (flags & COFF_SectionFlag_Mem16Bit) {
|
||||
str8_list_pushf(scratch.arena, &list, "Mem16Bit");
|
||||
}
|
||||
if (flags & COFF_SectionFlag_MemLocked) {
|
||||
str8_list_pushf(scratch.arena, &list, "MemLocked");
|
||||
}
|
||||
if (flags & COFF_SectionFlag_MemPreload) {
|
||||
str8_list_pushf(scratch.arena, &list, "MemPreload");
|
||||
}
|
||||
if (flags & COFF_SectionFlag_LnkNRelocOvfl) {
|
||||
str8_list_pushf(scratch.arena, &list, "LnkNRelocOvfl");
|
||||
}
|
||||
if (flags & COFF_SectionFlag_MemDiscardable) {
|
||||
str8_list_pushf(scratch.arena, &list, "MemDiscardable");
|
||||
}
|
||||
if (flags & COFF_SectionFlag_MemNotCached) {
|
||||
str8_list_pushf(scratch.arena, &list, "MemNotCached");
|
||||
}
|
||||
if (flags & COFF_SectionFlag_MemNotPaged) {
|
||||
str8_list_pushf(scratch.arena, &list, "MemNotPaged");
|
||||
}
|
||||
if (flags & COFF_SectionFlag_MemShared) {
|
||||
str8_list_pushf(scratch.arena, &list, "MemShared");
|
||||
}
|
||||
if (flags & COFF_SectionFlag_MemExecute) {
|
||||
str8_list_pushf(scratch.arena, &list, "MemExecute");
|
||||
}
|
||||
if (flags & COFF_SectionFlag_MemRead) {
|
||||
str8_list_pushf(scratch.arena, &list, "MemRead");
|
||||
}
|
||||
if (flags & COFF_SectionFlag_MemWrite) {
|
||||
str8_list_pushf(scratch.arena, &list, "MemWrite");
|
||||
}
|
||||
|
||||
U64 align = coff_align_size_from_section_flags(flags);
|
||||
if (align) {
|
||||
str8_list_pushf(scratch.arena, &list, "Align=%u", align);
|
||||
}
|
||||
|
||||
if (!list.node_count) {
|
||||
str8_list_pushf(scratch.arena, &list, "None");
|
||||
}
|
||||
|
||||
StringJoin join = {0};
|
||||
join.sep = str8_lit(", ");
|
||||
String8 result = str8_list_join(arena, &list, &join);
|
||||
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String8
|
||||
coff_string_from_resource_memory_flags(Arena *arena, COFF_ResourceMemoryFlags flags)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
|
||||
String8List list = {0};
|
||||
|
||||
if (flags & COFF_ResourceMemoryFlag_Moveable) {
|
||||
flags &= COFF_ResourceMemoryFlag_Moveable;
|
||||
str8_list_pushf(scratch.arena, &list, "Moveable");
|
||||
}
|
||||
if (flags & COFF_ResourceMemoryFlag_Pure) {
|
||||
flags &= COFF_ResourceMemoryFlag_Pure;
|
||||
str8_list_pushf(scratch.arena, &list, "Pure");
|
||||
}
|
||||
if (flags & COFF_ResourceMemoryFlag_Discardable) {
|
||||
flags &= COFF_ResourceMemoryFlag_Discardable;
|
||||
str8_list_pushf(scratch.arena, &list, "Discardable");
|
||||
}
|
||||
if (flags != 0) {
|
||||
str8_list_pushf(scratch.arena, &list, "%#x", flags);
|
||||
}
|
||||
|
||||
String8 result = str8_list_join(arena, &list, &(StringJoin){.sep=str8_lit(", ")});
|
||||
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String8
|
||||
coff_string_from_import_header_type(COFF_ImportType type)
|
||||
{
|
||||
for (U64 i = 0; i < ArrayCount(g_coff_import_header_type_map); ++i) {
|
||||
if (g_coff_import_header_type_map[i].type == type) {
|
||||
return str8_cstring(g_coff_import_header_type_map[i].name);
|
||||
}
|
||||
}
|
||||
return str8(0,0);
|
||||
}
|
||||
|
||||
internal String8
|
||||
coff_string_from_sym_dtype(COFF_SymDType x)
|
||||
{
|
||||
switch (x) {
|
||||
case COFF_SymDType_Null: return str8_lit("Null");
|
||||
case COFF_SymDType_Ptr : return str8_lit("Ptr");
|
||||
case COFF_SymDType_Func: return str8_lit("Func");
|
||||
case COFF_SymDType_Array: return str8_lit("Array");
|
||||
}
|
||||
return str8_zero();
|
||||
}
|
||||
|
||||
internal String8
|
||||
coff_string_from_sym_type(COFF_SymType x)
|
||||
{
|
||||
switch (x) {
|
||||
case COFF_SymType_Null: return str8_lit("Null");
|
||||
case COFF_SymType_Void: return str8_lit("Void");
|
||||
case COFF_SymType_Char: return str8_lit("Char");
|
||||
case COFF_SymType_Short: return str8_lit("Short");
|
||||
case COFF_SymType_Int: return str8_lit("Int");
|
||||
case COFF_SymType_Long: return str8_lit("Long");
|
||||
case COFF_SymType_Float: return str8_lit("Float");
|
||||
case COFF_SymType_Double: return str8_lit("Double");
|
||||
case COFF_SymType_Struct: return str8_lit("Struct");
|
||||
case COFF_SymType_Union: return str8_lit("Union");
|
||||
case COFF_SymType_Enum: return str8_lit("Enum");
|
||||
case COFF_SymType_MemberOfEnumeration: return str8_lit("MOE");
|
||||
case COFF_SymType_Byte: return str8_lit("Byte");
|
||||
case COFF_SymType_Word: return str8_lit("Word");
|
||||
case COFF_SymType_UInt: return str8_lit("UInt");
|
||||
case COFF_SymType_DWord: return str8_lit("DWord");
|
||||
}
|
||||
return str8_zero();
|
||||
}
|
||||
|
||||
internal String8
|
||||
coff_string_from_sym_storage_class(COFF_SymStorageClass x)
|
||||
{
|
||||
switch (x) {
|
||||
case COFF_SymStorageClass_Null: break;
|
||||
case COFF_SymStorageClass_EndOfFunction: return str8_lit("EndOfFunction");
|
||||
case COFF_SymStorageClass_Automatic: return str8_lit("Automatic");
|
||||
case COFF_SymStorageClass_External: return str8_lit("External");
|
||||
case COFF_SymStorageClass_Static: return str8_lit("Static");
|
||||
case COFF_SymStorageClass_Register: return str8_lit("Register");
|
||||
case COFF_SymStorageClass_ExternalDef: return str8_lit("Def");
|
||||
case COFF_SymStorageClass_Label: return str8_lit("Label");
|
||||
case COFF_SymStorageClass_UndefinedLabel: return str8_lit("UndefinedLabel");
|
||||
case COFF_SymStorageClass_MemberOfStruct: return str8_lit("Struct");
|
||||
case COFF_SymStorageClass_Argument: return str8_lit("Argument");
|
||||
case COFF_SymStorageClass_StructTag: return str8_lit("Tag");
|
||||
case COFF_SymStorageClass_MemberOfUnion: return str8_lit("Union");
|
||||
case COFF_SymStorageClass_UnionTag: return str8_lit("Tag");
|
||||
case COFF_SymStorageClass_TypeDefinition: return str8_lit("Definition");
|
||||
case COFF_SymStorageClass_UndefinedStatic: return str8_lit("Static");
|
||||
case COFF_SymStorageClass_EnumTag: return str8_lit("Tag");
|
||||
case COFF_SymStorageClass_MemberOfEnum: return str8_lit("Enum");
|
||||
case COFF_SymStorageClass_RegisterParam: return str8_lit("Param");
|
||||
case COFF_SymStorageClass_BitField: return str8_lit("Field");
|
||||
case COFF_SymStorageClass_Block: return str8_lit("Block");
|
||||
case COFF_SymStorageClass_Function: return str8_lit("Function");
|
||||
case COFF_SymStorageClass_EndOfStruct: return str8_lit("Struct");
|
||||
case COFF_SymStorageClass_File: return str8_lit("File");
|
||||
case COFF_SymStorageClass_Section: return str8_lit("Section");
|
||||
case COFF_SymStorageClass_WeakExternal: return str8_lit("External");
|
||||
case COFF_SymStorageClass_CLRToken: return str8_lit("Token");
|
||||
}
|
||||
return str8_zero();
|
||||
}
|
||||
|
||||
internal String8
|
||||
coff_string_from_weak_ext_type(COFF_WeakExtType x)
|
||||
{
|
||||
switch (x) {
|
||||
case COFF_WeakExt_NoLibrary: return str8_lit("NoLibrary");
|
||||
case COFF_WeakExt_SearchLibrary: return str8_lit("SearchLibrary");
|
||||
case COFF_WeakExt_SearchAlias: return str8_lit("SearchAlias");
|
||||
}
|
||||
return str8_zero();
|
||||
}
|
||||
|
||||
internal String8
|
||||
coff_string_from_reloc_x86(COFF_Reloc_X86 x)
|
||||
{
|
||||
switch (x) {
|
||||
case COFF_Reloc_X86_Abs: return str8_lit("Abs");
|
||||
case COFF_Reloc_X86_Dir16: return str8_lit("Dir16");
|
||||
case COFF_Reloc_X86_Rel16: return str8_lit("Rel16");
|
||||
case COFF_Reloc_X86_Unknown0: return str8_lit("Unknown0");
|
||||
case COFF_Reloc_X86_Unknown2: return str8_lit("Unknown2");
|
||||
case COFF_Reloc_X86_Unknown3: return str8_lit("Unknown3");
|
||||
case COFF_Reloc_X86_Dir32: return str8_lit("Dir32");
|
||||
case COFF_Reloc_X86_Dir32Nb: return str8_lit("Dir32Nb");
|
||||
case COFF_Reloc_X86_Seg12: return str8_lit("Seg12");
|
||||
case COFF_Reloc_X86_Section: return str8_lit("Section");
|
||||
case COFF_Reloc_X86_SecRel: return str8_lit("SecRel");
|
||||
case COFF_Reloc_X86_Token: return str8_lit("Token");
|
||||
case COFF_Reloc_X86_SecRel7: return str8_lit("SecRel7");
|
||||
case COFF_Reloc_X86_Unknown4: return str8_lit("Unknown4");
|
||||
case COFF_Reloc_X86_Unknown5: return str8_lit("Unknown5");
|
||||
case COFF_Reloc_X86_Unknown6: return str8_lit("Unknown6");
|
||||
case COFF_Reloc_X86_Unknown7: return str8_lit("Unknown7");
|
||||
case COFF_Reloc_X86_Unknown8: return str8_lit("Unknown8");
|
||||
case COFF_Reloc_X86_Unknown9: return str8_lit("Unknown9");
|
||||
case COFF_Reloc_X86_Rel32: return str8_lit("Rel32");
|
||||
}
|
||||
return str8_zero();
|
||||
}
|
||||
|
||||
internal String8
|
||||
coff_string_from_reloc_x64(COFF_Reloc_X64 x)
|
||||
{
|
||||
switch (x) {
|
||||
case COFF_Reloc_X64_Abs: return str8_lit("Abs");
|
||||
case COFF_Reloc_X64_Addr64: return str8_lit("Addr64");
|
||||
case COFF_Reloc_X64_Addr32: return str8_lit("Addr32");
|
||||
case COFF_Reloc_X64_Addr32Nb: return str8_lit("Addr32Nb");
|
||||
case COFF_Reloc_X64_Rel32: return str8_lit("Rel32");
|
||||
case COFF_Reloc_X64_Rel32_1: return str8_lit("Rel32_1");
|
||||
case COFF_Reloc_X64_Rel32_2: return str8_lit("Rel32_2");
|
||||
case COFF_Reloc_X64_Rel32_3: return str8_lit("Rel32_3");
|
||||
case COFF_Reloc_X64_Rel32_4: return str8_lit("Rel32_4");
|
||||
case COFF_Reloc_X64_Rel32_5: return str8_lit("Rel32_5");
|
||||
case COFF_Reloc_X64_Section: return str8_lit("Section");
|
||||
case COFF_Reloc_X64_SecRel: return str8_lit("SecRel");
|
||||
case COFF_Reloc_X64_SecRel7: return str8_lit("SecRel7");
|
||||
case COFF_Reloc_X64_Token: return str8_lit("Token");
|
||||
case COFF_Reloc_X64_SRel32: return str8_lit("SRel32");
|
||||
case COFF_Reloc_X64_Pair: return str8_lit("Pair");
|
||||
case COFF_Reloc_X64_SSpan32: return str8_lit("SSpan32");
|
||||
}
|
||||
return str8_zero();
|
||||
}
|
||||
|
||||
internal String8
|
||||
coff_string_from_reloc_arm(COFF_Reloc_Arm x)
|
||||
{
|
||||
switch (x) {
|
||||
case COFF_Reloc_Arm_Abs: return str8_lit("Abs");
|
||||
case COFF_Reloc_Arm_Addr32: return str8_lit("Addr32");
|
||||
case COFF_Reloc_Arm_Addr32Nb: return str8_lit("Addr32Nb");
|
||||
case COFF_Reloc_Arm_Branch24: return str8_lit("Branch24");
|
||||
case COFF_Reloc_Arm_Branch11: return str8_lit("Branch11");
|
||||
case COFF_Reloc_Arm_Unknown1: return str8_lit("Unknown1");
|
||||
case COFF_Reloc_Arm_Unknown2: return str8_lit("Unknown2");
|
||||
case COFF_Reloc_Arm_Unknown3: return str8_lit("Unknown3");
|
||||
case COFF_Reloc_Arm_Unknown4: return str8_lit("Unknown4");
|
||||
case COFF_Reloc_Arm_Unknown5: return str8_lit("Unknown5");
|
||||
case COFF_Reloc_Arm_Rel32: return str8_lit("Rel32");
|
||||
case COFF_Reloc_Arm_Section: return str8_lit("Section");
|
||||
case COFF_Reloc_Arm_SecRel: return str8_lit("SecRel");
|
||||
case COFF_Reloc_Arm_Mov32: return str8_lit("Mov32");
|
||||
case COFF_Reloc_Arm_ThumbMov32: return str8_lit("ThumbMov32");
|
||||
case COFF_Reloc_Arm_ThumbBranch20: return str8_lit("ThumbBranch20");
|
||||
case COFF_Reloc_Arm_Unused: return str8_lit("Unused");
|
||||
case COFF_Reloc_Arm_ThumbBranch24: return str8_lit("ThumbBranch24");
|
||||
case COFF_Reloc_Arm_ThumbBlx23: return str8_lit("ThumbBlx23");
|
||||
case COFF_Reloc_Arm_Pair: return str8_lit("Pair");
|
||||
}
|
||||
return str8_zero();
|
||||
}
|
||||
|
||||
internal String8
|
||||
coff_string_from_reloc_arm64(COFF_Reloc_Arm64 x)
|
||||
{
|
||||
switch (x) {
|
||||
case COFF_Reloc_Arm64_Abs: return str8_lit("Abs");
|
||||
case COFF_Reloc_Arm64_Addr32: return str8_lit("Addr32");
|
||||
case COFF_Reloc_Arm64_Addr32Nb: return str8_lit("Addr32Nb");
|
||||
case COFF_Reloc_Arm64_Branch26: return str8_lit("Branch26");
|
||||
case COFF_Reloc_Arm64_PageBaseRel21: return str8_lit("PageBaseRel21");
|
||||
case COFF_Reloc_Arm64_Rel21: return str8_lit("Rel21");
|
||||
case COFF_Reloc_Arm64_PageOffset12a: return str8_lit("PageOffset12a");
|
||||
case COFF_Reloc_Arm64_SecRel: return str8_lit("SecRel");
|
||||
case COFF_Reloc_Arm64_SecRelLow12a: return str8_lit("SecRelLow12a");
|
||||
case COFF_Reloc_Arm64_SecRelHigh12a: return str8_lit("SecRelHigh12a");
|
||||
case COFF_Reloc_Arm64_SecRelLow12l: return str8_lit("SecRelLow12l");
|
||||
case COFF_Reloc_Arm64_Token: return str8_lit("Token");
|
||||
case COFF_Reloc_Arm64_Section: return str8_lit("Section");
|
||||
case COFF_Reloc_Arm64_Addr64: return str8_lit("Addr64");
|
||||
case COFF_Reloc_Arm64_Branch19: return str8_lit("Branch19");
|
||||
case COFF_Reloc_Arm64_Branch14: return str8_lit("Branch14");
|
||||
case COFF_Reloc_Arm64_Rel32: return str8_lit("Rel32");
|
||||
}
|
||||
return str8_zero();
|
||||
}
|
||||
|
||||
internal String8
|
||||
coff_string_from_reloc(COFF_MachineType machine, COFF_RelocType x)
|
||||
{
|
||||
switch (machine) {
|
||||
case COFF_MachineType_X86: return coff_string_from_reloc_x86(x);
|
||||
case COFF_MachineType_X64: return coff_string_from_reloc_x64(x);
|
||||
case COFF_MachineType_Arm: return coff_string_from_reloc_arm(x);
|
||||
case COFF_MachineType_Arm64: return coff_string_from_reloc_arm64(x);
|
||||
}
|
||||
return str8_zero();
|
||||
}
|
||||
|
||||
internal COFF_MachineType
|
||||
coff_machine_from_string(String8 string)
|
||||
{
|
||||
for (U64 i = 0; i < ArrayCount(g_coff_machine_map); ++i) {
|
||||
if (str8_match(g_coff_machine_map[i].string, string, StringMatchFlag_CaseInsensitive)) {
|
||||
return g_coff_machine_map[i].machine;
|
||||
}
|
||||
}
|
||||
return COFF_MachineType_Unknown;
|
||||
}
|
||||
|
||||
internal COFF_ImportType
|
||||
coff_import_header_type_from_string(String8 name)
|
||||
{
|
||||
for (U64 i = 0; i < ArrayCount(g_coff_import_header_type_map); ++i) {
|
||||
if (str8_match(str8_cstring(g_coff_import_header_type_map[i].name), name, StringMatchFlag_CaseInsensitive)) {
|
||||
return g_coff_import_header_type_map[i].type;
|
||||
}
|
||||
}
|
||||
return COFF_ImportType_Invalid;
|
||||
}
|
||||
|
||||
|
||||
+76
-26
@@ -21,6 +21,7 @@ read_only global U8 g_coff_thin_archive_sig[8] = "!<thin>\n";
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
#define COFF_TimeStamp_Max max_U32
|
||||
typedef U32 COFF_TimeStamp;
|
||||
|
||||
typedef U16 COFF_FileHeaderFlags;
|
||||
@@ -102,6 +103,7 @@ typedef struct COFF_BigObjHeader
|
||||
typedef U32 COFF_SectionAlign;
|
||||
enum
|
||||
{
|
||||
COFF_SectionAlign_None = 0x0,
|
||||
COFF_SectionAlign_1Bytes = 0x1,
|
||||
COFF_SectionAlign_2Bytes = 0x2,
|
||||
COFF_SectionAlign_4Bytes = 0x3,
|
||||
@@ -135,6 +137,20 @@ enum
|
||||
COFF_SectionFlag_MemPreload = (1 << 19),
|
||||
COFF_SectionFlag_AlignShift = 20,
|
||||
COFF_SectionFlag_AlignMask = 0xf,
|
||||
COFF_SectionFlag_Align1Bytes = (COFF_SectionAlign_1Bytes << COFF_SectionFlag_AlignShift),
|
||||
COFF_SectionFlag_Align2Bytes = (COFF_SectionAlign_2Bytes << COFF_SectionFlag_AlignShift),
|
||||
COFF_SectionFlag_Align4Bytes = (COFF_SectionAlign_4Bytes << COFF_SectionFlag_AlignShift),
|
||||
COFF_SectionFlag_Align8Bytes = (COFF_SectionAlign_8Bytes << COFF_SectionFlag_AlignShift),
|
||||
COFF_SectionFlag_Align16Bytes = (COFF_SectionAlign_16Bytes << COFF_SectionFlag_AlignShift),
|
||||
COFF_SectionFlag_Align32Bytes = (COFF_SectionAlign_32Bytes << COFF_SectionFlag_AlignShift),
|
||||
COFF_SectionFlag_Align64Bytes = (COFF_SectionAlign_64Bytes << COFF_SectionFlag_AlignShift),
|
||||
COFF_SectionFlag_Align128Bytes = (COFF_SectionAlign_128Bytes << COFF_SectionFlag_AlignShift),
|
||||
COFF_SectionFlag_Align256Bytes = (COFF_SectionAlign_256Bytes << COFF_SectionFlag_AlignShift),
|
||||
COFF_SectionFlag_Align512Bytes = (COFF_SectionAlign_512Bytes << COFF_SectionFlag_AlignShift),
|
||||
COFF_SectionFlag_Align1024Bytes = (COFF_SectionAlign_1024Bytes << COFF_SectionFlag_AlignShift),
|
||||
COFF_SectionFlag_Align2048Bytes = (COFF_SectionAlign_2048Bytes << COFF_SectionFlag_AlignShift),
|
||||
COFF_SectionFlag_Align4096Bytes = (COFF_SectionAlign_4096Bytes << COFF_SectionFlag_AlignShift),
|
||||
COFF_SectionFlag_Align8192Bytes = (COFF_SectionAlign_8192Bytes << COFF_SectionFlag_AlignShift),
|
||||
COFF_SectionFlag_LnkNRelocOvfl = (1 << 24),
|
||||
COFF_SectionFlag_MemDiscardable = (1 << 25),
|
||||
COFF_SectionFlag_MemNotCached = (1 << 26),
|
||||
@@ -275,15 +291,13 @@ typedef struct COFF_Symbol32
|
||||
U8 aux_symbol_count;
|
||||
} COFF_Symbol32;
|
||||
|
||||
// Auxilary symbols are allocated with fixed size so that symbol table could be maintaned as array of regular size.
|
||||
#define COFF_AuxSymbolSize 18
|
||||
|
||||
typedef U32 COFF_WeakExtType;
|
||||
enum
|
||||
{
|
||||
COFF_WeakExt_NoLibrary = 1,
|
||||
COFF_WeakExt_SearchLibrary = 2,
|
||||
COFF_WeakExt_SearchAlias = 3
|
||||
COFF_WeakExt_NoLibrary = 1,
|
||||
COFF_WeakExt_SearchLibrary = 2,
|
||||
COFF_WeakExt_SearchAlias = 3,
|
||||
COFF_WeakExt_AntiDependency = 4, // default symbol must not reference a weak symbol
|
||||
};
|
||||
|
||||
// storage class: External
|
||||
@@ -352,23 +366,25 @@ typedef U16 COFF_RelocType;
|
||||
typedef COFF_RelocType COFF_Reloc_X64;
|
||||
enum
|
||||
{
|
||||
COFF_Reloc_X64_Abs = 0x0,
|
||||
COFF_Reloc_X64_Addr64 = 0x1,
|
||||
COFF_Reloc_X64_Addr32 = 0x2,
|
||||
COFF_Reloc_X64_Addr32Nb = 0x3, // NB => No Base
|
||||
COFF_Reloc_X64_Rel32 = 0x4,
|
||||
COFF_Reloc_X64_Rel32_1 = 0x5,
|
||||
COFF_Reloc_X64_Rel32_2 = 0x6,
|
||||
COFF_Reloc_X64_Rel32_3 = 0x7,
|
||||
COFF_Reloc_X64_Rel32_4 = 0x8,
|
||||
COFF_Reloc_X64_Rel32_5 = 0x9,
|
||||
COFF_Reloc_X64_Section = 0xA,
|
||||
COFF_Reloc_X64_SecRel = 0xB,
|
||||
COFF_Reloc_X64_SecRel7 = 0xC, // TODO(nick): MSDN doesn't specify size for CLR token
|
||||
COFF_Reloc_X64_Token = 0xD,
|
||||
COFF_Reloc_X64_SRel32 = 0xE, // TODO(nick): MSDN doesn't specify size for PAIR
|
||||
COFF_Reloc_X64_Pair = 0xF,
|
||||
COFF_Reloc_X64_SSpan32 = 0x10
|
||||
COFF_Reloc_X64_Abs = 0x0,
|
||||
COFF_Reloc_X64_Addr64 = 0x1,
|
||||
COFF_Reloc_X64_Addr32 = 0x2,
|
||||
COFF_Reloc_X64_Addr32Nb = 0x3, // NB => No Base
|
||||
COFF_Reloc_X64_Rel32 = 0x4,
|
||||
COFF_Reloc_X64_Rel32_1 = 0x5,
|
||||
COFF_Reloc_X64_Rel32_2 = 0x6,
|
||||
COFF_Reloc_X64_Rel32_3 = 0x7,
|
||||
COFF_Reloc_X64_Rel32_4 = 0x8,
|
||||
COFF_Reloc_X64_Rel32_5 = 0x9,
|
||||
COFF_Reloc_X64_Section = 0xA,
|
||||
COFF_Reloc_X64_SecRel = 0xB,
|
||||
COFF_Reloc_X64_SecRel7 = 0xC, // TODO(nick): MSDN doesn't specify size for CLR token
|
||||
COFF_Reloc_X64_Token = 0xD,
|
||||
COFF_Reloc_X64_SRel32 = 0xE, // TODO(nick): MSDN doesn't specify size for PAIR
|
||||
COFF_Reloc_X64_Pair = 0xF,
|
||||
COFF_Reloc_X64_SSpan32 = 0x10,
|
||||
COFF_Reloc_X64_Unknown_11 = 0x11,
|
||||
COFF_Reloc_X64_Last = COFF_Reloc_X64_Unknown_11,
|
||||
};
|
||||
|
||||
typedef COFF_RelocType COFF_Reloc_X86;
|
||||
@@ -561,6 +577,12 @@ typedef struct COFF_ImportHeader
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
typedef struct COFF_RelocValue
|
||||
{
|
||||
U64 size;
|
||||
S64 value;
|
||||
} COFF_RelocValue;
|
||||
|
||||
////////////////////////////////
|
||||
// Section
|
||||
|
||||
@@ -581,19 +603,24 @@ internal String8 coff_read_symbol_name(String8 string_table, COFF_SymbolName *na
|
||||
internal U64 coff_apply_size_from_reloc_x64(COFF_Reloc_X64 x);
|
||||
internal U64 coff_apply_size_from_reloc_x86(COFF_Reloc_X86 x);
|
||||
|
||||
internal COFF_RelocValue coff_pick_reloc_value_x64(COFF_Reloc_X64 type, U64 image_base, U64 reloc_virtual_offset, U32 symbol_section_number, U32 symbol_section_offset, S64 symbol_virtual_offset);
|
||||
|
||||
////////////////////////////////
|
||||
// Import
|
||||
|
||||
internal U32 coff_make_ordinal32(U16 hint);
|
||||
internal U64 coff_make_ordinal64(U16 hint);
|
||||
internal String8 coff_ordinal_data_from_hint(Arena *arena, COFF_MachineType machine, U16 hint);
|
||||
|
||||
internal String8 coff_make_import_lookup (Arena *arena, U16 hint, String8 name);
|
||||
internal String8 coff_make_import_header_by_name (Arena *arena, String8 dll_name, COFF_MachineType machine, COFF_TimeStamp time_stamp, String8 name, U16 hint, COFF_ImportType type);
|
||||
internal String8 coff_make_import_header_by_ordinal(Arena *arena, String8 dll_name, COFF_MachineType machine, COFF_TimeStamp time_stamp, U16 ordinal, COFF_ImportType type);
|
||||
internal String8 coff_make_lib_member_header(Arena *arena, String8 name, COFF_TimeStamp time_stamp, U16 user_id, U16 group_id, U16 mode, U32 size);
|
||||
internal String8 coff_make_import_lookup(Arena *arena, U16 hint, String8 name);
|
||||
internal String8 coff_make_import_header(Arena *arena, COFF_MachineType machine, COFF_TimeStamp time_stamp, String8 dll_name, COFF_ImportByType import_by, String8 name, U16 hint_or_ordinal, COFF_ImportType type);
|
||||
|
||||
////////////////////////////////
|
||||
// Misc
|
||||
|
||||
internal U16 coff_default_align_from_machine (COFF_MachineType machine);
|
||||
internal U8 coff_code_align_byte_from_machine (COFF_MachineType machine);
|
||||
internal U64 coff_word_size_from_machine (COFF_MachineType machine);
|
||||
internal U64 coff_default_exe_base_from_machine(COFF_MachineType machine);
|
||||
internal U64 coff_default_dll_base_from_machine(COFF_MachineType machine);
|
||||
@@ -601,4 +628,27 @@ internal U64 coff_default_dll_base_from_machine(COFF_MachineType machine);
|
||||
internal Arch arch_from_coff_machine(COFF_MachineType machine);
|
||||
internal U64 coff_foff_from_voff(COFF_SectionHeader *sections, U64 section_count, U64 voff);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Enum <=> String
|
||||
|
||||
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_resource_memory_flags(Arena *arena, COFF_ResourceMemoryFlags 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_H
|
||||
|
||||
@@ -0,0 +1,819 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#if 0
|
||||
internal void
|
||||
coff_print_archive_member_header(Arena *arena, String8List *out, String8 indent, COFF_ParsedArchiveMemberHeader header, String8 long_names)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
String8 time_stamp = coff_string_from_time_stamp(scratch.arena, header.time_stamp);
|
||||
|
||||
rd_printf("Name : %S" , header.name );
|
||||
rd_printf("Time Stamp: (%#x) %S" , header.time_stamp, time_stamp );
|
||||
rd_printf("User ID : %u" , header.user_id );
|
||||
rd_printf("Group ID : %u" , header.group_id);
|
||||
rd_printf("Mode : %S" , header.mode );
|
||||
rd_printf("Data : [%#llx-%#llx)", header.data_range.min, header.data_range.max);
|
||||
|
||||
scratch_end(scratch);
|
||||
}
|
||||
|
||||
internal void
|
||||
coff_print_section_table(Arena *arena,
|
||||
String8List *out,
|
||||
String8 indent,
|
||||
String8 string_table,
|
||||
COFF_Symbol32Array symbol_table,
|
||||
U64 section_count,
|
||||
COFF_SectionHeader *section_table)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
|
||||
String8 *symlinks = push_array(scratch.arena, String8, section_count);
|
||||
for (U64 i = 0; i < symbol_table.count; ++i) {
|
||||
COFF_Symbol32 *symbol = symbol_table.v+i;
|
||||
COFF_SymbolValueInterpType interp = coff_interp_symbol(symbol->section_number, symbol->value, symbol->storage_class);
|
||||
if (interp == COFF_SymbolValueInterp_Regular &&
|
||||
symbol->aux_symbol_count == 0 &&
|
||||
(symbol->storage_class == COFF_SymStorageClass_External || symbol->storage_class == COFF_SymStorageClass_Static)) {
|
||||
if (symbol->section_number > 0 && symbol->section_number <= symbol_table.count) {
|
||||
COFF_SectionHeader *header = section_table+(symbol->section_number-1);
|
||||
if (header->flags & COFF_SectionFlag_LnkCOMDAT) {
|
||||
symlinks[symbol->section_number-1] = coff_read_symbol_name(string_table, &symbol->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
i += symbol->aux_symbol_count;
|
||||
}
|
||||
|
||||
if (section_count) {
|
||||
rd_printf("# Section Table");
|
||||
rd_indent();
|
||||
|
||||
rd_printf("%-4s %-8s %-8s %-8s %-8s %-8s %-8s %-8s %-8s %-8s %-5s %-10s %s",
|
||||
"No.",
|
||||
"Name",
|
||||
"VirtSize",
|
||||
"VirtOff",
|
||||
"FileSize",
|
||||
"FileOff",
|
||||
"RelocOff",
|
||||
"LinesOff",
|
||||
"RelocCnt",
|
||||
"LineCnt",
|
||||
"Align",
|
||||
"Flags",
|
||||
"Symlink");
|
||||
|
||||
for (U64 i = 0; i < section_count; ++i) {
|
||||
COFF_SectionHeader *header = section_table+i;
|
||||
|
||||
String8 name = str8_cstring_capped(header->name, header->name+sizeof(header->name));
|
||||
String8 full_name = coff_name_from_section_header(string_table, header);
|
||||
|
||||
String8 align;
|
||||
{
|
||||
U64 align_size = coff_align_size_from_section_flags(header->flags);
|
||||
align = push_str8f(scratch.arena, "%u", align_size);
|
||||
}
|
||||
|
||||
String8 flags;
|
||||
{
|
||||
String8List mem_flags = {0};
|
||||
if (header->flags & COFF_SectionFlag_MemRead) {
|
||||
str8_list_pushf(scratch.arena, &mem_flags, "r");
|
||||
}
|
||||
if (header->flags & COFF_SectionFlag_MemWrite) {
|
||||
str8_list_pushf(scratch.arena, &mem_flags, "w");
|
||||
}
|
||||
if (header->flags & COFF_SectionFlag_MemExecute) {
|
||||
str8_list_pushf(scratch.arena, &mem_flags, "x");
|
||||
}
|
||||
|
||||
String8List cnt_flags = {0};
|
||||
if (header->flags & COFF_SectionFlag_CntCode) {
|
||||
str8_list_pushf(scratch.arena, &cnt_flags, "c");
|
||||
}
|
||||
if (header->flags & COFF_SectionFlag_CntInitializedData) {
|
||||
str8_list_pushf(scratch.arena, &cnt_flags, "d");
|
||||
}
|
||||
if (header->flags & COFF_SectionFlag_CntUninitializedData) {
|
||||
str8_list_pushf(scratch.arena, &cnt_flags, "u");
|
||||
}
|
||||
|
||||
String8List mem_extra_flags = {0};
|
||||
if (header->flags & COFF_SectionFlag_MemShared) {
|
||||
str8_list_pushf(scratch.arena, &mem_flags, "s");
|
||||
}
|
||||
if (header->flags & COFF_SectionFlag_Mem16Bit) {
|
||||
str8_list_pushf(scratch.arena, &mem_extra_flags, "h");
|
||||
}
|
||||
if (header->flags & COFF_SectionFlag_MemLocked) {
|
||||
str8_list_pushf(scratch.arena, &mem_extra_flags, "l");
|
||||
}
|
||||
if (header->flags & COFF_SectionFlag_MemDiscardable) {
|
||||
str8_list_pushf(scratch.arena, &mem_extra_flags, "d");
|
||||
}
|
||||
if (header->flags & COFF_SectionFlag_MemNotCached) {
|
||||
str8_list_pushf(scratch.arena, &mem_extra_flags, "c");
|
||||
}
|
||||
if (header->flags & COFF_SectionFlag_MemNotPaged) {
|
||||
str8_list_pushf(scratch.arena, &mem_extra_flags, "p");
|
||||
}
|
||||
|
||||
String8List lnk_flags = {0};
|
||||
if (header->flags & COFF_SectionFlag_LnkRemove) {
|
||||
str8_list_pushf(scratch.arena, &lnk_flags, "r");
|
||||
}
|
||||
if (header->flags & COFF_SectionFlag_LnkCOMDAT) {
|
||||
str8_list_pushf(scratch.arena, &lnk_flags, "c");
|
||||
}
|
||||
if (header->flags & COFF_SectionFlag_LnkOther) {
|
||||
str8_list_pushf(scratch.arena, &lnk_flags, "o");
|
||||
}
|
||||
if (header->flags & COFF_SectionFlag_LnkInfo) {
|
||||
str8_list_pushf(scratch.arena, &lnk_flags, "i");
|
||||
}
|
||||
if (header->flags & COFF_SectionFlag_LnkNRelocOvfl) {
|
||||
str8_list_pushf(scratch.arena, &lnk_flags, "f");
|
||||
}
|
||||
|
||||
String8List other_flags = {0};
|
||||
if (header->flags & COFF_SectionFlag_TypeNoPad) {
|
||||
str8_list_pushf(scratch.arena, &other_flags, "n");
|
||||
}
|
||||
if (header->flags & COFF_SectionFlag_GpRel) {
|
||||
str8_list_pushf(scratch.arena, &other_flags, "g");
|
||||
}
|
||||
|
||||
String8 mem = str8_list_join(scratch.arena, &mem_flags, 0);
|
||||
String8 cnt = str8_list_join(scratch.arena, &cnt_flags, 0);
|
||||
String8 lnk = str8_list_join(scratch.arena, &lnk_flags, 0);
|
||||
String8 ext = str8_list_join(scratch.arena, &mem_extra_flags, 0);
|
||||
String8 oth = str8_list_join(scratch.arena, &other_flags, 0);
|
||||
|
||||
String8List f = {0};
|
||||
str8_list_push(scratch.arena, &f, mem);
|
||||
str8_list_push(scratch.arena, &f, cnt);
|
||||
str8_list_push(scratch.arena, &f, ext);
|
||||
str8_list_push(scratch.arena, &f, lnk);
|
||||
str8_list_push(scratch.arena, &f, oth);
|
||||
|
||||
flags = str8_list_join(scratch.arena, &f, &(StringJoin){ .sep = str8_lit("-") });
|
||||
|
||||
if (!flags.size) {
|
||||
flags = str8_lit("none");
|
||||
}
|
||||
}
|
||||
|
||||
String8List l = {0};
|
||||
str8_list_pushf(scratch.arena, &l, "%-4x", i+1 );
|
||||
str8_list_pushf(scratch.arena, &l, "%-8S", name );
|
||||
str8_list_pushf(scratch.arena, &l, "%08x", header->vsize );
|
||||
str8_list_pushf(scratch.arena, &l, "%08x", header->voff );
|
||||
str8_list_pushf(scratch.arena, &l, "%08x", header->fsize );
|
||||
str8_list_pushf(scratch.arena, &l, "%08x", header->foff );
|
||||
str8_list_pushf(scratch.arena, &l, "%08x", header->relocs_foff);
|
||||
str8_list_pushf(scratch.arena, &l, "%08x", header->lines_foff );
|
||||
str8_list_pushf(scratch.arena, &l, "%08x", header->reloc_count);
|
||||
str8_list_pushf(scratch.arena, &l, "%08x", header->line_count );
|
||||
str8_list_pushf(scratch.arena, &l, "%-5S", align );
|
||||
str8_list_pushf(scratch.arena, &l, "%-10S", flags );
|
||||
if (symlinks[i].size > 0) {
|
||||
str8_list_pushf(scratch.arena, &l, "%S", symlinks[i]);
|
||||
} else {
|
||||
str8_list_pushf(scratch.arena, &l, "[no symlink]");
|
||||
}
|
||||
|
||||
String8 line = str8_list_join(scratch.arena, &l, &(StringJoin){ .sep = str8_lit(" "), });
|
||||
rd_printf("%S", line);
|
||||
|
||||
if (full_name.size != name.size) {
|
||||
rd_indent();
|
||||
rd_printf("Full Name: %S", full_name);
|
||||
rd_unindent();
|
||||
}
|
||||
}
|
||||
|
||||
rd_newline();
|
||||
rd_printf("Flags:");
|
||||
rd_indent();
|
||||
rd_printf("r = MemRead w = MemWrite x = MemExecute");
|
||||
rd_printf("c = CntCode d = InitializedData u = UninitializedData");
|
||||
rd_printf("s = MemShared h = Mem16bit l = MemLocked d = MemDiscardable c = MemNotCached p = MemNotPaged");
|
||||
rd_printf("r = LnkRemove c = LnkComdat o = LnkOther i = LnkInfo f = LnkNRelocOvfl");
|
||||
rd_printf("g = GpRel n = TypeNoPad");
|
||||
rd_unindent();
|
||||
|
||||
rd_unindent();
|
||||
rd_newline();
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
}
|
||||
|
||||
internal void
|
||||
coff_disasm_sections(Arena *arena,
|
||||
String8List *out,
|
||||
String8 indent,
|
||||
String8 raw_data,
|
||||
COFF_MachineType machine,
|
||||
U64 image_base,
|
||||
B32 is_obj,
|
||||
RD_MarkerArray *section_markers,
|
||||
U64 section_count,
|
||||
COFF_SectionHeader *sections)
|
||||
{
|
||||
if (section_count) {
|
||||
for (U64 sect_idx = 0; sect_idx < section_count; ++sect_idx) {
|
||||
COFF_SectionHeader *sect = sections+sect_idx;
|
||||
if (sect->flags & COFF_SectionFlag_CntCode) {
|
||||
U64 sect_off = is_obj ? sect->foff : sect->voff;
|
||||
U64 sect_size = is_obj ? sect->fsize : sect->vsize;
|
||||
String8 raw_code = str8_substr(raw_data, rng_1u64(sect->foff, sect->foff+sect_size));
|
||||
U64 sect_number = sect_idx+1;
|
||||
RD_MarkerArray markers = section_markers[sect_number];
|
||||
|
||||
rd_printf("# Disassembly [Section No. %#llx]", sect_number);
|
||||
rd_indent();
|
||||
rd_print_disasm(arena, out, indent, arch_from_coff_machine(machine), image_base, sect_off, markers.count, markers.v, raw_code);
|
||||
rd_unindent();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal void
|
||||
coff_raw_data_sections(Arena *arena,
|
||||
String8List *out,
|
||||
String8 indent,
|
||||
String8 raw_data,
|
||||
B32 is_obj,
|
||||
RD_MarkerArray *section_markers,
|
||||
U64 section_count,
|
||||
COFF_SectionHeader *section_table)
|
||||
{
|
||||
if (section_count) {
|
||||
for (U64 sect_idx = 0; sect_idx < section_count; ++sect_idx) {
|
||||
COFF_SectionHeader *sect = section_table+sect_idx;
|
||||
if (sect->fsize > 0) {
|
||||
U64 sect_size = is_obj ? sect->fsize : sect->vsize;
|
||||
String8 raw_sect = str8_substr(raw_data, rng_1u64(sect->foff, sect->foff+sect_size));
|
||||
RD_MarkerArray markers = section_markers[sect_idx];
|
||||
|
||||
rd_printf("# Raw Data [Section No. %#llx]", (sect_idx+1));
|
||||
rd_indent();
|
||||
rd_print_raw_data(arena, out, indent, 32, markers.count, markers.v, raw_sect);
|
||||
rd_unindent();
|
||||
rd_newline();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal void
|
||||
coff_print_relocs(Arena *arena,
|
||||
String8List *out,
|
||||
String8 indent,
|
||||
String8 raw_data,
|
||||
String8 string_table,
|
||||
COFF_MachineType machine,
|
||||
U64 sect_count,
|
||||
COFF_SectionHeader *sect_headers,
|
||||
COFF_Symbol32Array symbols)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
|
||||
B32 print_header = 1;
|
||||
|
||||
for (U64 sect_idx = 0; sect_idx < sect_count; ++sect_idx) {
|
||||
COFF_SectionHeader *sect_header = sect_headers+sect_idx;
|
||||
COFF_RelocInfo reloc_info = coff_reloc_info_from_section_header(raw_data, sect_header);
|
||||
|
||||
if (reloc_info.count) {
|
||||
if (print_header) {
|
||||
print_header = 0;
|
||||
rd_printf("# Relocations");
|
||||
rd_indent();
|
||||
}
|
||||
|
||||
rd_printf("## Section %llx", sect_idx);
|
||||
rd_indent();
|
||||
|
||||
rd_printf("%-4s %-8s %-16s %-16s %-8s %-7s", "No.", "Offset", "Type", "ApplyTo", "SymIdx", "SymName");
|
||||
|
||||
for (U64 reloc_idx = 0; reloc_idx < reloc_info.count; ++reloc_idx) {
|
||||
COFF_Reloc *reloc = (COFF_Reloc*)(raw_data.str + reloc_info.array_off) + reloc_idx;
|
||||
String8 type = coff_string_from_reloc(machine, reloc->type);
|
||||
U64 apply_size = coff_apply_size_from_reloc(machine, reloc->type);
|
||||
|
||||
U64 apply_foff = sect_header->foff + reloc->apply_off;
|
||||
if (apply_foff + apply_size > raw_data.size) {
|
||||
rd_errorf("out of bounds apply file offset %#llx in relocation %#llx", apply_foff, reloc_idx);
|
||||
break;
|
||||
}
|
||||
|
||||
U64 raw_apply;
|
||||
AssertAlways(apply_size <= sizeof(raw_apply));
|
||||
MemoryCopy(&raw_apply, raw_data.str + apply_foff, apply_size);
|
||||
S64 apply = extend_sign64(raw_apply, apply_size);
|
||||
|
||||
if (reloc->isymbol > symbols.count) {
|
||||
rd_errorf("out of bounds symbol index %u in relocation %#llx", reloc->isymbol, reloc_idx);
|
||||
break;
|
||||
}
|
||||
|
||||
COFF_Symbol32 *symbol = symbols.v+reloc->isymbol;
|
||||
String8 symbol_name = coff_read_symbol_name(string_table, &symbol->name);
|
||||
|
||||
String8List line = {0};
|
||||
str8_list_pushf(scratch.arena, &line, "%-4x", reloc_idx );
|
||||
str8_list_pushf(scratch.arena, &line, "%08x", reloc->apply_off);
|
||||
str8_list_pushf(scratch.arena, &line, "%-16S", type );
|
||||
str8_list_pushf(scratch.arena, &line, "%016x", apply );
|
||||
str8_list_pushf(scratch.arena, &line, "%S", symbol_name );
|
||||
|
||||
String8 l = str8_list_join(scratch.arena, &line, &(StringJoin){.sep=str8_lit(" ")});
|
||||
rd_printf("%S", l);
|
||||
}
|
||||
|
||||
rd_unindent();
|
||||
}
|
||||
}
|
||||
|
||||
if (!print_header) {
|
||||
rd_unindent();
|
||||
}
|
||||
rd_newline();
|
||||
|
||||
scratch_end(scratch);
|
||||
}
|
||||
|
||||
internal void
|
||||
coff_print_symbol_table(Arena *arena,
|
||||
String8List *out,
|
||||
String8 indent,
|
||||
String8 raw_data,
|
||||
B32 is_big_obj,
|
||||
String8 string_table,
|
||||
COFF_Symbol32Array symbols)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
|
||||
if (symbols.count) {
|
||||
rd_printf("# Symbol Table");
|
||||
rd_indent();
|
||||
|
||||
rd_printf("%-4s %-8s %-10s %-4s %-4s %-4s %-16s %-20s",
|
||||
"No.", "Value", "SectNum", "Aux", "Msb", "Lsb", "Storage", "Name");
|
||||
|
||||
for (U64 i = 0; i < symbols.count; ++i) {
|
||||
COFF_Symbol32 *symbol = &symbols.v[i];
|
||||
String8 name = coff_read_symbol_name(string_table, &symbol->name);
|
||||
String8 msb = coff_string_from_sym_dtype(symbol->type.u.msb);
|
||||
String8 lsb = coff_string_from_sym_type(symbol->type.u.lsb);
|
||||
String8 storage_class = coff_string_from_sym_storage_class(symbol->storage_class);
|
||||
String8 section_number;
|
||||
switch (symbol->section_number) {
|
||||
case COFF_Symbol_UndefinedSection: section_number = str8_lit("Undef"); break;
|
||||
case COFF_Symbol_AbsSection32: section_number = str8_lit("Abs"); break;
|
||||
case COFF_Symbol_DebugSection32: section_number = str8_lit("Debug"); break;
|
||||
default: section_number = push_str8f(scratch.arena, "%010x", symbol->section_number); break;
|
||||
}
|
||||
|
||||
String8List line = {0};
|
||||
str8_list_pushf(scratch.arena, &line, "%-4x", i );
|
||||
str8_list_pushf(scratch.arena, &line, "%08x", symbol->value );
|
||||
str8_list_pushf(scratch.arena, &line, "%-10S", section_number );
|
||||
str8_list_pushf(scratch.arena, &line, "%-4u", symbol->aux_symbol_count);
|
||||
str8_list_pushf(scratch.arena, &line, "%-4S", msb );
|
||||
str8_list_pushf(scratch.arena, &line, "%-4S", lsb );
|
||||
str8_list_pushf(scratch.arena, &line, "%-16S", storage_class );
|
||||
str8_list_pushf(scratch.arena, &line, "%S", name );
|
||||
|
||||
String8 l = str8_list_join(scratch.arena, &line, &(StringJoin){.sep = str8_lit(" ")});
|
||||
rd_printf("%S", l);
|
||||
|
||||
rd_indent();
|
||||
for (U64 k=i+1, c = i+symbol->aux_symbol_count; k <= c; ++k) {
|
||||
void *raw_aux = &symbols.v[k];
|
||||
switch (symbol->storage_class) {
|
||||
case COFF_SymStorageClass_External: {
|
||||
COFF_SymbolFuncDef *func_def = (COFF_SymbolFuncDef*)&symbols.v[k];
|
||||
rd_printf("Tag Index %#x, Total Size %#x, Line Numbers %#x, Next Function %#x",
|
||||
func_def->tag_index, func_def->total_size, func_def->ptr_to_ln, func_def->ptr_to_next_func);
|
||||
} break;
|
||||
case COFF_SymStorageClass_Function: {
|
||||
COFF_SymbolFunc *func = raw_aux;
|
||||
rd_printf("Ordinal Line Number %#x, Next Function %#x", func->ln, func->ptr_to_next_func);
|
||||
} break;
|
||||
case COFF_SymStorageClass_WeakExternal: {
|
||||
COFF_SymbolWeakExt *weak = raw_aux;
|
||||
String8 type = coff_string_from_weak_ext_type(weak->characteristics);
|
||||
rd_printf("Tag Index %#x, Characteristics %S", weak->tag_index, type);
|
||||
} break;
|
||||
case COFF_SymStorageClass_File: {
|
||||
COFF_SymbolFile *file = raw_aux;
|
||||
String8 name = str8_cstring_capped(file->name, file->name+sizeof(file->name));
|
||||
rd_printf("Name %S", name);
|
||||
} break;
|
||||
case COFF_SymStorageClass_Static: {
|
||||
COFF_SymbolSecDef *sd = raw_aux;
|
||||
String8 selection = coff_string_from_comdat_select_type(sd->selection);
|
||||
U32 number = sd->number_lo;
|
||||
if (is_big_obj) {
|
||||
number |= (U32)sd->number_hi << 16;
|
||||
}
|
||||
if (number) {
|
||||
rd_printf("Length %x, Reloc Count %u, Line Count %u, Checksum %x, Section %x, Selection %S",
|
||||
sd->length, sd->number_of_relocations, sd->number_of_ln, sd->check_sum, number, selection);
|
||||
} else {
|
||||
rd_printf("Length %x, Reloc Count %u, Line Count %u, Checksum %x",
|
||||
sd->length, sd->number_of_relocations, sd->number_of_ln, sd->check_sum);
|
||||
}
|
||||
} break;
|
||||
default: {
|
||||
rd_printf("???");
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
i += symbol->aux_symbol_count;
|
||||
rd_unindent();
|
||||
}
|
||||
|
||||
rd_unindent();
|
||||
rd_newline();
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
}
|
||||
|
||||
internal void
|
||||
coff_print_big_obj_header(Arena *arena, String8List *out, String8 indent, COFF_BigObjHeader *header)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
|
||||
String8 time_stamp = coff_string_from_time_stamp(scratch.arena, header->time_stamp);
|
||||
String8 machine = coff_string_from_machine_type(header->machine);
|
||||
|
||||
rd_printf("# Big Obj");
|
||||
rd_indent();
|
||||
rd_printf("Time Stamp : %#x (%S)", header->time_stamp, time_stamp);
|
||||
rd_printf("Machine : %#x (%S)", header->machine, machine );
|
||||
rd_printf("Section Count: %u", header->section_count );
|
||||
rd_printf("Symbol Table : %#x", header->symbol_table_foff);
|
||||
rd_printf("Symbol Count : %u", header->symbol_count );
|
||||
rd_unindent();
|
||||
|
||||
scratch_end(scratch);
|
||||
}
|
||||
|
||||
internal void
|
||||
coff_print_file_header(Arena *arena, String8List *out, String8 indent, COFF_FileHeader *header)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
|
||||
String8 time_stamp = coff_string_from_time_stamp(scratch.arena, header->time_stamp);
|
||||
String8 machine = coff_string_from_machine_type(header->machine);
|
||||
String8 flags = coff_string_from_flags(scratch.arena, header->flags);
|
||||
|
||||
rd_printf("# COFF File Header");
|
||||
rd_indent();
|
||||
rd_printf("Time Stamp : %#x (%S)", header->time_stamp, time_stamp );
|
||||
rd_printf("Machine : %#x %S", header->machine, machine );
|
||||
rd_printf("Section Count : %u", header->section_count );
|
||||
rd_printf("Symbol Table : %#x", header->symbol_table_foff );
|
||||
rd_printf("Symbol Count : %u", header->symbol_count );
|
||||
rd_printf("Optional Header Size: %#x (%m)", header->optional_header_size, header->optional_header_size);
|
||||
rd_printf("Flags : %#x (%S)", header->flags, flags );
|
||||
rd_unindent();
|
||||
|
||||
scratch_end(scratch);
|
||||
}
|
||||
|
||||
internal void
|
||||
coff_print_import(Arena *arena, String8List *out, String8 indent, COFF_ParsedArchiveImportHeader *header)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
|
||||
String8 machine = coff_string_from_machine_type(header->machine);
|
||||
String8 time_stamp = coff_string_from_time_stamp(scratch.arena, header->time_stamp);
|
||||
|
||||
rd_printf("# Import");
|
||||
rd_indent();
|
||||
rd_printf("Version : %u", header->version );
|
||||
rd_printf("Machine : %S", machine );
|
||||
rd_printf("Time Stamp: %#x (%S)", header->time_stamp, time_stamp );
|
||||
rd_printf("Data Size : %#x (%m)", header->data_size, header->data_size);
|
||||
rd_printf("Hint : %u", header->hint_or_ordinal);
|
||||
rd_printf("Type : %u", header->type );
|
||||
rd_printf("Import By : %u", header->import_by );
|
||||
rd_printf("Function : %S", header->func_name );
|
||||
rd_printf("DLL : %S", header->dll_name );
|
||||
rd_unindent();
|
||||
|
||||
scratch_end(scratch);
|
||||
}
|
||||
|
||||
internal void
|
||||
coff_print_big_obj(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Option opts)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
|
||||
COFF_FileHeaderInfo header_info = coff_file_header_info_from_data(raw_data);
|
||||
|
||||
String8 raw_header = str8_substr(raw_data, header_info.header_range);
|
||||
String8 raw_section_table = str8_substr(raw_data, header_info.section_table_range);
|
||||
String8 raw_string_table = str8_substr(raw_data, header_info.string_table_range);
|
||||
|
||||
COFF_BigObjHeader *big_obj = (COFF_BigObjHeader *)raw_header.str;
|
||||
COFF_SectionHeader *section_table = (COFF_SectionHeader *)raw_section_table.str;
|
||||
COFF_Symbol32Array symbol_table = coff_symbol_array_from_data_32(scratch.arena, raw_data, header_info.symbol_table_range.min, big_obj->symbol_count);
|
||||
|
||||
if (opts & RD_Option_Headers) {
|
||||
coff_print_big_obj_header(arena, out, indent, big_obj);
|
||||
rd_newline();
|
||||
}
|
||||
|
||||
if (opts & RD_Option_Sections) {
|
||||
Rng1U64 sect_headers_range = rng_1u64(sizeof(*big_obj), sizeof(*big_obj) + sizeof(COFF_SectionHeader)*big_obj->section_count);
|
||||
Rng1U64 symbols_range = rng_1u64(big_obj->symbol_table_foff, big_obj->symbol_table_foff + sizeof(COFF_Symbol32)*big_obj->symbol_count);
|
||||
|
||||
if (sect_headers_range.max > raw_data.size) {
|
||||
rd_errorf("not enough bytes to read big obj section headers");
|
||||
goto exit;
|
||||
}
|
||||
if (big_obj->symbol_count) {
|
||||
if (symbols_range.max > raw_data.size) {
|
||||
rd_errorf("not enough bytes to read big obj symbol table");
|
||||
goto exit;
|
||||
}
|
||||
if (contains_1u64(symbols_range, sect_headers_range.min) ||
|
||||
contains_1u64(symbols_range, sect_headers_range.max)) {
|
||||
rd_errorf("section headers and symbol table ranges overlap");
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
coff_print_section_table(arena, out, indent, raw_string_table, symbol_table, big_obj->section_count, section_table);
|
||||
rd_newline();
|
||||
}
|
||||
|
||||
if (opts & RD_Option_Relocs) {
|
||||
coff_print_relocs(arena, out, indent, raw_data, raw_string_table, big_obj->machine, big_obj->section_count, section_table, symbol_table);
|
||||
rd_newline();
|
||||
}
|
||||
|
||||
if (opts & RD_Option_Symbols) {
|
||||
coff_print_symbol_table(arena, out, indent, raw_data, 1, raw_string_table, symbol_table);
|
||||
rd_newline();
|
||||
}
|
||||
|
||||
exit:;
|
||||
scratch_end(scratch);
|
||||
}
|
||||
|
||||
internal void
|
||||
coff_print_obj(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Option opts)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
|
||||
COFF_FileHeaderInfo header_info = coff_file_header_info_from_data(raw_data);
|
||||
|
||||
String8 raw_header = str8_substr(raw_data, header_info.header_range);
|
||||
String8 raw_section_table = str8_substr(raw_data, header_info.section_table_range);
|
||||
String8 raw_string_table = str8_substr(raw_data, header_info.string_table_range);
|
||||
|
||||
COFF_FileHeader *header = (COFF_FileHeader *)raw_header.str;
|
||||
COFF_SectionHeader *section_table = (COFF_SectionHeader *)raw_section_table.str;
|
||||
COFF_Symbol32Array symbol_table = coff_symbol_array_from_data_16(scratch.arena, raw_data, header_info.symbol_table_range.min, header->symbol_count);
|
||||
Arch arch = arch_from_coff_machine(header->machine);
|
||||
|
||||
if (opts & RD_Option_Headers) {
|
||||
coff_print_file_header(arena, out, indent, header);
|
||||
rd_newline();
|
||||
}
|
||||
|
||||
if (opts & RD_Option_Sections) {
|
||||
Rng1U64 sect_headers_range = rng_1u64(sizeof(*header), sizeof(*header) + sizeof(COFF_SectionHeader)*header->section_count);
|
||||
Rng1U64 symbols_range = rng_1u64(header->symbol_table_foff, header->symbol_table_foff + sizeof(COFF_Symbol16)*header->symbol_count);
|
||||
|
||||
if (sect_headers_range.max > raw_data.size) {
|
||||
rd_errorf("not enough bytes to read obj section headers");
|
||||
goto exit;
|
||||
}
|
||||
if (header->symbol_count) {
|
||||
if (symbols_range.max > raw_data.size) {
|
||||
rd_errorf("not enough bytes to read obj symbol table");
|
||||
goto exit;
|
||||
}
|
||||
if (contains_1u64(symbols_range, sect_headers_range.min) ||
|
||||
contains_1u64(symbols_range, sect_headers_range.max)) {
|
||||
rd_errorf("section headers and symbol table ranges overlap");
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
coff_print_section_table(arena, out, indent, raw_string_table, symbol_table, header->section_count, section_table);
|
||||
rd_newline();
|
||||
}
|
||||
|
||||
if (opts & RD_Option_Relocs) {
|
||||
coff_print_relocs(arena, out, indent, raw_data, raw_string_table, header->machine, header->section_count, section_table, symbol_table);
|
||||
rd_newline();
|
||||
}
|
||||
|
||||
if (opts & RD_Option_Symbols) {
|
||||
coff_print_symbol_table(arena, out, indent, raw_data, 0, raw_string_table, symbol_table);
|
||||
rd_newline();
|
||||
}
|
||||
|
||||
RD_MarkerArray *section_markers = 0;
|
||||
if (opts & (RD_Option_Disasm|RD_Option_Rawdata)) {
|
||||
section_markers = rd_section_markers_from_coff_symbol_table(scratch.arena, raw_string_table, header->section_count, symbol_table);
|
||||
}
|
||||
|
||||
if (opts & RD_Option_Rawdata) {
|
||||
coff_raw_data_sections(arena, out, indent, raw_data, 1, section_markers, header->section_count, section_table);
|
||||
}
|
||||
|
||||
if (opts & RD_Option_Disasm) {
|
||||
coff_disasm_sections(arena, out, indent, raw_data, header->machine, 0, 1, section_markers, header->section_count, section_table);
|
||||
rd_newline();
|
||||
}
|
||||
|
||||
if (opts & RD_Option_Codeview) {
|
||||
cv_format_debug_sections(arena, out, indent, raw_data, raw_string_table, header->section_count, section_table);
|
||||
}
|
||||
|
||||
if (opts & RD_Option_Dwarf) {
|
||||
DW_Input dwarf_input = dw_input_from_coff_section_table(scratch.arena, raw_data, raw_string_table, header->section_count, section_table);
|
||||
dw_format(arena, out, indent, opts, &dwarf_input, arch, ExecutableImageKind_CoffPe);
|
||||
}
|
||||
|
||||
exit:;
|
||||
scratch_end(scratch);
|
||||
}
|
||||
|
||||
internal void
|
||||
coff_print_archive(Arena *arena, String8List *out, String8 indent, String8 raw_archive, RD_Option opts)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
|
||||
COFF_ArchiveParse archive_parse = coff_archive_parse_from_data(raw_archive);
|
||||
|
||||
if (archive_parse.error.size) {
|
||||
rd_errorf("%S", archive_parse.error);
|
||||
return;
|
||||
}
|
||||
|
||||
COFF_ArchiveFirstMember first_member = archive_parse.first_member;
|
||||
{
|
||||
rd_printf("# First Header");
|
||||
rd_indent();
|
||||
|
||||
rd_printf("Symbol Count : %u", first_member.symbol_count);
|
||||
rd_printf("String Table Size: %#llx (%M)", first_member.string_table.size, first_member.string_table.size);
|
||||
|
||||
rd_printf("Members:");
|
||||
rd_indent();
|
||||
|
||||
String8List string_table = str8_split_by_string_chars(scratch.arena, first_member.string_table, str8_lit("\0"), 0);
|
||||
|
||||
if (string_table.node_count == first_member.member_offset_count) {
|
||||
String8Node *string_n = string_table.first;
|
||||
|
||||
for (U64 i = 0; i < string_table.node_count; ++i, string_n = string_n->next) {
|
||||
U32 offset = from_be_u32(first_member.member_offsets[i]);
|
||||
rd_printf("[%4u] %#08x %S", i, offset, string_n->string);
|
||||
}
|
||||
} else {
|
||||
rd_errorf("Member offset count (%llu) doesn't match string table count (%llu)", first_member.member_offset_count);
|
||||
}
|
||||
|
||||
rd_unindent();
|
||||
rd_unindent();
|
||||
rd_newline();
|
||||
}
|
||||
|
||||
if (archive_parse.has_second_header) {
|
||||
COFF_ArchiveSecondMember second_member = archive_parse.second_member;
|
||||
|
||||
rd_printf("# Second Header");
|
||||
rd_indent();
|
||||
|
||||
rd_printf("Member Count : %u", second_member.member_count);
|
||||
rd_printf("Symbol Count : %u", second_member.symbol_count);
|
||||
rd_printf("String Table Size: %#llx (%M)", second_member.string_table.size, second_member.string_table.size);
|
||||
|
||||
String8List string_table = str8_split_by_string_chars(scratch.arena, second_member.string_table, str8_lit("\0"), 0);
|
||||
|
||||
rd_printf("Members:");
|
||||
rd_indent();
|
||||
if (second_member.symbol_index_count == second_member.symbol_count) {
|
||||
String8Node *string_n = string_table.first;
|
||||
for (U64 i = 0; i < second_member.symbol_count; ++i, string_n = string_n->next) {
|
||||
U16 symbol_number = second_member.symbol_indices[i];
|
||||
if (symbol_number > 0 && symbol_number <= second_member.member_offset_count) {
|
||||
U16 symbol_idx = symbol_number - 1;
|
||||
U32 member_offset = second_member.member_offsets[i];
|
||||
rd_printf("[%4u] %#08x %S", i, member_offset, string_n->string);
|
||||
} else {
|
||||
rd_errorf("[%4u] Out of bounds symbol number %u", i, symbol_number);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
rd_errorf("Symbol index count %u doesn't match symbol count %u",
|
||||
second_member.symbol_index_count, second_member.symbol_count);
|
||||
}
|
||||
rd_unindent();
|
||||
|
||||
rd_unindent();
|
||||
rd_newline();
|
||||
}
|
||||
|
||||
if (archive_parse.has_long_names && opts & RD_Option_LongNames) {
|
||||
rd_printf("# Long Names");
|
||||
rd_indent();
|
||||
|
||||
String8List long_names = str8_split_by_string_chars(scratch.arena, archive_parse.long_names, str8_lit("\0"), 0);
|
||||
U64 name_idx = 0;
|
||||
for (String8Node *name_n = long_names.first; name_n != 0; name_n = name_n->next, ++name_idx) {
|
||||
U64 offset = (U64)(name_n->string.str - archive_parse.long_names.str);
|
||||
rd_printf("[%-4u] %#08x %S", name_idx, offset, name_n->string);
|
||||
}
|
||||
|
||||
rd_unindent();
|
||||
rd_newline();
|
||||
}
|
||||
|
||||
U64 member_offset_count = 0;
|
||||
U32 *member_offsets = 0;
|
||||
if (archive_parse.has_second_header) {
|
||||
member_offset_count = archive_parse.second_member.member_offset_count;
|
||||
member_offsets = archive_parse.second_member.member_offsets;
|
||||
} else {
|
||||
HashTable *ht = hash_table_init(scratch.arena, 0x1000);
|
||||
for (U64 i = 0; i < archive_parse.first_member.member_offset_count; ++i) {
|
||||
U32 member_offset = from_be_u32(archive_parse.first_member.member_offsets[i]);
|
||||
if (!hash_table_search_u32(ht, member_offset)) {
|
||||
hash_table_push_u32_raw(scratch.arena, ht, member_offset, 0);
|
||||
}
|
||||
}
|
||||
member_offset_count = ht->count;
|
||||
member_offsets = keys_from_hash_table_u32(scratch.arena, ht);
|
||||
radsort(member_offsets, member_offset_count, u32_is_before);
|
||||
}
|
||||
|
||||
rd_printf("# Members");
|
||||
rd_indent();
|
||||
|
||||
for (U64 i = 0; i < member_offset_count; ++i) {
|
||||
U64 next_member_offset = i+1 < member_offset_count ? member_offsets[i+1] : raw_archive.size;
|
||||
U64 member_offset = member_offsets[i];
|
||||
String8 raw_member = str8_substr(raw_archive, rng_1u64(member_offset, next_member_offset));
|
||||
COFF_ArchiveMember member = coff_archive_member_from_data(raw_member);
|
||||
COFF_DataType member_type = coff_data_type_from_data(member.data);
|
||||
|
||||
rd_printf("Member @ %#llx", member_offset);
|
||||
rd_indent();
|
||||
|
||||
if (opts & RD_Option_Headers) {
|
||||
coff_print_archive_member_header(arena, out, indent, member.header, archive_parse.long_names);
|
||||
rd_newline();
|
||||
}
|
||||
|
||||
switch (member_type) {
|
||||
case COFF_DataType_Obj: {
|
||||
coff_print_obj(arena, out, indent, member.data, opts);
|
||||
} break;
|
||||
case COFF_DataType_BigObj: {
|
||||
coff_print_big_obj(arena, out, indent, member.data, opts);
|
||||
} break;
|
||||
case COFF_DataType_Import: {
|
||||
if (opts & RD_Option_Headers) {
|
||||
COFF_ParsedArchiveImportHeader header = {0};
|
||||
U64 parse_size = coff_parse_import(member.data, 0, &header);
|
||||
if (parse_size) {
|
||||
coff_print_import(arena, out, indent, &header);
|
||||
} else {
|
||||
rd_errorf("not enough bytes to parse import header");
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case COFF_DataType_Null: {
|
||||
rd_errorf("unknown member format", member_offset);
|
||||
} break;
|
||||
}
|
||||
|
||||
rd_unindent();
|
||||
rd_newline();
|
||||
}
|
||||
|
||||
rd_unindent();
|
||||
|
||||
scratch_end(scratch);
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,22 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef COFF_DUMP_H
|
||||
#define COFF_DUMP_H
|
||||
|
||||
#if 0
|
||||
internal void coff_print_archive_member_header(Arena *arena, String8List *out, String8 indent, COFF_ParsedArchiveMemberHeader header, String8 long_names);
|
||||
internal void coff_print_section_table (Arena *arena, String8List *out, String8 indent, String8 string_table, 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, String8 string_table, 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, String8 string_table, 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);
|
||||
#endif
|
||||
|
||||
#endif // COFF_DUMP_H
|
||||
@@ -1,480 +1 @@
|
||||
// Copyright (c) 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_MachineType_Unknown },
|
||||
{ str8_lit_comp("X86"), COFF_MachineType_X86 },
|
||||
{ str8_lit_comp("Amd64"), COFF_MachineType_X64 },
|
||||
{ str8_lit_comp("X64"), COFF_MachineType_X64 },
|
||||
{ str8_lit_comp("Am33"), COFF_MachineType_Am33 },
|
||||
{ str8_lit_comp("Arm"), COFF_MachineType_Arm },
|
||||
{ str8_lit_comp("Arm64"), COFF_MachineType_Arm64 },
|
||||
{ str8_lit_comp("ArmNt"), COFF_MachineType_ArmNt },
|
||||
{ str8_lit_comp("Ebc"), COFF_MachineType_Ebc },
|
||||
{ str8_lit_comp("Ia64"), COFF_MachineType_Ia64 },
|
||||
{ str8_lit_comp("M32r"), COFF_MachineType_M32R },
|
||||
{ str8_lit_comp("Mips16"), COFF_MachineType_Mips16 },
|
||||
{ str8_lit_comp("MipsFpu"), COFF_MachineType_MipsFpu },
|
||||
{ str8_lit_comp("MipsFpu16"), COFF_MachineType_MipsFpu16 },
|
||||
{ str8_lit_comp("PowerPc"), COFF_MachineType_PowerPc },
|
||||
{ str8_lit_comp("PowerPcFp"), COFF_MachineType_PowerPcFp },
|
||||
{ str8_lit_comp("R4000"), COFF_MachineType_R4000 },
|
||||
{ str8_lit_comp("RiscV32"), COFF_MachineType_RiscV32 },
|
||||
{ str8_lit_comp("RiscV64"), COFF_MachineType_RiscV64 },
|
||||
{ str8_lit_comp("Sh3"), COFF_MachineType_Sh3 },
|
||||
{ str8_lit_comp("Sh3Dsp"), COFF_MachineType_Sh3Dsp },
|
||||
{ str8_lit_comp("Sh4"), COFF_MachineType_Sh4 },
|
||||
{ str8_lit_comp("Sh5"), COFF_MachineType_Sh5 },
|
||||
{ str8_lit_comp("Thumb"), COFF_MachineType_Thumb },
|
||||
{ str8_lit_comp("WceMipsV2"), COFF_MachineType_WceMipsV2 },
|
||||
};
|
||||
|
||||
read_only static struct {
|
||||
char * name;
|
||||
COFF_ImportType type;
|
||||
} g_coff_import_header_type_map[] = {
|
||||
{ "Code", COFF_ImportHeader_Code },
|
||||
{ "Data", COFF_ImportHeader_Data },
|
||||
{ "Const", COFF_ImportHeader_Const },
|
||||
};
|
||||
|
||||
internal String8
|
||||
coff_string_from_comdat_select_type(COFF_ComdatSelectType type)
|
||||
{
|
||||
String8 result = str8_zero();
|
||||
switch (type) {
|
||||
case COFF_ComdatSelect_Null: result = str8_lit("Null"); break;
|
||||
case COFF_ComdatSelect_NoDuplicates: result = str8_lit("NoDuplicates"); break;
|
||||
case COFF_ComdatSelect_Any: result = str8_lit("Any"); break;
|
||||
case COFF_ComdatSelect_SameSize: result = str8_lit("SameSize"); break;
|
||||
case COFF_ComdatSelect_ExactMatch: result = str8_lit("ExactMatch"); break;
|
||||
case COFF_ComdatSelect_Associative: result = str8_lit("Associative"); break;
|
||||
case COFF_ComdatSelect_Largest: result = str8_lit("Largest"); break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String8
|
||||
coff_string_from_machine_type(COFF_MachineType machine)
|
||||
{
|
||||
for (U64 i = 0; i < ArrayCount(g_coff_machine_map); ++i) {
|
||||
if (g_coff_machine_map[i].machine == machine) {
|
||||
return g_coff_machine_map[i].string;
|
||||
}
|
||||
}
|
||||
return str8_zero();
|
||||
}
|
||||
|
||||
internal String8
|
||||
coff_string_from_flags(Arena *arena, COFF_FileHeaderFlags flags)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
String8List list = {0};
|
||||
|
||||
if (flags & COFF_FileHeaderFlag_RelocStripped) {
|
||||
str8_list_pushf(scratch.arena, &list, "Relocs Stripped");
|
||||
}
|
||||
if (flags & COFF_FileHeaderFlag_ExecutableImage) {
|
||||
str8_list_pushf(scratch.arena, &list, "Executable");
|
||||
}
|
||||
if (flags & COFF_FileHeaderFlag_LineNumbersStripped) {
|
||||
str8_list_pushf(scratch.arena, &list, "Line Numbers Stripped");
|
||||
}
|
||||
if (flags & COFF_FileHeaderFlag_SymbolsStripped) {
|
||||
str8_list_pushf(scratch.arena, &list, "Symbols Stripped");
|
||||
}
|
||||
if (flags & COFF_FileHeaderFlag_LargeAddressAware) {
|
||||
str8_list_pushf(scratch.arena, &list, "Large Address Aware");
|
||||
}
|
||||
if (flags & COFF_FileHeaderFlag_32BitMachine) {
|
||||
str8_list_pushf(scratch.arena, &list, "32-Bit Machine");
|
||||
}
|
||||
if (flags & COFF_FileHeaderFlag_DebugStripped) {
|
||||
str8_list_pushf(scratch.arena, &list, "Debug Stripped");
|
||||
}
|
||||
if (flags & COFF_FileHeaderFlag_RemovableRunFromSwap) {
|
||||
str8_list_pushf(scratch.arena, &list, "Removeable Run From Swap");
|
||||
}
|
||||
if (flags & COFF_FileHeaderFlag_NetRunFromSwap) {
|
||||
str8_list_pushf(scratch.arena, &list, "Net Run From Swap");
|
||||
}
|
||||
if (flags & COFF_FileHeaderFlag_System) {
|
||||
str8_list_pushf(scratch.arena, &list, "System");
|
||||
}
|
||||
if (flags & COFF_FileHeaderFlag_Dll) {
|
||||
str8_list_pushf(scratch.arena, &list, "DLL");
|
||||
}
|
||||
if (flags & COFF_FileHeaderFlag_UpSystemOnly) {
|
||||
str8_list_pushf(scratch.arena, &list, "Up System Only");
|
||||
}
|
||||
|
||||
String8 result = str8_list_join(arena, &list, &(StringJoin){.sep=str8_lit(", ")});
|
||||
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String8
|
||||
coff_string_from_section_flags(Arena *arena, COFF_SectionFlags flags)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
String8List list = {0};
|
||||
|
||||
if (flags & COFF_SectionFlag_TypeNoPad) {
|
||||
str8_list_pushf(scratch.arena, &list, "TypeNoPad");
|
||||
}
|
||||
if (flags & COFF_SectionFlag_CntCode) {
|
||||
str8_list_pushf(scratch.arena, &list, "CntCode");
|
||||
}
|
||||
if (flags & COFF_SectionFlag_CntInitializedData) {
|
||||
str8_list_pushf(scratch.arena, &list, "CntInitializedData");
|
||||
}
|
||||
if (flags & COFF_SectionFlag_CntUninitializedData) {
|
||||
str8_list_pushf(scratch.arena, &list, "CntUninitializedData");
|
||||
}
|
||||
if (flags & COFF_SectionFlag_LnkOther) {
|
||||
str8_list_pushf(scratch.arena, &list, "LnkOther");
|
||||
}
|
||||
if (flags & COFF_SectionFlag_LnkInfo) {
|
||||
str8_list_pushf(scratch.arena, &list, "LnkInfo");
|
||||
}
|
||||
if (flags & COFF_SectionFlag_LnkCOMDAT) {
|
||||
str8_list_pushf(scratch.arena, &list, "LnkCOMDAT");
|
||||
}
|
||||
if (flags & COFF_SectionFlag_GpRel) {
|
||||
str8_list_pushf(scratch.arena, &list, "GpRel");
|
||||
}
|
||||
if (flags & COFF_SectionFlag_Mem16Bit) {
|
||||
str8_list_pushf(scratch.arena, &list, "Mem16Bit");
|
||||
}
|
||||
if (flags & COFF_SectionFlag_MemLocked) {
|
||||
str8_list_pushf(scratch.arena, &list, "MemLocked");
|
||||
}
|
||||
if (flags & COFF_SectionFlag_MemPreload) {
|
||||
str8_list_pushf(scratch.arena, &list, "MemPreload");
|
||||
}
|
||||
if (flags & COFF_SectionFlag_LnkNRelocOvfl) {
|
||||
str8_list_pushf(scratch.arena, &list, "LnkNRelocOvfl");
|
||||
}
|
||||
if (flags & COFF_SectionFlag_MemDiscardable) {
|
||||
str8_list_pushf(scratch.arena, &list, "MemDiscardable");
|
||||
}
|
||||
if (flags & COFF_SectionFlag_MemNotCached) {
|
||||
str8_list_pushf(scratch.arena, &list, "MemNotCached");
|
||||
}
|
||||
if (flags & COFF_SectionFlag_MemNotPaged) {
|
||||
str8_list_pushf(scratch.arena, &list, "MemNotPaged");
|
||||
}
|
||||
if (flags & COFF_SectionFlag_MemShared) {
|
||||
str8_list_pushf(scratch.arena, &list, "MemShared");
|
||||
}
|
||||
if (flags & COFF_SectionFlag_MemExecute) {
|
||||
str8_list_pushf(scratch.arena, &list, "MemExecute");
|
||||
}
|
||||
if (flags & COFF_SectionFlag_MemRead) {
|
||||
str8_list_pushf(scratch.arena, &list, "MemRead");
|
||||
}
|
||||
if (flags & COFF_SectionFlag_MemWrite) {
|
||||
str8_list_pushf(scratch.arena, &list, "MemWrite");
|
||||
}
|
||||
|
||||
U64 align = coff_align_size_from_section_flags(flags);
|
||||
if (align) {
|
||||
str8_list_pushf(scratch.arena, &list, "Align=%u", align);
|
||||
}
|
||||
|
||||
if (!list.node_count) {
|
||||
str8_list_pushf(scratch.arena, &list, "None");
|
||||
}
|
||||
|
||||
StringJoin join = {0};
|
||||
join.sep = str8_lit(", ");
|
||||
String8 result = str8_list_join(arena, &list, &join);
|
||||
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String8
|
||||
coff_string_from_resource_memory_flags(Arena *arena, COFF_ResourceMemoryFlags flags)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
|
||||
String8List list = {0};
|
||||
|
||||
if (flags & COFF_ResourceMemoryFlag_Moveable) {
|
||||
flags &= COFF_ResourceMemoryFlag_Moveable;
|
||||
str8_list_pushf(scratch.arena, &list, "Moveable");
|
||||
}
|
||||
if (flags & COFF_ResourceMemoryFlag_Pure) {
|
||||
flags &= COFF_ResourceMemoryFlag_Pure;
|
||||
str8_list_pushf(scratch.arena, &list, "Pure");
|
||||
}
|
||||
if (flags & COFF_ResourceMemoryFlag_Discardable) {
|
||||
flags &= COFF_ResourceMemoryFlag_Discardable;
|
||||
str8_list_pushf(scratch.arena, &list, "Discardable");
|
||||
}
|
||||
if (flags != 0) {
|
||||
str8_list_pushf(scratch.arena, &list, "%#x", flags);
|
||||
}
|
||||
|
||||
String8 result = str8_list_join(arena, &list, &(StringJoin){.sep=str8_lit(", ")});
|
||||
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String8
|
||||
coff_string_from_import_header_type(COFF_ImportType type)
|
||||
{
|
||||
for (U64 i = 0; i < ArrayCount(g_coff_import_header_type_map); ++i) {
|
||||
if (g_coff_import_header_type_map[i].type == type) {
|
||||
return str8_cstring(g_coff_import_header_type_map[i].name);
|
||||
}
|
||||
}
|
||||
return str8(0,0);
|
||||
}
|
||||
|
||||
internal String8
|
||||
coff_string_from_sym_dtype(COFF_SymDType x)
|
||||
{
|
||||
switch (x) {
|
||||
case COFF_SymDType_Null: return str8_lit("Null");
|
||||
case COFF_SymDType_Ptr : return str8_lit("Ptr");
|
||||
case COFF_SymDType_Func: return str8_lit("Func");
|
||||
case COFF_SymDType_Array: return str8_lit("Array");
|
||||
}
|
||||
return str8_zero();
|
||||
}
|
||||
|
||||
internal String8
|
||||
coff_string_from_sym_type(COFF_SymType x)
|
||||
{
|
||||
switch (x) {
|
||||
case COFF_SymType_Null: return str8_lit("Null");
|
||||
case COFF_SymType_Void: return str8_lit("Void");
|
||||
case COFF_SymType_Char: return str8_lit("Char");
|
||||
case COFF_SymType_Short: return str8_lit("Short");
|
||||
case COFF_SymType_Int: return str8_lit("Int");
|
||||
case COFF_SymType_Long: return str8_lit("Long");
|
||||
case COFF_SymType_Float: return str8_lit("Float");
|
||||
case COFF_SymType_Double: return str8_lit("Double");
|
||||
case COFF_SymType_Struct: return str8_lit("Struct");
|
||||
case COFF_SymType_Union: return str8_lit("Union");
|
||||
case COFF_SymType_Enum: return str8_lit("Enum");
|
||||
case COFF_SymType_MemberOfEnumeration: return str8_lit("MOE");
|
||||
case COFF_SymType_Byte: return str8_lit("Byte");
|
||||
case COFF_SymType_Word: return str8_lit("Word");
|
||||
case COFF_SymType_UInt: return str8_lit("UInt");
|
||||
case COFF_SymType_DWord: return str8_lit("DWord");
|
||||
}
|
||||
return str8_zero();
|
||||
}
|
||||
|
||||
internal String8
|
||||
coff_string_from_sym_storage_class(COFF_SymStorageClass x)
|
||||
{
|
||||
switch (x) {
|
||||
case COFF_SymStorageClass_Null: break;
|
||||
case COFF_SymStorageClass_EndOfFunction: return str8_lit("EndOfFunction");
|
||||
case COFF_SymStorageClass_Automatic: return str8_lit("Automatic");
|
||||
case COFF_SymStorageClass_External: return str8_lit("External");
|
||||
case COFF_SymStorageClass_Static: return str8_lit("Static");
|
||||
case COFF_SymStorageClass_Register: return str8_lit("Register");
|
||||
case COFF_SymStorageClass_ExternalDef: return str8_lit("Def");
|
||||
case COFF_SymStorageClass_Label: return str8_lit("Label");
|
||||
case COFF_SymStorageClass_UndefinedLabel: return str8_lit("UndefinedLabel");
|
||||
case COFF_SymStorageClass_MemberOfStruct: return str8_lit("Struct");
|
||||
case COFF_SymStorageClass_Argument: return str8_lit("Argument");
|
||||
case COFF_SymStorageClass_StructTag: return str8_lit("Tag");
|
||||
case COFF_SymStorageClass_MemberOfUnion: return str8_lit("Union");
|
||||
case COFF_SymStorageClass_UnionTag: return str8_lit("Tag");
|
||||
case COFF_SymStorageClass_TypeDefinition: return str8_lit("Definition");
|
||||
case COFF_SymStorageClass_UndefinedStatic: return str8_lit("Static");
|
||||
case COFF_SymStorageClass_EnumTag: return str8_lit("Tag");
|
||||
case COFF_SymStorageClass_MemberOfEnum: return str8_lit("Enum");
|
||||
case COFF_SymStorageClass_RegisterParam: return str8_lit("Param");
|
||||
case COFF_SymStorageClass_BitField: return str8_lit("Field");
|
||||
case COFF_SymStorageClass_Block: return str8_lit("Block");
|
||||
case COFF_SymStorageClass_Function: return str8_lit("Function");
|
||||
case COFF_SymStorageClass_EndOfStruct: return str8_lit("Struct");
|
||||
case COFF_SymStorageClass_File: return str8_lit("File");
|
||||
case COFF_SymStorageClass_Section: return str8_lit("Section");
|
||||
case COFF_SymStorageClass_WeakExternal: return str8_lit("External");
|
||||
case COFF_SymStorageClass_CLRToken: return str8_lit("Token");
|
||||
}
|
||||
return str8_zero();
|
||||
}
|
||||
|
||||
internal String8
|
||||
coff_string_from_weak_ext_type(COFF_WeakExtType x)
|
||||
{
|
||||
switch (x) {
|
||||
case COFF_WeakExt_NoLibrary: return str8_lit("NoLibrary");
|
||||
case COFF_WeakExt_SearchLibrary: return str8_lit("SearchLibrary");
|
||||
case COFF_WeakExt_SearchAlias: return str8_lit("SearchAlias");
|
||||
}
|
||||
return str8_zero();
|
||||
}
|
||||
|
||||
internal String8
|
||||
coff_string_from_reloc_x86(COFF_Reloc_X86 x)
|
||||
{
|
||||
switch (x) {
|
||||
case COFF_Reloc_X86_Abs: return str8_lit("Abs");
|
||||
case COFF_Reloc_X86_Dir16: return str8_lit("Dir16");
|
||||
case COFF_Reloc_X86_Rel16: return str8_lit("Rel16");
|
||||
case COFF_Reloc_X86_Unknown0: return str8_lit("Unknown0");
|
||||
case COFF_Reloc_X86_Unknown2: return str8_lit("Unknown2");
|
||||
case COFF_Reloc_X86_Unknown3: return str8_lit("Unknown3");
|
||||
case COFF_Reloc_X86_Dir32: return str8_lit("Dir32");
|
||||
case COFF_Reloc_X86_Dir32Nb: return str8_lit("Dir32Nb");
|
||||
case COFF_Reloc_X86_Seg12: return str8_lit("Seg12");
|
||||
case COFF_Reloc_X86_Section: return str8_lit("Section");
|
||||
case COFF_Reloc_X86_SecRel: return str8_lit("SecRel");
|
||||
case COFF_Reloc_X86_Token: return str8_lit("Token");
|
||||
case COFF_Reloc_X86_SecRel7: return str8_lit("SecRel7");
|
||||
case COFF_Reloc_X86_Unknown4: return str8_lit("Unknown4");
|
||||
case COFF_Reloc_X86_Unknown5: return str8_lit("Unknown5");
|
||||
case COFF_Reloc_X86_Unknown6: return str8_lit("Unknown6");
|
||||
case COFF_Reloc_X86_Unknown7: return str8_lit("Unknown7");
|
||||
case COFF_Reloc_X86_Unknown8: return str8_lit("Unknown8");
|
||||
case COFF_Reloc_X86_Unknown9: return str8_lit("Unknown9");
|
||||
case COFF_Reloc_X86_Rel32: return str8_lit("Rel32");
|
||||
}
|
||||
return str8_zero();
|
||||
}
|
||||
|
||||
internal String8
|
||||
coff_string_from_reloc_x64(COFF_Reloc_X64 x)
|
||||
{
|
||||
switch (x) {
|
||||
case COFF_Reloc_X64_Abs: return str8_lit("Abs");
|
||||
case COFF_Reloc_X64_Addr64: return str8_lit("Addr64");
|
||||
case COFF_Reloc_X64_Addr32: return str8_lit("Addr32");
|
||||
case COFF_Reloc_X64_Addr32Nb: return str8_lit("Addr32Nb");
|
||||
case COFF_Reloc_X64_Rel32: return str8_lit("Rel32");
|
||||
case COFF_Reloc_X64_Rel32_1: return str8_lit("Rel32_1");
|
||||
case COFF_Reloc_X64_Rel32_2: return str8_lit("Rel32_2");
|
||||
case COFF_Reloc_X64_Rel32_3: return str8_lit("Rel32_3");
|
||||
case COFF_Reloc_X64_Rel32_4: return str8_lit("Rel32_4");
|
||||
case COFF_Reloc_X64_Rel32_5: return str8_lit("Rel32_5");
|
||||
case COFF_Reloc_X64_Section: return str8_lit("Section");
|
||||
case COFF_Reloc_X64_SecRel: return str8_lit("SecRel");
|
||||
case COFF_Reloc_X64_SecRel7: return str8_lit("SecRel7");
|
||||
case COFF_Reloc_X64_Token: return str8_lit("Token");
|
||||
case COFF_Reloc_X64_SRel32: return str8_lit("SRel32");
|
||||
case COFF_Reloc_X64_Pair: return str8_lit("Pair");
|
||||
case COFF_Reloc_X64_SSpan32: return str8_lit("SSpan32");
|
||||
}
|
||||
return str8_zero();
|
||||
}
|
||||
|
||||
internal String8
|
||||
coff_string_from_reloc_arm(COFF_Reloc_Arm x)
|
||||
{
|
||||
switch (x) {
|
||||
case COFF_Reloc_Arm_Abs: return str8_lit("Abs");
|
||||
case COFF_Reloc_Arm_Addr32: return str8_lit("Addr32");
|
||||
case COFF_Reloc_Arm_Addr32Nb: return str8_lit("Addr32Nb");
|
||||
case COFF_Reloc_Arm_Branch24: return str8_lit("Branch24");
|
||||
case COFF_Reloc_Arm_Branch11: return str8_lit("Branch11");
|
||||
case COFF_Reloc_Arm_Unknown1: return str8_lit("Unknown1");
|
||||
case COFF_Reloc_Arm_Unknown2: return str8_lit("Unknown2");
|
||||
case COFF_Reloc_Arm_Unknown3: return str8_lit("Unknown3");
|
||||
case COFF_Reloc_Arm_Unknown4: return str8_lit("Unknown4");
|
||||
case COFF_Reloc_Arm_Unknown5: return str8_lit("Unknown5");
|
||||
case COFF_Reloc_Arm_Rel32: return str8_lit("Rel32");
|
||||
case COFF_Reloc_Arm_Section: return str8_lit("Section");
|
||||
case COFF_Reloc_Arm_SecRel: return str8_lit("SecRel");
|
||||
case COFF_Reloc_Arm_Mov32: return str8_lit("Mov32");
|
||||
case COFF_Reloc_Arm_ThumbMov32: return str8_lit("ThumbMov32");
|
||||
case COFF_Reloc_Arm_ThumbBranch20: return str8_lit("ThumbBranch20");
|
||||
case COFF_Reloc_Arm_Unused: return str8_lit("Unused");
|
||||
case COFF_Reloc_Arm_ThumbBranch24: return str8_lit("ThumbBranch24");
|
||||
case COFF_Reloc_Arm_ThumbBlx23: return str8_lit("ThumbBlx23");
|
||||
case COFF_Reloc_Arm_Pair: return str8_lit("Pair");
|
||||
}
|
||||
return str8_zero();
|
||||
}
|
||||
|
||||
internal String8
|
||||
coff_string_from_reloc_arm64(COFF_Reloc_Arm64 x)
|
||||
{
|
||||
switch (x) {
|
||||
case COFF_Reloc_Arm64_Abs: return str8_lit("Abs");
|
||||
case COFF_Reloc_Arm64_Addr32: return str8_lit("Addr32");
|
||||
case COFF_Reloc_Arm64_Addr32Nb: return str8_lit("Addr32Nb");
|
||||
case COFF_Reloc_Arm64_Branch26: return str8_lit("Branch26");
|
||||
case COFF_Reloc_Arm64_PageBaseRel21: return str8_lit("PageBaseRel21");
|
||||
case COFF_Reloc_Arm64_Rel21: return str8_lit("Rel21");
|
||||
case COFF_Reloc_Arm64_PageOffset12a: return str8_lit("PageOffset12a");
|
||||
case COFF_Reloc_Arm64_SecRel: return str8_lit("SecRel");
|
||||
case COFF_Reloc_Arm64_SecRelLow12a: return str8_lit("SecRelLow12a");
|
||||
case COFF_Reloc_Arm64_SecRelHigh12a: return str8_lit("SecRelHigh12a");
|
||||
case COFF_Reloc_Arm64_SecRelLow12l: return str8_lit("SecRelLow12l");
|
||||
case COFF_Reloc_Arm64_Token: return str8_lit("Token");
|
||||
case COFF_Reloc_Arm64_Section: return str8_lit("Section");
|
||||
case COFF_Reloc_Arm64_Addr64: return str8_lit("Addr64");
|
||||
case COFF_Reloc_Arm64_Branch19: return str8_lit("Branch19");
|
||||
case COFF_Reloc_Arm64_Branch14: return str8_lit("Branch14");
|
||||
case COFF_Reloc_Arm64_Rel32: return str8_lit("Rel32");
|
||||
}
|
||||
return str8_zero();
|
||||
}
|
||||
|
||||
internal String8
|
||||
coff_string_from_reloc(COFF_MachineType machine, COFF_RelocType x)
|
||||
{
|
||||
switch (machine) {
|
||||
case COFF_MachineType_X86: return coff_string_from_reloc_x86(x);
|
||||
case COFF_MachineType_X64: return coff_string_from_reloc_x64(x);
|
||||
case COFF_MachineType_Arm: return coff_string_from_reloc_arm(x);
|
||||
case COFF_MachineType_Arm64: return coff_string_from_reloc_arm64(x);
|
||||
}
|
||||
return str8_zero();
|
||||
}
|
||||
|
||||
internal COFF_MachineType
|
||||
coff_machine_from_string(String8 string)
|
||||
{
|
||||
for (U64 i = 0; i < ArrayCount(g_coff_machine_map); ++i) {
|
||||
if (str8_match(g_coff_machine_map[i].string, string, StringMatchFlag_CaseInsensitive)) {
|
||||
return g_coff_machine_map[i].machine;
|
||||
}
|
||||
}
|
||||
return COFF_MachineType_Unknown;
|
||||
}
|
||||
|
||||
internal COFF_ImportType
|
||||
coff_import_header_type_from_string(String8 name)
|
||||
{
|
||||
for (U64 i = 0; i < ArrayCount(g_coff_import_header_type_map); ++i) {
|
||||
if (str8_match(str8_cstring(g_coff_import_header_type_map[i].name), name, StringMatchFlag_CaseInsensitive)) {
|
||||
return g_coff_import_header_type_map[i].type;
|
||||
}
|
||||
}
|
||||
return COFF_ImportType_Invalid;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
// Copyright (c) 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_resource_memory_flags(Arena *arena, COFF_ResourceMemoryFlags 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,6 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#include "coff/coff.c"
|
||||
#include "coff/coff_parse.c"
|
||||
#include "coff/coff_dump.c"
|
||||
@@ -0,0 +1,11 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef COFF_INC_H
|
||||
#define COFF_INC_H
|
||||
|
||||
#include "coff/coff.h"
|
||||
#include "coff/coff_parse.h"
|
||||
#include "coff/coff_dump.h"
|
||||
|
||||
#endif // COFF_INC_H
|
||||
@@ -0,0 +1,365 @@
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal COFF_LibWriterSymbolNode *
|
||||
coff_lib_writer_symbol_list_push(Arena *arena, COFF_LibWriterSymbolList *list, COFF_LibWriterSymbol symbol)
|
||||
{
|
||||
COFF_LibWriterSymbolNode *node = push_array_no_zero(arena, COFF_LibWriterSymbolNode, 1);
|
||||
node->next = 0;
|
||||
node->data = symbol;
|
||||
SLLQueuePush(list->first, list->last, node);
|
||||
list->count += 1;
|
||||
return node;
|
||||
}
|
||||
|
||||
internal COFF_LibWriterMemberNode *
|
||||
coff_lib_writer_member_list_push(Arena *arena, COFF_LibWriterMemberList *list, COFF_LibWriterMember member)
|
||||
{
|
||||
COFF_LibWriterMemberNode *node = push_array_no_zero(arena, COFF_LibWriterMemberNode, 1);
|
||||
node->next = 0;
|
||||
node->data = member;
|
||||
SLLQueuePush(list->first, list->last, node);
|
||||
list->count += 1;
|
||||
return node;
|
||||
}
|
||||
|
||||
internal COFF_LibWriterSymbol *
|
||||
coff_lib_writer_symbol_array_from_list(Arena *arena, COFF_LibWriterSymbolList list)
|
||||
{
|
||||
COFF_LibWriterSymbol *arr = push_array_no_zero(arena, COFF_LibWriterSymbol, list.count + 2);
|
||||
COFF_LibWriterSymbol *ptr = arr + 1;
|
||||
for (COFF_LibWriterSymbolNode *i = list.first; i != 0; i = i->next, ptr += 1) {
|
||||
ptr->name = push_str8_copy(arena, i->data.name);
|
||||
ptr->member_idx = i->data.member_idx;
|
||||
}
|
||||
MemoryZeroStruct(&arr[0]);
|
||||
MemoryZeroStruct(&arr[list.count+1]);
|
||||
return arr;
|
||||
}
|
||||
|
||||
internal COFF_LibWriterMember *
|
||||
coff_lib_writer_member_array_from_list(Arena *arena, COFF_LibWriterMemberList list)
|
||||
{
|
||||
COFF_LibWriterMember *arr = push_array_no_zero(arena, COFF_LibWriterMember, list.count);
|
||||
COFF_LibWriterMember *ptr = arr;
|
||||
for (COFF_LibWriterMemberNode *i = list.first; i != 0; i = i->next, ptr += 1) {
|
||||
ptr->name = push_str8_copy(arena, i->data.name);
|
||||
ptr->data = push_str8_copy(arena, i->data.data);
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
internal int
|
||||
coff_lib_writer_symbol_name_compar(const void *raw_a, const void *raw_b)
|
||||
{
|
||||
const COFF_LibWriterSymbol *sa = raw_a;
|
||||
const COFF_LibWriterSymbol *sb = raw_b;
|
||||
return str8_compar_case_sensitive(&sa->name, &sb->name);
|
||||
}
|
||||
|
||||
internal int
|
||||
coff_lib_writer_symbol_is_before(void *raw_a, void *raw_b)
|
||||
{
|
||||
int compar = coff_lib_writer_symbol_name_compar(raw_a, raw_b);
|
||||
return compar < 0;
|
||||
}
|
||||
|
||||
internal void
|
||||
coff_lib_writer_symbol_array_sort(COFF_LibWriterSymbol *arr, U64 count)
|
||||
{
|
||||
Assert(count >= 2);
|
||||
radsort(arr + 1, count - 2, coff_lib_writer_symbol_is_before);
|
||||
}
|
||||
|
||||
internal COFF_LibWriter *
|
||||
coff_lib_writer_alloc(void)
|
||||
{
|
||||
Arena *arena = arena_alloc();
|
||||
COFF_LibWriter *writer = push_array(arena, COFF_LibWriter, 1);
|
||||
writer->arena = arena;
|
||||
return writer;
|
||||
}
|
||||
|
||||
internal void
|
||||
coff_lib_writer_release(COFF_LibWriter **writer_ptr)
|
||||
{
|
||||
arena_release((*writer_ptr)->arena);
|
||||
*writer_ptr = 0;
|
||||
}
|
||||
|
||||
internal U64
|
||||
coff_lib_writer_push_obj(COFF_LibWriter *writer, String8 obj_path, String8 obj_data)
|
||||
{
|
||||
U64 member_idx = writer->member_list.count;
|
||||
|
||||
// push obj member
|
||||
COFF_LibWriterMember member = {0};
|
||||
member.name = obj_path;
|
||||
member.data = obj_data;
|
||||
coff_lib_writer_member_list_push(writer->arena, &writer->member_list, member);
|
||||
|
||||
// push external symbols
|
||||
{
|
||||
COFF_FileHeaderInfo obj_header = coff_file_header_info_from_data(obj_data);
|
||||
String8 string_table = str8_substr(obj_data, obj_header.string_table_range);
|
||||
String8 symbol_table = str8_substr(obj_data, obj_header.symbol_table_range);
|
||||
|
||||
COFF_ParsedSymbol symbol;
|
||||
for (U64 symbol_idx = 0; symbol_idx < obj_header.symbol_count; symbol_idx += (1 + symbol.aux_symbol_count)) {
|
||||
void *symbol_ptr;
|
||||
if (obj_header.is_big_obj) {
|
||||
symbol_ptr = &((COFF_Symbol32 *)symbol_table.str)[symbol_idx];
|
||||
symbol = coff_parse_symbol32(string_table, symbol_ptr);
|
||||
} else {
|
||||
symbol_ptr = &((COFF_Symbol16 *)symbol_table.str)[symbol_idx];
|
||||
symbol = coff_parse_symbol16(string_table, symbol_ptr);
|
||||
}
|
||||
|
||||
COFF_SymbolValueInterpType interp = coff_interp_symbol(symbol.section_number, symbol.value, symbol.storage_class);
|
||||
if (interp == COFF_SymbolValueInterp_Regular) {
|
||||
if (symbol.storage_class == COFF_SymStorageClass_External) {
|
||||
COFF_LibWriterSymbol lib_symbol = {0};
|
||||
lib_symbol.name = symbol.name;
|
||||
lib_symbol.member_idx = member_idx;
|
||||
coff_lib_writer_symbol_list_push(writer->arena, &writer->symbol_list, lib_symbol);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return member_idx;
|
||||
}
|
||||
|
||||
internal void
|
||||
coff_lib_writer_push_import(COFF_LibWriter *lib_writer, COFF_MachineType machine, COFF_TimeStamp time_stamp, String8 dll_name, COFF_ImportByType import_by, String8 name, U16 hint_or_ordinal, COFF_ImportType import_type)
|
||||
{
|
||||
// push import member
|
||||
U64 member_idx = lib_writer->member_list.count;
|
||||
COFF_LibWriterMember member = {0};
|
||||
member.name = dll_name;
|
||||
member.data = coff_make_import_header(lib_writer->arena, machine, time_stamp, dll_name, import_by, name, hint_or_ordinal, import_type);
|
||||
coff_lib_writer_member_list_push(lib_writer->arena, &lib_writer->member_list, member);
|
||||
|
||||
if (name.size) {
|
||||
switch (import_type) {
|
||||
case COFF_ImportHeader_Code: {
|
||||
COFF_LibWriterSymbol thunk_symbol = {0};
|
||||
thunk_symbol.name = push_str8_copy(lib_writer->arena, name);
|
||||
thunk_symbol.member_idx = member_idx;
|
||||
coff_lib_writer_symbol_list_push(lib_writer->arena, &lib_writer->symbol_list, thunk_symbol);
|
||||
|
||||
COFF_LibWriterSymbol imp_symbol = {0};
|
||||
imp_symbol.name = push_str8f(lib_writer->arena, "__imp_%S", name);
|
||||
imp_symbol.member_idx = member_idx;
|
||||
coff_lib_writer_symbol_list_push(lib_writer->arena, &lib_writer->symbol_list, imp_symbol);
|
||||
} break;
|
||||
case COFF_ImportHeader_Data: {
|
||||
COFF_LibWriterSymbol imp_symbol = {0};
|
||||
imp_symbol.name = push_str8f(lib_writer->arena, "__imp_%S", name);
|
||||
imp_symbol.member_idx = member_idx;
|
||||
coff_lib_writer_symbol_list_push(lib_writer->arena, &lib_writer->symbol_list, imp_symbol);
|
||||
} break;
|
||||
case COFF_ImportHeader_Const: { NotImplemented; } break;
|
||||
default: { InvalidPath; } break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal String8List
|
||||
coff_lib_writer_serialize(Arena *arena, COFF_LibWriter *lib_writer, COFF_TimeStamp time_stamp, U16 mode, B32 emit_second_member)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
|
||||
// symbol & member lists -> arrays
|
||||
U64 symbols_count;
|
||||
COFF_LibWriterSymbol *symbols;
|
||||
U64 member_count;
|
||||
COFF_LibWriterMember *member_array;
|
||||
{
|
||||
U64 symbols_count_with_null = lib_writer->symbol_list.count + 2;
|
||||
COFF_LibWriterSymbol *symbols_with_null = coff_lib_writer_symbol_array_from_list(scratch.arena, lib_writer->symbol_list);
|
||||
coff_lib_writer_symbol_array_sort(symbols_with_null, symbols_count_with_null);
|
||||
symbols_count = symbols_count_with_null - 2;
|
||||
symbols = symbols_with_null + 1;
|
||||
|
||||
member_count = lib_writer->member_list.count;
|
||||
member_array = coff_lib_writer_member_array_from_list(scratch.arena, lib_writer->member_list);
|
||||
}
|
||||
|
||||
// serialize members
|
||||
U64 *member_offsets = push_array_no_zero(scratch.arena, U64, member_count);
|
||||
String8List long_names_list = {0};
|
||||
String8List member_data_list = {0};
|
||||
{
|
||||
HashTable *name_ht = hash_table_init(scratch.arena, 1024);
|
||||
for (U64 member_idx = 0; member_idx < member_count; member_idx += 1) {
|
||||
COFF_LibWriterMember *member = &member_array[member_idx];
|
||||
|
||||
// make member name
|
||||
String8 name;
|
||||
U64 name_with_slash_size = member->name.size + 1;
|
||||
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) {
|
||||
name = is_present->value_string;
|
||||
} else {
|
||||
name = push_str8f(scratch.arena, "/%u", long_names_list.total_size);
|
||||
str8_list_pushf(scratch.arena, &long_names_list, "%S/\n", member->name);
|
||||
hash_table_push_string_string(scratch.arena, name_ht, member->name, name);
|
||||
}
|
||||
} else {
|
||||
name = push_str8f(scratch.arena, "%S/", member->name);
|
||||
}
|
||||
|
||||
member_offsets[member_idx] = member_data_list.total_size;
|
||||
|
||||
String8 member_data = member->data;
|
||||
String8 member_header = coff_make_lib_member_header(arena, name, time_stamp, 0, 0, mode, member_data.size);
|
||||
|
||||
str8_list_push(arena, &member_data_list, member_header);
|
||||
str8_list_push(arena, &member_data_list, member_data);
|
||||
{
|
||||
U64 pad_size = AlignPadPow2(member_data_list.total_size, COFF_Archive_MemberAlign);
|
||||
U8 *pad = push_array(arena, U8, pad_size);
|
||||
str8_list_push(arena, &member_data_list, str8(pad, pad_size));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// long names member
|
||||
if (long_names_list.total_size) {
|
||||
String8 header = coff_make_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;
|
||||
{
|
||||
U64 pad_size = AlignPadPow2(member_offset, COFF_Archive_MemberAlign);
|
||||
U8 *pad = push_array(arena, U8, pad_size);
|
||||
str8_list_push_front(arena, &member_data_list, str8(pad, pad_size));
|
||||
}
|
||||
str8_list_push_front(arena, &member_data_list, data);
|
||||
str8_list_push_front(arena, &member_data_list, header);
|
||||
}
|
||||
|
||||
// compute size for symbol string table
|
||||
U32 name_buffer_size = 0;
|
||||
for (COFF_LibWriterSymbol *ptr = &symbols[0], *opl = ptr + symbols_count; ptr < opl; ptr += 1) {
|
||||
name_buffer_size += ptr->name.size;
|
||||
name_buffer_size += 1; // null
|
||||
}
|
||||
|
||||
// write symbol name buffer
|
||||
U8 *name_buffer = push_array_no_zero(scratch.arena, U8, name_buffer_size);
|
||||
{
|
||||
U64 name_cursor = 0;
|
||||
for (COFF_LibWriterSymbol *ptr = &symbols[0], *opl = ptr + symbols_count; ptr < opl; ptr += 1) {
|
||||
MemoryCopy(name_buffer + name_cursor, ptr->name.str, ptr->name.size);
|
||||
name_buffer[name_cursor + ptr->name.size] = '\0';
|
||||
name_cursor += ptr->name.size + 1;
|
||||
}
|
||||
}
|
||||
|
||||
U64 members_base_offset;
|
||||
{
|
||||
U64 sizeof_first_header = sizeof(COFF_ArchiveMemberHeader) + sizeof(U32) + sizeof(U32) * symbols_count + name_buffer_size;
|
||||
U64 sizeof_second_header = sizeof(COFF_ArchiveMemberHeader) + sizeof(U32) + sizeof(U32) * member_count + sizeof(U32) + sizeof(U16) * symbols_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_MemberAlign);
|
||||
sizeof_second_header = AlignPow2(sizeof_second_header, COFF_Archive_MemberAlign);
|
||||
sizeof_long_names = AlignPow2(sizeof_long_names, COFF_Archive_MemberAlign);
|
||||
|
||||
members_base_offset = sizeof(g_coff_archive_sig);
|
||||
members_base_offset += sizeof_first_header;
|
||||
if (emit_second_member) {
|
||||
members_base_offset += sizeof_second_header;
|
||||
}
|
||||
if (long_names_list.total_size) {
|
||||
members_base_offset += sizeof_long_names;
|
||||
}
|
||||
}
|
||||
|
||||
// second linker member
|
||||
if (emit_second_member) {
|
||||
U32 member_count32 = safe_cast_u32(member_count);
|
||||
U32 symbol_count32 = safe_cast_u32(symbols_count);
|
||||
|
||||
U32 *member_off32_arr = push_array_no_zero(scratch.arena, U32, member_count);
|
||||
U16 *member_idx16_arr = push_array_no_zero(scratch.arena, U16, symbols_count);
|
||||
|
||||
// write member offset array
|
||||
for (U64 member_idx = 0; member_idx < member_count; member_idx += 1) {
|
||||
U64 member_offset = members_base_offset + member_offsets[member_idx];
|
||||
U32 member_off32 = safe_cast_u32(member_offset);
|
||||
member_off32_arr[member_idx] = member_off32;
|
||||
}
|
||||
|
||||
// write member offset indices for each symbol
|
||||
for (U64 symbol_idx = 0; symbol_idx < symbols_count; symbol_idx += 1) {
|
||||
// member offset indices are 1-based
|
||||
U64 member_idx = symbols[symbol_idx].member_idx + 1;
|
||||
U16 member_idx16 = safe_cast_u16(member_idx);
|
||||
member_idx16_arr[symbol_idx] = member_idx16;
|
||||
}
|
||||
|
||||
// layout second member data
|
||||
String8List second_member_data_list = {0};
|
||||
str8_list_push(scratch.arena, &second_member_data_list, str8_struct(&member_count32));
|
||||
str8_list_push(scratch.arena, &second_member_data_list, str8_array(member_off32_arr, member_count));
|
||||
str8_list_push(scratch.arena, &second_member_data_list, str8_struct(&symbol_count32));
|
||||
str8_list_push(scratch.arena, &second_member_data_list, str8_array(member_idx16_arr, symbols_count));
|
||||
str8_list_push(scratch.arena, &second_member_data_list, str8(name_buffer, name_buffer_size));
|
||||
|
||||
String8 member_data = str8_list_join(arena, &second_member_data_list, 0);
|
||||
String8 member_header = coff_make_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;
|
||||
{
|
||||
U64 pad_size = AlignPadPow2(member_offset, COFF_Archive_MemberAlign);
|
||||
U8 *pad = push_array(arena, U8, pad_size);
|
||||
str8_list_push_front(arena, &member_data_list, str8(pad, pad_size));
|
||||
}
|
||||
str8_list_push_front(arena, &member_data_list, member_data);
|
||||
str8_list_push_front(arena, &member_data_list, member_header);
|
||||
}
|
||||
|
||||
// first linker member (obsolete, but kept for compatability reasons)
|
||||
{
|
||||
U32 symbol_count_be = from_be_u32(symbols_count);
|
||||
U32 *member_off32_arr = push_array_no_zero(scratch.arena, U32, symbols_count);
|
||||
|
||||
for (U64 symbol_idx = 0; symbol_idx < symbols_count; symbol_idx += 1) {
|
||||
COFF_LibWriterSymbol *symbol = &symbols[symbol_idx];
|
||||
|
||||
// write big endian member offset
|
||||
U64 member_offset = members_base_offset + member_offsets[symbol->member_idx];
|
||||
U32 member_off32 = from_be_u32(safe_cast_u32(member_offset));
|
||||
member_off32_arr[symbol_idx] = member_off32;
|
||||
}
|
||||
|
||||
// layout first member data
|
||||
String8List first_member_data_list = {0};
|
||||
str8_list_push(scratch.arena, &first_member_data_list, str8_struct(&symbol_count_be));
|
||||
str8_list_push(scratch.arena, &first_member_data_list, str8_array(member_off32_arr, symbols_count));
|
||||
str8_list_push(scratch.arena, &first_member_data_list, str8(name_buffer, name_buffer_size));
|
||||
|
||||
String8 member_data = str8_list_join(arena, &first_member_data_list, 0);
|
||||
String8 member_header = coff_make_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;
|
||||
{
|
||||
U64 pad_size = AlignPadPow2(member_offset, COFF_Archive_MemberAlign);
|
||||
U8 *pad = push_array(arena, U8, pad_size);
|
||||
str8_list_push_front(arena, &member_data_list, str8(pad, pad_size));
|
||||
}
|
||||
str8_list_push_front(arena, &member_data_list, member_data);
|
||||
str8_list_push_front(arena, &member_data_list, member_header);
|
||||
}
|
||||
|
||||
// archive signature
|
||||
str8_list_push_front(arena, &member_data_list, str8_struct(&g_coff_archive_sig));
|
||||
|
||||
scratch_end(scratch);
|
||||
return member_data_list;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef COFF_LIB_WRITER_H
|
||||
#define COFF_LIB_WRITER_H
|
||||
|
||||
typedef struct COFF_LibWriterMember
|
||||
{
|
||||
String8 name;
|
||||
String8 data;
|
||||
} COFF_LibWriterMember;
|
||||
|
||||
typedef struct COFF_LibWriterMemberNode
|
||||
{
|
||||
COFF_LibWriterMember data;
|
||||
struct COFF_LibWriterMemberNode *next;
|
||||
} COFF_LibWriterMemberNode;
|
||||
|
||||
typedef struct COFF_LibWriterMemberList
|
||||
{
|
||||
U64 count;
|
||||
COFF_LibWriterMemberNode *first;
|
||||
COFF_LibWriterMemberNode *last;
|
||||
} COFF_LibWriterMemberList;
|
||||
|
||||
typedef struct COFF_LibWriterSymbol
|
||||
{
|
||||
String8 name;
|
||||
U64 member_idx;
|
||||
} COFF_LibWriterSymbol;
|
||||
|
||||
typedef struct COFF_LibWriterSymbolNode
|
||||
{
|
||||
COFF_LibWriterSymbol data;
|
||||
struct COFF_LibWriterSymbolNode *next;
|
||||
} COFF_LibWriterSymbolNode;
|
||||
|
||||
typedef struct COFF_LibWriterSymbolList
|
||||
{
|
||||
U64 count;
|
||||
COFF_LibWriterSymbolNode *first;
|
||||
COFF_LibWriterSymbolNode *last;
|
||||
} COFF_LibWriterSymbolList;
|
||||
|
||||
typedef struct COFF_LibWriter
|
||||
{
|
||||
Arena *arena;
|
||||
COFF_LibWriterMemberList member_list;
|
||||
COFF_LibWriterSymbolList symbol_list;
|
||||
} COFF_LibWriter;
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal COFF_LibWriterSymbolNode * coff_lib_writer_symbol_list_push(Arena *arena, COFF_LibWriterSymbolList *list, COFF_LibWriterSymbol symbol);
|
||||
internal COFF_LibWriterMemberNode * coff_lib_writer_member_list_push(Arena *arena, COFF_LibWriterMemberList *list, COFF_LibWriterMember member);
|
||||
|
||||
internal COFF_LibWriterSymbol * coff_lib_writer_symbol_array_from_list(Arena *arena, COFF_LibWriterSymbolList list);
|
||||
internal COFF_LibWriterMember * coff_lib_writer_member_array_from_list(Arena *arena, COFF_LibWriterMemberList list);
|
||||
|
||||
internal void coff_lib_writer_symbol_array_sort(COFF_LibWriterSymbol *arr, U64 count);
|
||||
|
||||
internal COFF_LibWriter * coff_lib_writer_alloc(void);
|
||||
internal void coff_lib_writer_release(COFF_LibWriter **writer_ptr);
|
||||
internal U64 coff_lib_writer_push_obj(COFF_LibWriter *writer, String8 obj_path, String8 obj_data);
|
||||
internal void coff_lib_writer_push_import(COFF_LibWriter *lib_writer, COFF_MachineType machine, COFF_TimeStamp time_stamp, String8 dll_name, COFF_ImportByType import_by, String8 name, U16 hint_or_ordinal, COFF_ImportType import_type);
|
||||
internal String8List coff_lib_writer_serialize(Arena *arena, COFF_LibWriter *lib_writer, COFF_TimeStamp time_stamp, U16 mode, B32 emit_second_member);
|
||||
|
||||
#endif // COFF_LIB_WRITER_H
|
||||
|
||||
@@ -0,0 +1,470 @@
|
||||
internal COFF_ObjWriter*
|
||||
coff_obj_writer_alloc(COFF_TimeStamp time_stamp, COFF_MachineType machine)
|
||||
{
|
||||
Arena *arena = arena_alloc();
|
||||
COFF_ObjWriter *obj_writer = push_array(arena, COFF_ObjWriter, 1);
|
||||
obj_writer->arena = arena;
|
||||
obj_writer->time_stamp = time_stamp;
|
||||
obj_writer->machine = machine;
|
||||
return obj_writer;
|
||||
}
|
||||
|
||||
internal void
|
||||
coff_obj_writer_release(COFF_ObjWriter **obj_writer)
|
||||
{
|
||||
arena_release((*obj_writer)->arena);
|
||||
*obj_writer = 0;
|
||||
}
|
||||
|
||||
internal String8
|
||||
coff_obj_writer_serialize(Arena *arena, COFF_ObjWriter *obj_writer)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
|
||||
String8List srl = {0};
|
||||
|
||||
String8List string_table = {0};
|
||||
U32 *string_table_size = push_array(scratch.arena, U32, 1);
|
||||
*string_table_size = sizeof(*string_table_size);
|
||||
str8_list_push(scratch.arena, &string_table, str8_struct(string_table_size));
|
||||
|
||||
//
|
||||
// assing section numbers
|
||||
//
|
||||
U64 obj_sections_count;
|
||||
COFF_ObjSection **obj_sections;
|
||||
{
|
||||
obj_sections_count = obj_writer->sect_count;
|
||||
obj_sections = push_array(scratch.arena, COFF_ObjSection *, obj_writer->sect_count);
|
||||
U64 sect_idx = 0;
|
||||
for (COFF_ObjSectionNode *sect_n = obj_writer->sect_first; sect_n != 0; sect_n = sect_n->next, sect_idx += 1) {
|
||||
COFF_ObjSection *sect = §_n->v;
|
||||
sect->section_number = sect_idx+1;
|
||||
obj_sections[sect_idx] = sect;
|
||||
|
||||
}
|
||||
}
|
||||
AssertAlways(obj_sections_count <= max_U16);
|
||||
|
||||
//
|
||||
// serialize symbol table
|
||||
//
|
||||
String8List symbol_table = {0};
|
||||
{
|
||||
U64 symbol_idx = 0;
|
||||
for (COFF_ObjSymbolNode *symbol_n = obj_writer->symbol_first; symbol_n != 0; symbol_n = symbol_n->next) {
|
||||
COFF_ObjSymbol *s = &symbol_n->v;
|
||||
|
||||
// assign symbol index
|
||||
s->idx = symbol_idx++;
|
||||
|
||||
COFF_Symbol16 *d = push_array(scratch.arena, COFF_Symbol16, 1);
|
||||
str8_list_push(scratch.arena, &symbol_table, str8_struct(d));
|
||||
|
||||
COFF_SymbolName name = {0};
|
||||
// long name
|
||||
if (s->name.size > sizeof(name.short_name)) {
|
||||
U64 string_table_offset = string_table.total_size;
|
||||
str8_list_push_cstr(scratch.arena, &string_table, s->name);
|
||||
|
||||
name.long_name.zeroes = 0;
|
||||
name.long_name.string_table_offset = safe_cast_u32(string_table_offset);
|
||||
}
|
||||
// short name
|
||||
else {
|
||||
MemoryCopyStr8(name.short_name, s->name);
|
||||
MemoryZeroTyped(name.short_name + s->name.size, sizeof(name.short_name) - s->name.size);
|
||||
}
|
||||
|
||||
// symbol header
|
||||
AssertAlways(s->aux_symbols.node_count <= max_U8);
|
||||
d->name = name;
|
||||
d->value = s->value;
|
||||
switch (s->loc.type) {
|
||||
case COFF_SymbolLocation_Null: break;
|
||||
case COFF_SymbolLocation_Section: d->section_number = safe_cast_u16(s->loc.u.section->section_number); break;
|
||||
case COFF_SymbolLocation_Abs: d->section_number = COFF_Symbol_AbsSection16; break;
|
||||
case COFF_SymbolLocation_Undef: d->section_number = COFF_Symbol_UndefinedSection; break;
|
||||
}
|
||||
d->type = s->type;
|
||||
d->storage_class = s->storage_class;
|
||||
d->aux_symbol_count = 0;
|
||||
|
||||
U64 start_symbol_idx = symbol_idx;
|
||||
if (s->storage_class == COFF_SymStorageClass_WeakExternal) {
|
||||
if (s->aux_symbols.node_count > 0) {
|
||||
COFF_ObjSymbolWeak *s_weak = (COFF_ObjSymbolWeak *)s->aux_symbols.first->string.str;
|
||||
COFF_SymbolWeakExt *d_weak = push_array(scratch.arena, COFF_SymbolWeakExt, 1);
|
||||
d_weak->tag_index = s_weak->tag->idx;
|
||||
d_weak->characteristics = s_weak->characteristics;
|
||||
|
||||
str8_list_push(scratch.arena, &symbol_table, str8_struct(d_weak));
|
||||
symbol_idx += 1;
|
||||
}
|
||||
} else if (s->storage_class == COFF_SymStorageClass_Static) {
|
||||
if (s->aux_symbols.node_count > 0) {
|
||||
Assert(s->loc.type == COFF_SymbolLocation_Section);
|
||||
COFF_ObjSection *sect = s->loc.u.section;
|
||||
|
||||
COFF_ObjSymbolSecDef *s_sd = (COFF_ObjSymbolSecDef *)s->aux_symbols.first->string.str;
|
||||
COFF_SymbolSecDef *d_sd = push_array(scratch.arena, COFF_SymbolSecDef, 1);
|
||||
|
||||
d_sd->length = safe_cast_u32(sect->data.total_size);
|
||||
d_sd->number_of_relocations = (U16)sect->reloc_count;
|
||||
d_sd->check_sum = 0;
|
||||
d_sd->number_lo = s_sd->selection == COFF_ComdatSelect_Associative ? safe_cast_u16(s_sd->associate->section_number) : 0;
|
||||
d_sd->selection = s_sd->selection;
|
||||
|
||||
str8_list_push(scratch.arena, &symbol_table, str8_struct(d_sd));
|
||||
symbol_idx += 1;
|
||||
}
|
||||
}
|
||||
|
||||
U8 processed_aux_symbol_count = (U8)(symbol_idx - start_symbol_idx);
|
||||
|
||||
for (U64 aux_idx = processed_aux_symbol_count; aux_idx < s->aux_symbols.node_count; aux_idx += 1) {
|
||||
COFF_Symbol16 *a = push_array(scratch.arena, COFF_Symbol16, 1);
|
||||
str8_list_push(scratch.arena, &symbol_table, str8_struct(a));
|
||||
}
|
||||
|
||||
d->aux_symbol_count = (U8)s->aux_symbols.node_count;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// file header
|
||||
//
|
||||
COFF_FileHeader *file_header = push_array(scratch.arena, COFF_FileHeader, 1);
|
||||
file_header->machine = obj_writer->machine;
|
||||
file_header->section_count = obj_sections_count;
|
||||
file_header->time_stamp = obj_writer->time_stamp;
|
||||
file_header->symbol_table_foff = 0;
|
||||
file_header->symbol_count = safe_cast_u32(symbol_table.node_count);
|
||||
file_header->optional_header_size = 0;
|
||||
file_header->flags = 0;
|
||||
str8_list_push(scratch.arena, &srl, str8_struct(file_header));
|
||||
|
||||
//
|
||||
// section table
|
||||
//
|
||||
|
||||
COFF_SectionHeader *sectab = push_array(scratch.arena, COFF_SectionHeader, obj_sections_count);
|
||||
str8_list_push(scratch.arena, &srl, str8_array(sectab, obj_sections_count));
|
||||
{
|
||||
for (U64 sect_idx = 0; sect_idx < obj_sections_count; sect_idx += 1) {
|
||||
COFF_ObjSection *s = obj_sections[sect_idx];
|
||||
COFF_SectionHeader *d = §ab[sect_idx];
|
||||
|
||||
// section name
|
||||
String8 sect_name = s->name;
|
||||
if (sect_name.size > sizeof(d->name)) {
|
||||
U64 sect_name_off = string_table.total_size;
|
||||
str8_list_push_cstr(scratch.arena, &string_table, sect_name);
|
||||
|
||||
sect_name = push_str8f(scratch.arena, "/%u", sect_name_off);
|
||||
AssertAlways(sect_name.size <= sizeof(d->name));
|
||||
}
|
||||
|
||||
// alloc zero nodes
|
||||
for (String8Node *data_n = s->data.first; data_n != 0; data_n = data_n->next) {
|
||||
if (data_n->string.str == 0 && data_n->string.size > 0) {
|
||||
data_n->string = str8(push_array(scratch.arena, U8, data_n->string.size), data_n->string.size);
|
||||
}
|
||||
}
|
||||
|
||||
// section data
|
||||
U64 data_foff = 0;
|
||||
U64 data_size = 0;
|
||||
if (s->data.total_size > 0) {
|
||||
data_foff = srl.total_size;
|
||||
data_size = s->data.total_size;
|
||||
str8_list_concat_in_place(&srl, &s->data);
|
||||
}
|
||||
|
||||
// section relocs
|
||||
U64 relocs_foff = 0;
|
||||
if (s->reloc_count) {
|
||||
AssertAlways(s->reloc_count <= max_U16);
|
||||
COFF_Reloc *relocs = push_array(scratch.arena, COFF_Reloc, s->reloc_count);
|
||||
U64 reloc_idx = 0;
|
||||
for (COFF_ObjRelocNode *reloc_n = s->reloc_first; reloc_n != 0; reloc_n = reloc_n->next, reloc_idx += 1) {
|
||||
COFF_ObjReloc *rs = &reloc_n->v;
|
||||
COFF_Reloc *rd = &relocs[reloc_idx];
|
||||
rd->apply_off = rs->apply_off;
|
||||
rd->isymbol = rs->symbol->idx;
|
||||
rd->type = rs->type;
|
||||
}
|
||||
relocs_foff = srl.total_size;
|
||||
str8_list_push(scratch.arena, &srl, str8_array(relocs, s->reloc_count));
|
||||
}
|
||||
|
||||
// section header
|
||||
MemoryCopyStr8(d->name, sect_name);
|
||||
MemoryZeroTyped(d->name + sect_name.size, sizeof(d->name) - sect_name.size);
|
||||
d->vsize = 0;
|
||||
d->voff = 0;
|
||||
d->fsize = data_size;
|
||||
d->foff = data_foff;
|
||||
d->relocs_foff = relocs_foff;
|
||||
d->lines_foff = 0;
|
||||
d->reloc_count = safe_cast_u32(s->reloc_count);
|
||||
d->line_count = 0;
|
||||
d->flags = s->flags;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// symbol table
|
||||
//
|
||||
if (symbol_table.total_size || string_table.total_size > sizeof(*string_table_size)) {
|
||||
file_header->symbol_table_foff = srl.total_size;
|
||||
str8_list_concat_in_place(&srl, &symbol_table);
|
||||
}
|
||||
|
||||
//
|
||||
// string table
|
||||
//
|
||||
if (string_table.total_size) {
|
||||
*string_table_size = safe_cast_u32(string_table.total_size);
|
||||
str8_list_concat_in_place(&srl, &string_table);
|
||||
}
|
||||
|
||||
//
|
||||
// join
|
||||
//
|
||||
String8 obj = str8_list_join(arena, &srl, 0);
|
||||
|
||||
scratch_end(scratch);
|
||||
return obj;
|
||||
}
|
||||
|
||||
internal COFF_ObjSection *
|
||||
coff_obj_writer_push_section(COFF_ObjWriter *obj_writer, String8 name, COFF_SectionFlags flags, String8 data)
|
||||
{
|
||||
COFF_ObjSectionNode *sect_n = push_array(obj_writer->arena, COFF_ObjSectionNode, 1);
|
||||
SLLQueuePush(obj_writer->sect_first, obj_writer->sect_last, sect_n);
|
||||
obj_writer->sect_count += 1;
|
||||
|
||||
COFF_ObjSection *sect = §_n->v;
|
||||
sect->name = name;
|
||||
sect->flags = flags;
|
||||
|
||||
if (data.size) {
|
||||
str8_list_push(obj_writer->arena, §->data, data);
|
||||
}
|
||||
|
||||
return sect;
|
||||
}
|
||||
|
||||
internal COFF_ObjSymbol *
|
||||
coff_obj_writer_push_symbol(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_SymbolLocation loc, COFF_SymbolType type, COFF_SymStorageClass storage_class)
|
||||
{
|
||||
COFF_ObjSymbolNode *n = push_array(obj_writer->arena, COFF_ObjSymbolNode, 1);
|
||||
SLLQueuePush(obj_writer->symbol_first, obj_writer->symbol_last, n);
|
||||
obj_writer->symbol_count += 1;
|
||||
|
||||
COFF_ObjSymbol *s = &n->v;
|
||||
s->name = name;
|
||||
s->value = value;
|
||||
s->loc = loc;
|
||||
s->type = type;
|
||||
s->storage_class = storage_class;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
internal COFF_ObjSymbol *
|
||||
coff_obj_writer_push_symbol_extern(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_ObjSection *section)
|
||||
{
|
||||
COFF_SymbolLocation loc = {0};
|
||||
loc.type = COFF_SymbolLocation_Section;
|
||||
loc.u.section = section;
|
||||
COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, value, loc, (COFF_SymbolType){0}, COFF_SymStorageClass_External);
|
||||
return s;
|
||||
}
|
||||
|
||||
internal COFF_ObjSymbol *
|
||||
coff_obj_writer_push_symbol_extern_func(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_ObjSection *section)
|
||||
{
|
||||
COFF_SymbolType type = { .u.msb = COFF_SymDType_Func };
|
||||
COFF_SymbolLocation loc = { .type = COFF_SymbolLocation_Section, .u.section = section };
|
||||
COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, value, loc, type, COFF_SymStorageClass_External);
|
||||
return s;
|
||||
}
|
||||
|
||||
internal COFF_ObjSymbol *
|
||||
coff_obj_writer_push_symbol_static(COFF_ObjWriter *obj_writer, String8 name, U32 off, COFF_ObjSection *section)
|
||||
{
|
||||
COFF_SymbolLocation loc = {0};
|
||||
loc.type = COFF_SymbolLocation_Section;
|
||||
loc.u.section = section;
|
||||
|
||||
COFF_SymbolType symtype = {0};
|
||||
|
||||
COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, off, loc, symtype, COFF_SymStorageClass_Static);
|
||||
return s;
|
||||
}
|
||||
|
||||
internal COFF_ObjSymbol *
|
||||
coff_obj_writer_push_symbol_secdef(COFF_ObjWriter *obj_writer, COFF_ObjSection *section, COFF_ComdatSelectType selection)
|
||||
{
|
||||
COFF_ObjSymbol *s = coff_obj_writer_push_symbol_static(obj_writer, section->name, 0, section);
|
||||
COFF_ObjSymbolSecDef *sd = push_array(obj_writer->arena, COFF_ObjSymbolSecDef, 1);
|
||||
sd->selection = selection;
|
||||
str8_list_push(obj_writer->arena, &s->aux_symbols, str8_struct(sd));
|
||||
return s;
|
||||
}
|
||||
|
||||
internal COFF_ObjSymbol *
|
||||
coff_obj_writer_push_symbol_associative(COFF_ObjWriter *obj_writer, COFF_ObjSection *head, COFF_ObjSection *associate)
|
||||
{
|
||||
COFF_ObjSymbol *s = coff_obj_writer_push_symbol_static(obj_writer, head->name, 0, head);
|
||||
COFF_ObjSymbolSecDef *sd = push_array(obj_writer->arena, COFF_ObjSymbolSecDef, 1);
|
||||
sd->selection = COFF_ComdatSelect_Associative;
|
||||
sd->associate = associate;
|
||||
str8_list_push(obj_writer->arena, &s->aux_symbols, str8_struct(sd));
|
||||
return s;
|
||||
}
|
||||
|
||||
internal COFF_ObjSymbol *
|
||||
coff_obj_writer_push_symbol_weak(COFF_ObjWriter *obj_writer, String8 name, COFF_WeakExtType characteristics, COFF_ObjSymbol *tag)
|
||||
{
|
||||
COFF_SymbolLocation loc = {0};
|
||||
COFF_SymbolType symtype = {0};
|
||||
COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, COFF_Symbol_UndefinedSection, loc, symtype, COFF_SymStorageClass_WeakExternal);
|
||||
|
||||
COFF_ObjSymbolWeak *weak_ext = push_array(obj_writer->arena, COFF_ObjSymbolWeak, 1);
|
||||
weak_ext->tag = tag;
|
||||
weak_ext->characteristics = characteristics;
|
||||
|
||||
str8_list_push(obj_writer->arena, &s->aux_symbols, str8_struct(weak_ext));
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
internal COFF_ObjSymbol *
|
||||
coff_obj_writer_push_symbol_abs(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_SymStorageClass storage_class)
|
||||
{
|
||||
COFF_SymbolLocation loc = {0};
|
||||
loc.type = COFF_SymbolLocation_Abs;
|
||||
COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, value, loc, (COFF_SymbolType){0}, storage_class);
|
||||
return s;
|
||||
}
|
||||
|
||||
internal COFF_ObjSymbol *
|
||||
coff_obj_writer_push_symbol_undef(COFF_ObjWriter *obj_writer, String8 name)
|
||||
{
|
||||
COFF_SymbolType type = {0};
|
||||
COFF_SymbolLocation loc = {0};
|
||||
loc.type = COFF_SymbolLocation_Undef;
|
||||
COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, 0, loc, type, COFF_SymStorageClass_External);
|
||||
return s;
|
||||
}
|
||||
|
||||
internal COFF_ObjSymbol *
|
||||
coff_obj_writer_push_symbol_undef_func(COFF_ObjWriter *obj_writer, String8 name)
|
||||
{
|
||||
COFF_SymbolType type = {0};
|
||||
type.u.msb = COFF_SymDType_Func;
|
||||
COFF_SymbolLocation loc = {0};
|
||||
loc.type = COFF_SymbolLocation_Undef;
|
||||
COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, 0, loc, type, COFF_SymStorageClass_External);
|
||||
return s;
|
||||
}
|
||||
|
||||
internal COFF_ObjSymbol *
|
||||
coff_obj_writer_push_symbol_undef_sect(COFF_ObjWriter *obj_writer, String8 name, U32 value)
|
||||
{
|
||||
COFF_SymbolType type = {0};
|
||||
COFF_SymbolLocation loc = {0};
|
||||
loc.type = COFF_SymbolLocation_Undef;
|
||||
COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, value, loc, type, COFF_SymStorageClass_Section);
|
||||
return s;
|
||||
}
|
||||
|
||||
internal COFF_ObjSymbol *
|
||||
coff_obj_writer_push_symbol_sect(COFF_ObjWriter *obj_writer, String8 name, COFF_ObjSection *sect)
|
||||
{
|
||||
COFF_SymbolType type = {0};
|
||||
COFF_SymbolLocation loc = {0};
|
||||
loc.type = COFF_SymbolLocation_Section;
|
||||
loc.u.section = sect;
|
||||
|
||||
// strip align flags
|
||||
COFF_SectionFlags expected_flags = sect->flags & ~(COFF_SectionFlag_AlignMask << COFF_SectionFlag_AlignShift);
|
||||
|
||||
COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, expected_flags, loc, type, COFF_SymStorageClass_Section);
|
||||
return s;
|
||||
}
|
||||
|
||||
internal COFF_ObjSymbol *
|
||||
coff_obj_writer_push_symbol_common(COFF_ObjWriter *obj_writer, String8 name, U32 size)
|
||||
{
|
||||
COFF_SymbolType type = {0};
|
||||
COFF_SymbolLocation loc = {0};
|
||||
loc.type = COFF_SymbolLocation_Common;
|
||||
COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, size, loc, type, COFF_SymStorageClass_External);
|
||||
return s;
|
||||
}
|
||||
|
||||
internal COFF_ObjReloc*
|
||||
coff_obj_writer_section_push_reloc(COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol, COFF_RelocType type)
|
||||
{
|
||||
COFF_ObjRelocNode *reloc_n = push_array(obj_writer->arena, COFF_ObjRelocNode, 1);
|
||||
SLLQueuePush(sect->reloc_first, sect->reloc_last, reloc_n);
|
||||
sect->reloc_count += 1;
|
||||
|
||||
COFF_ObjReloc *reloc = &reloc_n->v;
|
||||
reloc->apply_off = apply_off;
|
||||
reloc->symbol = symbol;
|
||||
reloc->type = type;
|
||||
|
||||
return reloc;
|
||||
}
|
||||
|
||||
internal COFF_ObjReloc *
|
||||
coff_obj_writer_section_push_reloc_addr(COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol)
|
||||
{
|
||||
COFF_RelocType reloc_type = 0;
|
||||
switch (obj_writer->machine) {
|
||||
case COFF_MachineType_Unknown: break;
|
||||
case COFF_MachineType_X64: reloc_type = COFF_Reloc_X64_Addr64; break;
|
||||
default: { NotImplemented; } break;
|
||||
}
|
||||
return coff_obj_writer_section_push_reloc(obj_writer, sect, apply_off, symbol, reloc_type);
|
||||
}
|
||||
|
||||
internal COFF_ObjReloc *
|
||||
coff_obj_writer_section_push_reloc_voff(COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol)
|
||||
{
|
||||
COFF_RelocType reloc_type = 0;
|
||||
switch (obj_writer->machine) {
|
||||
case COFF_MachineType_Unknown: break;
|
||||
case COFF_MachineType_X64: reloc_type = COFF_Reloc_X64_Addr32Nb; break;
|
||||
default: { NotImplemented; } break;
|
||||
}
|
||||
return coff_obj_writer_section_push_reloc(obj_writer, sect, apply_off, symbol, reloc_type);
|
||||
}
|
||||
|
||||
internal void
|
||||
coff_obj_writer_push_directive(COFF_ObjWriter *obj_writer, String8 directive)
|
||||
{
|
||||
if (obj_writer->drectve_sect == 0) {
|
||||
local_persist const U8 bom_sig[] = { ' ', ' ', ' ' };
|
||||
obj_writer->drectve_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".drectve"), COFF_SectionFlag_LnkInfo|COFF_SectionFlag_LnkRemove|COFF_SectionFlag_Align1Bytes, str8_array_fixed(bom_sig));
|
||||
}
|
||||
String8List *data = &obj_writer->drectve_sect->data;
|
||||
str8_list_push(obj_writer->arena, data, directive);
|
||||
str8_list_pushf(obj_writer->arena, data, " ");
|
||||
}
|
||||
|
||||
internal int
|
||||
coff_obj_section_is_before(void *raw_a, void *raw_b)
|
||||
{
|
||||
COFF_ObjSection **a = raw_a;
|
||||
COFF_ObjSection **b = raw_b;
|
||||
return (*a)->section_number < (*b)->section_number;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
#ifndef COFF_OBJ_WRITER_H
|
||||
#define COFF_OBJ_WRITER_H
|
||||
|
||||
typedef enum
|
||||
{
|
||||
COFF_SymbolLocation_Null,
|
||||
COFF_SymbolLocation_Section,
|
||||
COFF_SymbolLocation_Abs,
|
||||
COFF_SymbolLocation_Undef,
|
||||
COFF_SymbolLocation_Common,
|
||||
} COFF_SymbolLocationType;
|
||||
|
||||
typedef struct COFF_SymbolLocation
|
||||
{
|
||||
COFF_SymbolLocationType type;
|
||||
union {
|
||||
struct COFF_ObjSection *section;
|
||||
} u;
|
||||
} COFF_SymbolLocation;
|
||||
|
||||
typedef struct COFF_ObjSymbolWeak
|
||||
{
|
||||
struct COFF_ObjSymbol *tag;
|
||||
COFF_WeakExtType characteristics;
|
||||
} COFF_ObjSymbolWeak;
|
||||
|
||||
typedef struct COFF_ObjSymbolSecDef
|
||||
{
|
||||
COFF_ComdatSelectType selection;
|
||||
struct COFF_ObjSection *associate;
|
||||
} COFF_ObjSymbolSecDef;
|
||||
|
||||
typedef struct COFF_ObjSymbol
|
||||
{
|
||||
String8 name;
|
||||
U32 value;
|
||||
COFF_SymbolLocation loc;
|
||||
COFF_SymbolType type;
|
||||
COFF_SymStorageClass storage_class;
|
||||
String8List aux_symbols;
|
||||
U32 idx;
|
||||
} COFF_ObjSymbol;
|
||||
|
||||
typedef struct COFF_ObjSymbolNode
|
||||
{
|
||||
struct COFF_ObjSymbolNode *next;
|
||||
COFF_ObjSymbol v;
|
||||
} COFF_ObjSymbolNode;
|
||||
|
||||
typedef struct COFF_ObjReloc
|
||||
{
|
||||
U32 apply_off;
|
||||
COFF_ObjSymbol *symbol;
|
||||
COFF_RelocType type;
|
||||
} COFF_ObjReloc;
|
||||
|
||||
typedef struct COFF_ObjRelocNode
|
||||
{
|
||||
struct COFF_ObjRelocNode *next;
|
||||
COFF_ObjReloc v;
|
||||
} COFF_ObjRelocNode;
|
||||
|
||||
typedef struct COFF_ObjSection
|
||||
{
|
||||
String8 name;
|
||||
String8List data;
|
||||
COFF_SectionFlags flags;
|
||||
|
||||
U64 reloc_count;
|
||||
COFF_ObjRelocNode *reloc_first;
|
||||
COFF_ObjRelocNode *reloc_last;
|
||||
|
||||
U32 section_number;
|
||||
} COFF_ObjSection;
|
||||
|
||||
typedef struct COFF_ObjSectionNode
|
||||
{
|
||||
struct COFF_ObjSectionNode *next;
|
||||
COFF_ObjSection v;
|
||||
} COFF_ObjSectionNode;
|
||||
|
||||
typedef struct COFF_ObjWriter
|
||||
{
|
||||
Arena *arena;
|
||||
COFF_TimeStamp time_stamp;
|
||||
COFF_MachineType machine;
|
||||
U64 symbol_count;
|
||||
COFF_ObjSymbolNode *symbol_first;
|
||||
COFF_ObjSymbolNode *symbol_last;
|
||||
U64 sect_count;
|
||||
COFF_ObjSectionNode *sect_first;
|
||||
COFF_ObjSectionNode *sect_last;
|
||||
COFF_ObjSection *drectve_sect;
|
||||
} COFF_ObjWriter;
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal COFF_ObjWriter * coff_obj_writer_alloc(COFF_TimeStamp time_stamp, COFF_MachineType machine);
|
||||
internal void coff_obj_writer_release(COFF_ObjWriter **obj_writer);
|
||||
internal String8 coff_obj_writer_serialize(Arena *arena, COFF_ObjWriter *obj_writer);
|
||||
|
||||
internal COFF_ObjSection * coff_obj_writer_push_section(COFF_ObjWriter *obj_writer, String8 name, COFF_SectionFlags flags, String8 data);
|
||||
|
||||
internal COFF_ObjSymbol* coff_obj_writer_push_symbol(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_SymbolLocation loc, COFF_SymbolType type, COFF_SymStorageClass storage_class);
|
||||
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_extern_func(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_ObjSection *section);
|
||||
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_extern(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_ObjSection *section);
|
||||
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_static(COFF_ObjWriter *obj_writer, String8 name, U32 off, COFF_ObjSection *section);
|
||||
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_secdef(COFF_ObjWriter *obj_writer, COFF_ObjSection *section, COFF_ComdatSelectType selection);
|
||||
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_associative(COFF_ObjWriter *obj_writer, COFF_ObjSection *head, COFF_ObjSection *associate);
|
||||
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_weak(COFF_ObjWriter *obj_writer, String8 name, COFF_WeakExtType characteristics, COFF_ObjSymbol *tag);
|
||||
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_abs(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_SymStorageClass storage_class);
|
||||
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_undef(COFF_ObjWriter *obj_writer, String8 name);
|
||||
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_undef_func(COFF_ObjWriter *obj_writer, String8 name);
|
||||
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_undef_sect(COFF_ObjWriter *obj_writer, String8 name, U32 value);
|
||||
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_sect(COFF_ObjWriter *obj_writer, String8 name, COFF_ObjSection *sect);
|
||||
internal COFF_ObjSymbol * coff_obj_writer_push_symbol_common(COFF_ObjWriter *obj_writer, String8 name, U32 size);
|
||||
|
||||
internal COFF_ObjReloc * coff_obj_writer_section_push_reloc(COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol, COFF_RelocType reloc_type);
|
||||
internal COFF_ObjReloc * coff_obj_writer_section_push_reloc_addr(COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol);
|
||||
internal COFF_ObjReloc * coff_obj_writer_section_push_reloc_voff(COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol);
|
||||
|
||||
internal void coff_obj_writer_push_directive(COFF_ObjWriter *obj_writer, String8 directive);
|
||||
|
||||
#endif // COFF_OBJ_WRITER_H
|
||||
|
||||
@@ -121,6 +121,18 @@ coff_file_header_info_from_data(String8 raw_coff)
|
||||
return info;
|
||||
}
|
||||
|
||||
internal COFF_SectionHeader **
|
||||
coff_section_table_from_data(Arena *arena, String8 data, Rng1U64 section_table_range)
|
||||
{
|
||||
U64 section_count = dim_1u64(section_table_range) / sizeof(COFF_SectionHeader);
|
||||
COFF_SectionHeader **section_table = push_array_no_zero(arena, COFF_SectionHeader *, section_count+1);
|
||||
section_table[0] = push_array(arena, COFF_SectionHeader, 1);
|
||||
for (U64 i = 0; i < section_count; ++i) {
|
||||
section_table[i+1] = str8_deserial_get_raw_ptr(data, section_table_range.min + i*sizeof(COFF_SectionHeader), sizeof(COFF_SectionHeader));
|
||||
}
|
||||
return section_table;
|
||||
}
|
||||
|
||||
internal COFF_ParsedSymbol
|
||||
coff_parse_symbol32(String8 string_table, COFF_Symbol32 *sym32)
|
||||
{
|
||||
@@ -131,6 +143,7 @@ coff_parse_symbol32(String8 string_table, COFF_Symbol32 *sym32)
|
||||
result.type = sym32->type;
|
||||
result.storage_class = sym32->storage_class;
|
||||
result.aux_symbol_count = sym32->aux_symbol_count;
|
||||
result.raw_symbol = sym32;
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -150,9 +163,22 @@ coff_parse_symbol16(String8 string_table, COFF_Symbol16 *sym16)
|
||||
result.type = sym16->type;
|
||||
result.storage_class = sym16->storage_class;
|
||||
result.aux_symbol_count = sym16->aux_symbol_count;
|
||||
result.raw_symbol = sym16;
|
||||
return result;
|
||||
}
|
||||
|
||||
internal COFF_ParsedSymbol
|
||||
coff_parse_symbol(COFF_FileHeaderInfo header, String8 string_table, String8 symbol_table, U32 symbol_idx)
|
||||
{
|
||||
COFF_ParsedSymbol symbol;
|
||||
if (header.is_big_obj) {
|
||||
symbol = coff_parse_symbol32(string_table, (COFF_Symbol32 *)symbol_table.str + symbol_idx);
|
||||
} else {
|
||||
symbol = coff_parse_symbol16(string_table, (COFF_Symbol16 *)symbol_table.str + symbol_idx);
|
||||
}
|
||||
return symbol;
|
||||
}
|
||||
|
||||
internal COFF_Symbol32Array
|
||||
coff_symbol_array_from_data_16(Arena *arena, String8 raw_coff, U64 symbol_array_off, U64 symbol_count)
|
||||
{
|
||||
@@ -253,6 +279,49 @@ coff_interp_symbol(U32 section_number, U32 value, COFF_SymStorageClass storage_c
|
||||
return COFF_SymbolValueInterp_Regular;
|
||||
}
|
||||
|
||||
internal COFF_SymbolValueInterpType
|
||||
coff_interp_from_parsed_symbol(COFF_ParsedSymbol symbol)
|
||||
{
|
||||
return coff_interp_symbol(symbol.section_number, symbol.value, symbol.storage_class);
|
||||
}
|
||||
|
||||
internal void
|
||||
coff_parse_secdef(COFF_ParsedSymbol symbol, B32 is_big_obj, COFF_ComdatSelectType *selection_out, U32 *number_out, U32 *length_out, U32 *check_sum_out)
|
||||
{
|
||||
Assert(coff_interp_symbol(symbol.section_number, symbol.value, symbol.storage_class) == COFF_SymbolValueInterp_Regular);
|
||||
Assert(symbol.aux_symbol_count > 0);
|
||||
|
||||
if (is_big_obj) {
|
||||
COFF_SymbolSecDef *sd = (COFF_SymbolSecDef *)((COFF_Symbol32 *)symbol.raw_symbol + 1);
|
||||
if (selection_out) *selection_out = sd->selection;
|
||||
if (length_out) *length_out = sd->length;
|
||||
if (check_sum_out) *check_sum_out = sd->check_sum;
|
||||
if (number_out) *number_out = Compose32Bit(sd->number_hi, sd->number_lo);
|
||||
} else {
|
||||
COFF_SymbolSecDef *sd = (COFF_SymbolSecDef *)((COFF_Symbol16 *)symbol.raw_symbol + 1);
|
||||
if (selection_out) *selection_out = sd->selection;
|
||||
if (length_out) *length_out = sd->length;
|
||||
if (check_sum_out) *check_sum_out = sd->check_sum;
|
||||
if (number_out) *number_out = sd->number_lo;
|
||||
}
|
||||
}
|
||||
|
||||
internal COFF_SymbolWeakExt *
|
||||
coff_parse_weak_tag(COFF_ParsedSymbol symbol, B32 is_big_obj)
|
||||
{
|
||||
Assert(coff_interp_symbol(symbol.section_number, symbol.value, symbol.storage_class) == COFF_SymbolValueInterp_Weak);
|
||||
Assert(symbol.aux_symbol_count > 0);
|
||||
|
||||
void *tag;
|
||||
if (is_big_obj) {
|
||||
tag = (COFF_SymbolWeakExt *)((COFF_Symbol32 *)symbol.raw_symbol + 1);
|
||||
} else {
|
||||
tag = (COFF_SymbolWeakExt *)((COFF_Symbol16 *)symbol.raw_symbol + 1);
|
||||
}
|
||||
|
||||
return tag;
|
||||
}
|
||||
|
||||
internal COFF_RelocNode *
|
||||
coff_reloc_list_push(Arena *arena, COFF_RelocList *list, COFF_Reloc reloc)
|
||||
{
|
||||
|
||||
+19
-8
@@ -49,12 +49,13 @@ typedef struct COFF_Symbol32Array
|
||||
|
||||
typedef struct COFF_ParsedSymbol
|
||||
{
|
||||
String8 name;
|
||||
U32 value;
|
||||
U32 section_number;
|
||||
COFF_SymbolType type;
|
||||
COFF_SymStorageClass storage_class;
|
||||
U8 aux_symbol_count;
|
||||
String8 name;
|
||||
U64 value;
|
||||
U32 section_number;
|
||||
COFF_SymbolType type;
|
||||
COFF_SymStorageClass storage_class;
|
||||
U8 aux_symbol_count;
|
||||
void *raw_symbol;
|
||||
} COFF_ParsedSymbol;
|
||||
|
||||
typedef U32 COFF_SymbolValueInterpType;
|
||||
@@ -194,8 +195,8 @@ typedef struct COFF_ParsedArchiveImportHeader
|
||||
typedef struct COFF_ArchiveMember
|
||||
{
|
||||
COFF_ParsedArchiveMemberHeader header;
|
||||
U64 offset;
|
||||
String8 data;
|
||||
U64 offset;
|
||||
String8 data;
|
||||
} COFF_ArchiveMember;
|
||||
|
||||
typedef struct COFF_ArchiveFirstMember
|
||||
@@ -247,11 +248,17 @@ 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);
|
||||
|
||||
////////////////////////////////
|
||||
// Section
|
||||
|
||||
internal COFF_SectionHeader ** coff_section_table_from_data(Arena *arena, String8 data, Rng1U64 section_table_range);
|
||||
|
||||
////////////////////////////////
|
||||
// Symbol
|
||||
|
||||
internal COFF_ParsedSymbol coff_parse_symbol32(String8 string_table, COFF_Symbol32 *sym32);
|
||||
internal COFF_ParsedSymbol coff_parse_symbol16(String8 string_table, COFF_Symbol16 *sym16);
|
||||
internal COFF_ParsedSymbol coff_parse_symbol(COFF_FileHeaderInfo header, String8 string_table, String8 symbol_table, U32 symbol_idx);
|
||||
|
||||
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);
|
||||
@@ -260,6 +267,10 @@ internal COFF_Symbol32Array coff_symbol_array_from_data (Arena *arena, String8
|
||||
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);
|
||||
internal COFF_SymbolValueInterpType coff_interp_from_parsed_symbol(COFF_ParsedSymbol symbol);
|
||||
|
||||
internal void coff_parse_secdef(COFF_ParsedSymbol symbol, B32 is_big_obj, COFF_ComdatSelectType *selection_out, U32 *number_out, U32 *length_out, U32 *check_sum_out);
|
||||
internal COFF_SymbolWeakExt * coff_parse_weak_tag(COFF_ParsedSymbol symbol, B32 is_big_obj);
|
||||
|
||||
////////////////////////////////
|
||||
// Reloc
|
||||
|
||||
+376
-148
@@ -9,14 +9,16 @@
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Type Functions
|
||||
|
||||
#if !defined(XXH_IMPLEMENTATION)
|
||||
# define XXH_IMPLEMENTATION
|
||||
# define XXH_STATIC_LINKING_ONLY
|
||||
# include "third_party/xxHash/xxhash.h"
|
||||
#endif
|
||||
|
||||
internal U64
|
||||
ctrl_hash_from_string(String8 string)
|
||||
{
|
||||
U64 result = 5381;
|
||||
for(U64 i = 0; i < string.size; i += 1)
|
||||
{
|
||||
result = ((result << 5) + result) + string.str[i];
|
||||
}
|
||||
U64 result = XXH3_64bits_withSeed(string.str, string.size, 5381);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1366,14 +1368,16 @@ ctrl_entity_store_apply_events(CTRL_EntityCtxRWStore *store, CTRL_EventList *lis
|
||||
}break;
|
||||
case CTRL_EventKind_ModuleDebugInfoPathChange:
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
CTRL_Entity *module = ctrl_entity_from_handle(&store->ctx, event->entity);
|
||||
CTRL_Entity *debug_info_path = ctrl_entity_child_from_kind(module, CTRL_EntityKind_DebugInfoPath);
|
||||
if(debug_info_path == &ctrl_entity_nil)
|
||||
{
|
||||
debug_info_path = ctrl_entity_alloc(store, module, CTRL_EntityKind_DebugInfoPath, Arch_Null, ctrl_handle_zero(), 0);
|
||||
}
|
||||
ctrl_entity_equip_string(store, debug_info_path, event->string);
|
||||
ctrl_entity_equip_string(store, debug_info_path, path_normalized_from_string(scratch.arena, event->string));
|
||||
debug_info_path->timestamp = event->timestamp;
|
||||
scratch_end(scratch);
|
||||
}break;
|
||||
|
||||
//- rjf: dynamic, program-created breakpoints
|
||||
@@ -1552,6 +1556,7 @@ ctrl_init(void)
|
||||
ctrl_state->ctrl_thread_entity_ctx_rw_mutex = os_rw_mutex_alloc();
|
||||
ctrl_state->ctrl_thread_entity_store = ctrl_entity_ctx_rw_store_alloc();
|
||||
ctrl_state->ctrl_thread_eval_cache = e_cache_alloc();
|
||||
ctrl_state->ctrl_thread_msg_process_arena = arena_alloc();
|
||||
ctrl_state->dmn_event_arena = arena_alloc();
|
||||
ctrl_state->user_entry_point_arena = arena_alloc();
|
||||
ctrl_state->dbg_dir_arena = arena_alloc();
|
||||
@@ -1681,14 +1686,14 @@ ctrl_key_from_process_vaddr_range(CTRL_Handle process, Rng1U64 vaddr_range, B32
|
||||
{
|
||||
id_exists = 1;
|
||||
id_stale = (n->mem_gen < mem_gen);
|
||||
id_working = (ins_atomic_u64_eval(&n->working_count) != 0);
|
||||
id_working = (n->working_count != 0);
|
||||
goto end_fast_lookup;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
end_fast_lookup:;
|
||||
if(os_now_microseconds() >= endt_us || !id_working)
|
||||
if(!id_stale || !id_working || os_now_microseconds() >= endt_us)
|
||||
{
|
||||
break;
|
||||
}
|
||||
@@ -1715,7 +1720,6 @@ ctrl_key_from_process_vaddr_range(CTRL_Handle process, Rng1U64 vaddr_range, B32
|
||||
if(!id_exists || (id_exists && id_stale && !id_working))
|
||||
{
|
||||
B32 node_needs_stream = 0;
|
||||
U64 *node_working_count = 0;
|
||||
OS_MutexScopeW(process_stripe->rw_mutex)
|
||||
{
|
||||
for(CTRL_ProcessMemoryCacheNode *process_n = process_slot->first; process_n != 0; process_n = process_n->next)
|
||||
@@ -1744,13 +1748,12 @@ ctrl_key_from_process_vaddr_range(CTRL_Handle process, Rng1U64 vaddr_range, B32
|
||||
}
|
||||
else
|
||||
{
|
||||
node_needs_stream = (range_n->mem_gen < mem_gen);
|
||||
node_needs_stream = (range_n->mem_gen < mem_gen && range_n->working_count == 0);
|
||||
}
|
||||
if(node_needs_stream)
|
||||
{
|
||||
ins_atomic_u64_inc_eval(&range_n->working_count);
|
||||
range_n->working_count += 1;
|
||||
}
|
||||
node_working_count = &range_n->working_count;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1759,10 +1762,14 @@ ctrl_key_from_process_vaddr_range(CTRL_Handle process, Rng1U64 vaddr_range, B32
|
||||
{
|
||||
if(ctrl_u2ms_enqueue_req(key, process, vaddr_range, zero_terminated, endt_us))
|
||||
{
|
||||
async_push_work(ctrl_mem_stream_work, .working_counter = node_working_count);
|
||||
// NOTE(rjf): debugging
|
||||
#if 0
|
||||
raddbg_log("[0x%I64x, 0x%I64x) push: (gen: %I64u)\n", vaddr_range.min, vaddr_range.max, mem_gen);
|
||||
#endif
|
||||
async_push_work(ctrl_mem_stream_work);
|
||||
requested = 1;
|
||||
}
|
||||
else OS_MutexScopeR(process_stripe->rw_mutex)
|
||||
else OS_MutexScopeW(process_stripe->rw_mutex)
|
||||
{
|
||||
for(CTRL_ProcessMemoryCacheNode *process_n = process_slot->first; process_n != 0; process_n = process_n->next)
|
||||
{
|
||||
@@ -1770,23 +1777,29 @@ ctrl_key_from_process_vaddr_range(CTRL_Handle process, Rng1U64 vaddr_range, B32
|
||||
{
|
||||
U64 range_slot_idx = range_hash%process_n->range_hash_slots_count;
|
||||
CTRL_ProcessMemoryRangeHashSlot *range_slot = &process_n->range_hash_slots[range_slot_idx];
|
||||
CTRL_ProcessMemoryRangeHashNode *range_n = 0;
|
||||
for(CTRL_ProcessMemoryRangeHashNode *n = range_slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(hs_id_match(n->id, id))
|
||||
{
|
||||
ins_atomic_u64_dec_eval(&n->working_count);
|
||||
goto end_fail_work;
|
||||
n->working_count -= 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
end_fail_work:;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: step 4: if we didn't request, and if we aren't working, then exit
|
||||
if(!requested && !id_working)
|
||||
if(!requested)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
//- rjf: step 5: exit if out of time
|
||||
if(os_now_microseconds() >= endt_us)
|
||||
{
|
||||
break;
|
||||
}
|
||||
@@ -1971,6 +1984,12 @@ ctrl_process_write(CTRL_Handle process, Rng1U64 range, void *src)
|
||||
ProfBeginFunction();
|
||||
B32 result = dmn_process_write(process.dmn_handle, range, src);
|
||||
|
||||
//- rjf: success -> bump generation
|
||||
if(result)
|
||||
{
|
||||
ins_atomic_u64_inc_eval(&ctrl_state->mem_gen);
|
||||
}
|
||||
|
||||
//- rjf: success -> wait for cache updates, for small regions - prefer relatively seamless
|
||||
// writes within calling frame's "view" of the memory, at the expense of a small amount of
|
||||
// time.
|
||||
@@ -2077,7 +2096,7 @@ ctrl_reg_block_from_thread(Arena *arena, CTRL_EntityCtx *ctx, CTRL_Handle handle
|
||||
// rjf: copy from node
|
||||
if(node)
|
||||
{
|
||||
U64 current_reg_gen = dmn_reg_gen();
|
||||
U64 current_reg_gen = ctrl_reg_gen();
|
||||
B32 need_stale = 1;
|
||||
if(node->reg_gen != current_reg_gen && dmn_thread_read_reg_block(handle.dmn_handle, result))
|
||||
{
|
||||
@@ -2135,6 +2154,10 @@ ctrl_thread_write_reg_block(CTRL_Handle thread, void *block)
|
||||
{
|
||||
// TODO(rjf): @callstacks immediately reflect this in the call stack cache
|
||||
B32 good = dmn_thread_write_reg_block(thread.dmn_handle, block);
|
||||
if(good)
|
||||
{
|
||||
ins_atomic_u64_inc_eval(&ctrl_state->reg_gen);
|
||||
}
|
||||
return good;
|
||||
}
|
||||
|
||||
@@ -3287,7 +3310,7 @@ ctrl_call_stack_from_unwind(Arena *arena, CTRL_Entity *process, CTRL_Unwind *bas
|
||||
CTRL_Entity *module = ctrl_module_from_process_vaddr(process, rip_vaddr);
|
||||
U64 rip_voff = ctrl_voff_from_vaddr(module, rip_vaddr);
|
||||
DI_Key dbgi_key = ctrl_dbgi_key_from_module(module);
|
||||
RDI_Parsed *rdi = di_rdi_from_key(di_scope, &dbgi_key, 0);
|
||||
RDI_Parsed *rdi = di_rdi_from_key(di_scope, &dbgi_key, 1, 0);
|
||||
RDI_Scope *scope = rdi_scope_from_voff(rdi, rip_voff);
|
||||
|
||||
// rjf: build inline frames (minus parent & inline depth)
|
||||
@@ -3405,96 +3428,89 @@ ctrl_call_stack_from_thread(CTRL_Scope *scope, CTRL_EntityCtx *entity_ctx, CTRL_
|
||||
//- rjf: loop: try to grab cached call stack; request; wait
|
||||
//
|
||||
B32 can_request = !ins_atomic_u64_eval(&ctrl_state->ctrl_thread_run_state);
|
||||
B32 did_request = 0;
|
||||
OS_MutexScopeR(stripe->rw_mutex)
|
||||
for(U64 retry_idx = 0;; retry_idx += 1)
|
||||
{
|
||||
CTRL_CallStackCacheNode *taken_node = 0;
|
||||
for(;;)
|
||||
//- rjf: [read-only] try to look for current call stack; wait if working
|
||||
B32 node_exists = 0;
|
||||
B32 node_stale = 1;
|
||||
B32 node_working = 0;
|
||||
OS_MutexScopeR(stripe->rw_mutex) for(;;)
|
||||
{
|
||||
////////////////////////////
|
||||
//- rjf: try to grab cached
|
||||
//
|
||||
B32 is_good = 0;
|
||||
B32 is_stale = 1;
|
||||
B32 is_working = 0;
|
||||
CTRL_CallStackCacheNode *node = 0;
|
||||
for(CTRL_CallStackCacheNode *n = slot->first; n != 0; n = n->next)
|
||||
{
|
||||
for(CTRL_CallStackCacheNode *n = slot->first; n != 0; n = n->next)
|
||||
if(ctrl_handle_match(n->thread, handle))
|
||||
{
|
||||
if(ctrl_handle_match(n->thread, handle))
|
||||
{
|
||||
node = n;
|
||||
is_good = 1;
|
||||
is_stale = (reg_gen > n->reg_gen || mem_gen > n->mem_gen);
|
||||
is_working = (n->working_count > 0);
|
||||
call_stack = n->call_stack;
|
||||
taken_node = node;
|
||||
break;
|
||||
}
|
||||
node = n;
|
||||
node_exists = 1;
|
||||
node_stale = (reg_gen > n->reg_gen || mem_gen > n->mem_gen);
|
||||
node_working = (n->working_count > 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////
|
||||
//- rjf: create node if needed
|
||||
//
|
||||
if(!is_good) OS_MutexScopeRWPromote(stripe->rw_mutex)
|
||||
{
|
||||
node = 0;
|
||||
for(CTRL_CallStackCacheNode *n = slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(ctrl_handle_match(n->thread, handle))
|
||||
{
|
||||
node = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(node == 0)
|
||||
{
|
||||
node = push_array(stripe->arena, CTRL_CallStackCacheNode, 1);
|
||||
DLLPushBack(slot->first, slot->last, node);
|
||||
node->thread = thread->handle;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////
|
||||
//- rjf: request if needed
|
||||
//
|
||||
if(can_request && node != 0 && !is_working && is_stale)
|
||||
{
|
||||
if(ctrl_u2csb_enqueue_req(thread->handle, endt_us))
|
||||
{
|
||||
did_request = 1;
|
||||
is_working = 1;
|
||||
ins_atomic_u64_inc_eval(&node->working_count);
|
||||
async_push_work(ctrl_call_stack_build_work, .priority = high_priority ? ASYNC_Priority_High : ASYNC_Priority_Low);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////
|
||||
//- rjf: good, or timeout? -> exit
|
||||
//
|
||||
if(!can_request || !is_stale || os_now_microseconds() >= endt_us)
|
||||
if(node_exists && (!can_request || !node_stale || os_now_microseconds() >= endt_us))
|
||||
{
|
||||
call_stack = node->call_stack;
|
||||
ctrl_scope_touch_call_stack_node__stripe_r_guarded(scope, stripe, node);
|
||||
break;
|
||||
}
|
||||
|
||||
////////////////////////////
|
||||
//- rjf: time to wait for new result? -> wait
|
||||
//
|
||||
if(did_request && !is_working)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if(did_request)
|
||||
else if(node_working)
|
||||
{
|
||||
os_condition_variable_wait_rw_r(stripe->cv, stripe->rw_mutex, endt_us);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(taken_node != 0)
|
||||
|
||||
//- rjf: out of time => exit
|
||||
if(retry_idx > 0 && os_now_microseconds() >= endt_us)
|
||||
{
|
||||
ctrl_scope_touch_call_stack_node__stripe_r_guarded(scope, stripe, taken_node);
|
||||
break;
|
||||
}
|
||||
|
||||
//- rjf: [write] node does not exist => create; request if new or stale
|
||||
B32 need_request = (!node_exists || node_stale);
|
||||
CTRL_CallStackCacheNode *node_to_request = 0;
|
||||
if(can_request && need_request) OS_MutexScopeW(stripe->rw_mutex)
|
||||
{
|
||||
CTRL_CallStackCacheNode *node = 0;
|
||||
for(CTRL_CallStackCacheNode *n = slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(ctrl_handle_match(n->thread, handle))
|
||||
{
|
||||
node = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(node == 0)
|
||||
{
|
||||
node = push_array(stripe->arena, CTRL_CallStackCacheNode, 1);
|
||||
DLLPushBack(slot->first, slot->last, node);
|
||||
node->thread = thread->handle;
|
||||
}
|
||||
if(node->working_count == 0)
|
||||
{
|
||||
node->working_count += 1;
|
||||
node_to_request = node;
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: request if needed
|
||||
if(node_to_request != 0)
|
||||
{
|
||||
if(ctrl_u2csb_enqueue_req(thread->handle, endt_us))
|
||||
{
|
||||
async_push_work(ctrl_call_stack_build_work, .priority = high_priority ? ASYNC_Priority_High : ASYNC_Priority_Low);
|
||||
}
|
||||
else OS_MutexScopeW(stripe->rw_mutex)
|
||||
{
|
||||
node_to_request->working_count -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return call_stack;
|
||||
}
|
||||
|
||||
@@ -3510,26 +3526,26 @@ ctrl_halt(void)
|
||||
////////////////////////////////
|
||||
//~ rjf: Shared Accessor Functions
|
||||
|
||||
//- rjf: run generation counter
|
||||
//- rjf: generation counters
|
||||
|
||||
internal U64
|
||||
ctrl_run_gen(void)
|
||||
{
|
||||
U64 result = dmn_run_gen();
|
||||
U64 result = ins_atomic_u64_eval(&ctrl_state->run_gen);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal U64
|
||||
ctrl_mem_gen(void)
|
||||
{
|
||||
U64 result = dmn_mem_gen();
|
||||
U64 result = ins_atomic_u64_eval(&ctrl_state->mem_gen);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal U64
|
||||
ctrl_reg_gen(void)
|
||||
{
|
||||
U64 result = dmn_reg_gen();
|
||||
U64 result = ins_atomic_u64_eval(&ctrl_state->reg_gen);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -3709,9 +3725,75 @@ ctrl_thread__entry_point(void *p)
|
||||
log_infof("user2ctrl_msg:{kind:\"%S\"}\n", ctrl_string_from_msg_kind(msg->kind));
|
||||
}
|
||||
|
||||
//- rjf: unpack per-message parameterizations & store
|
||||
//- rjf: reset per-message state
|
||||
arena_clear(ctrl_state->ctrl_thread_msg_process_arena);
|
||||
ctrl_state->module_req_cache_slots_count = 1024;
|
||||
ctrl_state->module_req_cache_slots = push_array(ctrl_state->ctrl_thread_msg_process_arena, CTRL_ModuleReqCacheNode *, ctrl_state->module_req_cache_slots_count);
|
||||
MemoryZeroStruct(&ctrl_state->msg_user_bp_touched_files);
|
||||
MemoryZeroStruct(&ctrl_state->msg_user_bp_touched_symbols);
|
||||
MemoryCopyArray(ctrl_state->exception_code_filters, msg->exception_code_filters);
|
||||
|
||||
//- rjf: gather all touched symbols by user breakpoints
|
||||
{
|
||||
MemoryCopyArray(ctrl_state->exception_code_filters, msg->exception_code_filters);
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
for(CTRL_UserBreakpointNode *n = msg->user_bps.first; n != 0; n = n->next)
|
||||
{
|
||||
if(n->v.kind != CTRL_UserBreakpointKind_Expression)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
E_Parse addr_parse = e_push_parse_from_string(scratch.arena, n->v.string);
|
||||
E_Parse cnd_parse = e_push_parse_from_string(scratch.arena, n->v.condition);
|
||||
E_Expr *exprs[] = {addr_parse.expr, cnd_parse.expr};
|
||||
for EachElement(idx, exprs)
|
||||
{
|
||||
typedef struct ExprWalkTask ExprWalkTask;
|
||||
struct ExprWalkTask
|
||||
{
|
||||
ExprWalkTask *next;
|
||||
E_Expr *expr;
|
||||
};
|
||||
ExprWalkTask start_task = {0, exprs[idx]};
|
||||
ExprWalkTask *first_task = &start_task;
|
||||
for(ExprWalkTask *t = first_task; t != 0; t = t->next)
|
||||
{
|
||||
E_Expr *expr = t->expr;
|
||||
if(expr->ref != &e_expr_nil)
|
||||
{
|
||||
expr = expr->ref;
|
||||
}
|
||||
if(expr->kind == E_ExprKind_LeafIdentifier)
|
||||
{
|
||||
str8_list_push(ctrl_state->ctrl_thread_msg_process_arena, &ctrl_state->msg_user_bp_touched_symbols, expr->string);
|
||||
}
|
||||
if(expr->next != &e_expr_nil)
|
||||
{
|
||||
ExprWalkTask *task = push_array(scratch.arena, ExprWalkTask, 1);
|
||||
task->expr = expr->next;
|
||||
task->next = t->next;
|
||||
t->next = task;
|
||||
}
|
||||
if(expr->first != &e_expr_nil)
|
||||
{
|
||||
ExprWalkTask *task = push_array(scratch.arena, ExprWalkTask, 1);
|
||||
task->expr = expr->first;
|
||||
task->next = t->next;
|
||||
t->next = task;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
scratch_end(scratch);
|
||||
}
|
||||
|
||||
//- rjf: gather all touched files by user breakpoints
|
||||
for(CTRL_UserBreakpointNode *n = msg->user_bps.first; n != 0; n = n->next)
|
||||
{
|
||||
if(n->v.kind != CTRL_UserBreakpointKind_FileNameAndLineColNumber)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
str8_list_push(ctrl_state->ctrl_thread_msg_process_arena, &ctrl_state->msg_user_bp_touched_files, n->v.string);
|
||||
}
|
||||
|
||||
//- rjf: process message
|
||||
@@ -3747,7 +3829,10 @@ ctrl_thread__entry_point(void *p)
|
||||
CTRL_Entity *debug_info_path = ctrl_entity_child_from_kind(module, CTRL_EntityKind_DebugInfoPath);
|
||||
DI_Key old_dbgi_key = {debug_info_path->string, debug_info_path->timestamp};
|
||||
di_close(&old_dbgi_key);
|
||||
OS_MutexScopeW(ctrl_state->ctrl_thread_entity_ctx_rw_mutex) ctrl_entity_equip_string(ctrl_state->ctrl_thread_entity_store, debug_info_path, path);
|
||||
OS_MutexScopeW(ctrl_state->ctrl_thread_entity_ctx_rw_mutex)
|
||||
{
|
||||
ctrl_entity_equip_string(ctrl_state->ctrl_thread_entity_store, debug_info_path, path_normalized_from_string(scratch.arena, path));
|
||||
}
|
||||
U64 new_dbgi_timestamp = os_properties_from_file_path(path).modified;
|
||||
debug_info_path->timestamp = new_dbgi_timestamp;
|
||||
DI_Key new_dbgi_key = {debug_info_path->string, new_dbgi_timestamp};
|
||||
@@ -3780,18 +3865,28 @@ ctrl_thread__entry_point(void *p)
|
||||
}
|
||||
ins_atomic_u64_eval_assign(&ctrl_state->ctrl_thread_run_state, 0);
|
||||
}
|
||||
ins_atomic_u64_inc_eval(&ctrl_state->run_gen);
|
||||
ins_atomic_u64_inc_eval(&ctrl_state->mem_gen);
|
||||
ins_atomic_u64_inc_eval(&ctrl_state->reg_gen);
|
||||
|
||||
//- rjf: update thread register cache
|
||||
ProfScope("update thread register cache")
|
||||
{
|
||||
CTRL_EntityCtx *entity_ctx = &ctrl_state->ctrl_thread_entity_store->ctx;
|
||||
CTRL_EntityArray threads = ctrl_entity_array_from_kind(entity_ctx, CTRL_EntityKind_Thread);
|
||||
REGS_RegBlockX64 *blocks = push_array(scratch.arena, REGS_RegBlockX64, threads.count);
|
||||
{
|
||||
for EachIndex(idx, threads.count)
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
ctrl_reg_block_from_thread(scratch.arena, entity_ctx, threads.v[idx]->handle);
|
||||
scratch_end(scratch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: gather & output logs
|
||||
LogScopeResult log = log_scope_end(scratch.arena);
|
||||
ctrl_thread__flush_info_log(log.strings[LogMsgKind_Info]);
|
||||
if(log.strings[LogMsgKind_UserError].size != 0)
|
||||
{
|
||||
CTRL_EventList evts = {0};
|
||||
CTRL_Event *evt = ctrl_event_list_push(scratch.arena, &evts);
|
||||
evt->kind = CTRL_EventKind_Error;
|
||||
evt->string = log.strings[LogMsgKind_UserError];
|
||||
ctrl_c2u_push_events(&evts);
|
||||
}
|
||||
ctrl_thread__end_and_flush_log();
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
@@ -3804,13 +3899,14 @@ internal void
|
||||
ctrl_thread__append_resolved_module_user_bp_traps(Arena *arena, CTRL_EvalScope *eval_scope, CTRL_Handle process, CTRL_Handle module, CTRL_UserBreakpointList *user_bps, DMN_TrapChunkList *traps_out)
|
||||
{
|
||||
if(user_bps->first == 0) { return; }
|
||||
ProfBeginFunction();
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
DI_Scope *di_scope = eval_scope->di_scope;
|
||||
CTRL_EntityCtx *entity_ctx = &ctrl_state->ctrl_thread_entity_store->ctx;
|
||||
CTRL_Entity *module_entity = ctrl_entity_from_handle(entity_ctx, module);
|
||||
CTRL_Entity *debug_info_path_entity = ctrl_entity_child_from_kind(module_entity, CTRL_EntityKind_DebugInfoPath);
|
||||
DI_Key dbgi_key = {debug_info_path_entity->string, debug_info_path_entity->timestamp};
|
||||
RDI_Parsed *rdi = di_rdi_from_key(di_scope, &dbgi_key, max_U64);
|
||||
RDI_Parsed *rdi = di_rdi_from_key(di_scope, &dbgi_key, 1, 0);
|
||||
U64 base_vaddr = module_entity->vaddr_range.min;
|
||||
for(CTRL_UserBreakpointNode *n = user_bps->first; n != 0; n = n->next)
|
||||
{
|
||||
@@ -3854,6 +3950,7 @@ ctrl_thread__append_resolved_module_user_bp_traps(Arena *arena, CTRL_EvalScope *
|
||||
}
|
||||
|
||||
// rjf: src_id * pt -> push
|
||||
if(src_id != 0)
|
||||
{
|
||||
RDI_SourceFile *src = rdi_element_from_name_idx(rdi, SourceFiles, src_id);
|
||||
RDI_SourceLineMap *src_line_map = rdi_element_from_name_idx(rdi, SourceLineMaps, src->source_line_map_idx);
|
||||
@@ -3875,7 +3972,7 @@ ctrl_thread__append_resolved_module_user_bp_traps(Arena *arena, CTRL_EvalScope *
|
||||
{
|
||||
String8 expr = bp->string;
|
||||
E_Value value = e_value_from_string(expr);
|
||||
if(value.u64 != 0)
|
||||
if(value.u64 != 0 || bp->flags != 0)
|
||||
{
|
||||
DMN_Trap trap = {process.dmn_handle, value.u64, (U64)bp};
|
||||
trap.flags = ctrl_dmn_trap_flags_from_user_breakpoint_flags(bp->flags);
|
||||
@@ -3886,6 +3983,7 @@ ctrl_thread__append_resolved_module_user_bp_traps(Arena *arena, CTRL_EvalScope *
|
||||
}
|
||||
}
|
||||
scratch_end(scratch);
|
||||
ProfEnd();
|
||||
}
|
||||
|
||||
internal void
|
||||
@@ -3898,7 +3996,7 @@ ctrl_thread__append_resolved_process_user_bp_traps(Arena *arena, CTRL_EvalScope
|
||||
{
|
||||
String8 expr = bp->string;
|
||||
E_Value value = e_value_from_string(expr);
|
||||
if(value.u64 != 0)
|
||||
if(value.u64 != 0 || bp->flags != 0)
|
||||
{
|
||||
DMN_Trap trap = {process.dmn_handle, value.u64, (U64)bp};
|
||||
trap.flags = ctrl_dmn_trap_flags_from_user_breakpoint_flags(bp->flags);
|
||||
@@ -3946,6 +4044,7 @@ ctrl_thread__module_open(CTRL_Handle process, CTRL_Handle module, Rng1U64 vaddr_
|
||||
String8 rdi_dbg_path = str8_zero();
|
||||
String8 raddbg_data = str8_zero();
|
||||
Rng1U64 raddbg_section_voff_range = r1u64(0, 0);
|
||||
Rng1U64 raddbg_is_attached_section_voff_range = r1u64(0, 0);
|
||||
ProfScope("unpack relevant PE info")
|
||||
{
|
||||
B32 is_valid = 1;
|
||||
@@ -4144,6 +4243,11 @@ ctrl_thread__module_open(CTRL_Handle process, CTRL_Handle module, Rng1U64 vaddr_
|
||||
raddbg_section_voff_range.min = sec[idx].voff;
|
||||
raddbg_section_voff_range.max = sec[idx].voff + sec[idx].vsize;
|
||||
}
|
||||
else if(str8_match(section_name, str8_lit(".rdbgia"), 0))
|
||||
{
|
||||
raddbg_is_attached_section_voff_range.min = sec[idx].voff;
|
||||
raddbg_is_attached_section_voff_range.max = sec[idx].voff + sec[idx].vsize;
|
||||
}
|
||||
}
|
||||
raddbg_data.size = dim_1u64(raddbg_section_voff_range);
|
||||
raddbg_data.str = push_array(arena, U8, raddbg_data.size);
|
||||
@@ -4152,11 +4256,11 @@ ctrl_thread__module_open(CTRL_Handle process, CTRL_Handle module, Rng1U64 vaddr_
|
||||
scratch_end(scratch);
|
||||
}
|
||||
|
||||
// rjf: if we have a raddbg section, mark the first byte as 1, to signify attachment
|
||||
if(raddbg_section_voff_range.max != raddbg_section_voff_range.min)
|
||||
// rjf: if we have a "raddbg is attached" section, mark the first byte as 1, to signify attachment
|
||||
if(raddbg_is_attached_section_voff_range.max != raddbg_is_attached_section_voff_range.min)
|
||||
{
|
||||
U8 new_value = 1;
|
||||
dmn_process_write_struct(process.dmn_handle, vaddr_range.min + raddbg_section_voff_range.min, &new_value);
|
||||
dmn_process_write_struct(process.dmn_handle, vaddr_range.min + raddbg_is_attached_section_voff_range.min, &new_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4384,7 +4488,7 @@ ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg,
|
||||
B32 asan_shadow_variable_exists_but_is_zero = 0;
|
||||
CTRL_Entity *dbg_path = ctrl_entity_child_from_kind(module, CTRL_EntityKind_DebugInfoPath);
|
||||
DI_Key dbgi_key = {dbg_path->string, dbg_path->timestamp};
|
||||
RDI_Parsed *rdi = di_rdi_from_key(di_scope, &dbgi_key, max_U64);
|
||||
RDI_Parsed *rdi = di_rdi_from_key(di_scope, &dbgi_key, 1, max_U64);
|
||||
RDI_NameMap *unparsed_map = rdi_element_from_name_idx(rdi, NameMaps, RDI_NameMapKind_GlobalVariables);
|
||||
{
|
||||
RDI_ParsedNameMap map = {0};
|
||||
@@ -4494,6 +4598,9 @@ ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg,
|
||||
}
|
||||
}
|
||||
DMN_EventList events = dmn_ctrl_run(scratch.arena, ctrl_ctx, run_ctrls);
|
||||
ins_atomic_u64_inc_eval(&ctrl_state->mem_gen);
|
||||
ins_atomic_u64_inc_eval(&ctrl_state->reg_gen);
|
||||
ins_atomic_u64_inc_eval(&ctrl_state->run_gen);
|
||||
for(DMN_EventNode *src_n = events.first; src_n != 0; src_n = src_n->next)
|
||||
{
|
||||
DMN_EventNode *dst_n = ctrl_state->free_dmn_event_node;
|
||||
@@ -4613,6 +4720,7 @@ ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg,
|
||||
out_evt->entity_id = event->code;
|
||||
}break;
|
||||
case DMN_EventKind_UnloadModule:
|
||||
ProfScope("unload module %.*s", str8_varg(event->string))
|
||||
{
|
||||
CTRL_Event *out_evt = ctrl_event_list_push(scratch.arena, &evts);
|
||||
CTRL_Handle module_handle = ctrl_handle_make(CTRL_MachineID_Local, event->module);
|
||||
@@ -4672,7 +4780,7 @@ ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg,
|
||||
out_evt->msg_id = msg->msg_id;
|
||||
out_evt->vaddr_rng = r1u64(event->address, event->address + event->size);
|
||||
out_evt->string = event->string;
|
||||
}
|
||||
}break;
|
||||
case DMN_EventKind_SetBreakpoint:
|
||||
{
|
||||
CTRL_Event *out_evt = ctrl_event_list_push(scratch.arena, &evts);
|
||||
@@ -4718,12 +4826,11 @@ ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg,
|
||||
// modules (a very bad heuristic that may or may not inform us that we are
|
||||
// dealing with insane-town projects)
|
||||
//
|
||||
if(event->kind == DMN_EventKind_LoadModule &&
|
||||
if(0 &&
|
||||
event->kind == DMN_EventKind_LoadModule &&
|
||||
(entity_ctx->entity_kind_counts[CTRL_EntityKind_Module] > 256 ||
|
||||
entity_ctx->entity_kind_counts[CTRL_EntityKind_Module] == 1))
|
||||
{
|
||||
U64 endt_us = os_now_microseconds() + 1000000;
|
||||
|
||||
//- rjf: unpack event
|
||||
CTRL_Handle process_handle = ctrl_handle_make(CTRL_MachineID_Local, event->process);
|
||||
CTRL_Handle loaded_module_handle = ctrl_handle_make(CTRL_MachineID_Local, event->module);
|
||||
@@ -4867,6 +4974,14 @@ ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg,
|
||||
DI_Key key = {push_str8f(scratch.arena, "%S/%S", t->path, info.name), info.props.modified};
|
||||
di_open(&key);
|
||||
di_key_list_push(scratch.arena, &preemptively_loaded_keys, &key);
|
||||
if(preemptively_loaded_keys.count >= Max(1, async_thread_count()/2))
|
||||
{
|
||||
for(DI_KeyNode *n = preemptively_loaded_keys.first; n != 0; n = n->next)
|
||||
{
|
||||
di_close(&n->v);
|
||||
}
|
||||
MemoryZeroStruct(&preemptively_loaded_keys);
|
||||
}
|
||||
}
|
||||
}
|
||||
os_file_iter_end(it);
|
||||
@@ -4874,16 +4989,6 @@ ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: for each pre-emptively loaded key, wait for the initial
|
||||
// load task to be done
|
||||
for(DI_KeyNode *n = preemptively_loaded_keys.first; n != 0; n = n->next)
|
||||
{
|
||||
DI_Scope *di_scope = di_scope_open();
|
||||
RDI_Parsed *rdi = di_rdi_from_key(di_scope, &n->v, endt_us);
|
||||
di_scope_close(di_scope);
|
||||
di_close(&n->v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4970,7 +5075,7 @@ ctrl_eval_space_read(void *u, E_Space space, void *out, Rng1U64 range)
|
||||
//- rjf: control thread eval scopes
|
||||
|
||||
internal CTRL_EvalScope *
|
||||
ctrl_thread__eval_scope_begin(Arena *arena, CTRL_Entity *thread)
|
||||
ctrl_thread__eval_scope_begin(Arena *arena, CTRL_UserBreakpointList *user_bps, CTRL_Entity *thread)
|
||||
{
|
||||
CTRL_EntityCtx *entity_ctx = &ctrl_state->ctrl_thread_entity_store->ctx;
|
||||
CTRL_EvalScope *scope = push_array(arena, CTRL_EvalScope, 1);
|
||||
@@ -5012,8 +5117,96 @@ ctrl_thread__eval_scope_begin(Arena *arena, CTRL_Entity *thread)
|
||||
if(mod->kind != CTRL_EntityKind_Module) { continue; }
|
||||
CTRL_Entity *dbg_path = ctrl_entity_child_from_kind(mod, CTRL_EntityKind_DebugInfoPath);
|
||||
DI_Key dbgi_key = {dbg_path->string, dbg_path->timestamp};
|
||||
|
||||
//- rjf: try to obtain this module's RDI
|
||||
RDI_Parsed *rdi = di_rdi_from_key(scope->di_scope, &dbgi_key, 1, 0);
|
||||
|
||||
//- rjf: if this RDI is not yet ready => determine if we need to wait for it
|
||||
//
|
||||
// (we *always* wait for the initial module)
|
||||
//
|
||||
B32 rdi_is_necessary = 1;
|
||||
if(rdi == &rdi_parsed_nil) ProfScope("determine if RDI is necessary")
|
||||
{
|
||||
// rjf: find cached result
|
||||
U64 hash = ctrl_hash_from_handle(mod->handle);
|
||||
U64 slot_idx = hash%ctrl_state->module_req_cache_slots_count;
|
||||
CTRL_ModuleReqCacheNode *slot = ctrl_state->module_req_cache_slots[slot_idx];
|
||||
CTRL_ModuleReqCacheNode *node = 0;
|
||||
for(CTRL_ModuleReqCacheNode *n = slot; slot != 0; slot = slot->next)
|
||||
{
|
||||
if(ctrl_handle_match(n->module, mod->handle))
|
||||
{
|
||||
node = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: cached? -> take cached result
|
||||
if(node != 0)
|
||||
{
|
||||
rdi_is_necessary = node->required;
|
||||
}
|
||||
|
||||
// rjf: not cached -> compute & store
|
||||
else ProfScope("cache miss")
|
||||
{
|
||||
OS_Handle file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead, dbgi_key.path);
|
||||
{
|
||||
//- rjf: determine if file is PDB
|
||||
B32 file_is_pdb = 0;
|
||||
if(!file_is_pdb)
|
||||
{
|
||||
U8 msf70_magic_maybe[sizeof(msf_msf70_magic)] = {0};
|
||||
os_file_read(file, r1u64(0, sizeof(msf70_magic_maybe)), msf70_magic_maybe);
|
||||
if(MemoryMatch(msf70_magic_maybe, msf_msf70_magic, sizeof(msf70_magic_maybe)))
|
||||
{
|
||||
file_is_pdb = 1;
|
||||
}
|
||||
}
|
||||
if(!file_is_pdb)
|
||||
{
|
||||
U8 msf20_magic_maybe[sizeof(msf_msf20_magic)] = {0};
|
||||
os_file_read(file, r1u64(0, sizeof(msf20_magic_maybe)), msf20_magic_maybe);
|
||||
if(MemoryMatch(msf20_magic_maybe, msf_msf20_magic, sizeof(msf20_magic_maybe)))
|
||||
{
|
||||
file_is_pdb = 1;
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: file is PDB -> do thin parse & lookup of all breakpoint files/symbols.
|
||||
// if any are found in the PDB, then this RDI is necessary.
|
||||
if(file_is_pdb)
|
||||
{
|
||||
FileProperties props = os_properties_from_file(file);
|
||||
OS_Handle map = os_file_map_open(OS_AccessFlag_Read, file);
|
||||
void *file_base = os_file_map_view_open(map, OS_AccessFlag_Read, r1u64(0, props.size));
|
||||
String8 file_data = str8(file_base, props.size);
|
||||
{
|
||||
rdi_is_necessary = pdb_has_symbol_or_file_ref(file_data, ctrl_state->msg_user_bp_touched_symbols, ctrl_state->msg_user_bp_touched_files);
|
||||
}
|
||||
os_file_map_view_close(map, file_base, r1u64(0, props.size));
|
||||
os_file_map_close(map);
|
||||
}
|
||||
}
|
||||
os_file_close(file);
|
||||
node = push_array(ctrl_state->ctrl_thread_msg_process_arena, CTRL_ModuleReqCacheNode, 1);
|
||||
node->next = slot;
|
||||
ctrl_state->module_req_cache_slots[slot_idx] = node;
|
||||
node->module = mod->handle;
|
||||
node->required = rdi_is_necessary;
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: if this RDI is necessary, but we do not have it => wait for it forever
|
||||
if(rdi == &rdi_parsed_nil && rdi_is_necessary)
|
||||
{
|
||||
rdi = di_rdi_from_key(scope->di_scope, &dbgi_key, 1, max_U64);
|
||||
}
|
||||
|
||||
//- rjf: fill evaluation module info
|
||||
eval_modules[eval_module_idx].arch = arch;
|
||||
eval_modules[eval_module_idx].rdi = di_rdi_from_key(scope->di_scope, &dbgi_key, max_U64);
|
||||
eval_modules[eval_module_idx].rdi = rdi;
|
||||
eval_modules[eval_module_idx].vaddr_range = mod->vaddr_range;
|
||||
eval_modules[eval_module_idx].space = e_space_make(CTRL_EvalSpaceKind_Entity);
|
||||
eval_modules[eval_module_idx].space.u64_0 = (U64)process;
|
||||
@@ -5101,17 +5294,19 @@ ctrl_thread__eval_scope_end(CTRL_EvalScope *scope)
|
||||
//- rjf: log flusher
|
||||
|
||||
internal void
|
||||
ctrl_thread__flush_info_log(String8 string)
|
||||
{
|
||||
os_append_data_to_file_path(ctrl_state->ctrl_thread_log_path, string);
|
||||
}
|
||||
|
||||
internal void
|
||||
ctrl_thread__end_and_flush_info_log(void)
|
||||
ctrl_thread__end_and_flush_log(void)
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
LogScopeResult log = log_scope_end(scratch.arena);
|
||||
ctrl_thread__flush_info_log(log.strings[LogMsgKind_Info]);
|
||||
os_append_data_to_file_path(ctrl_state->ctrl_thread_log_path, log.strings[LogMsgKind_Info]);
|
||||
if(log.strings[LogMsgKind_UserError].size != 0)
|
||||
{
|
||||
CTRL_EventList evts = {0};
|
||||
CTRL_Event *evt = ctrl_event_list_push(scratch.arena, &evts);
|
||||
evt->kind = CTRL_EventKind_Error;
|
||||
evt->string = log.strings[LogMsgKind_UserError];
|
||||
ctrl_c2u_push_events(&evts);
|
||||
}
|
||||
scratch_end(scratch);
|
||||
}
|
||||
|
||||
@@ -5447,7 +5642,7 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg)
|
||||
DMN_TrapChunkList user_traps = {0};
|
||||
{
|
||||
CTRL_Entity *thread = ctrl_entity_from_handle(entity_ctx, target_thread);
|
||||
CTRL_EvalScope *eval_scope = ctrl_thread__eval_scope_begin(scratch.arena, thread);
|
||||
CTRL_EvalScope *eval_scope = ctrl_thread__eval_scope_begin(scratch.arena, &msg->user_bps, thread);
|
||||
for(CTRL_Entity *machine = entity_ctx->root->first;
|
||||
machine != &ctrl_entity_nil;
|
||||
machine = machine->next)
|
||||
@@ -5692,6 +5887,7 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg)
|
||||
//- rjf: setup run controls
|
||||
//
|
||||
DMN_RunCtrls run_ctrls = {0};
|
||||
run_ctrls.priority_thread = target_thread.dmn_handle;
|
||||
run_ctrls.ignore_previous_exception = 1;
|
||||
run_ctrls.run_entity_count = frozen_threads.count;
|
||||
run_ctrls.run_entities = push_array(scratch.arena, DMN_Handle, run_ctrls.run_entity_count);
|
||||
@@ -5739,7 +5935,7 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg)
|
||||
}break;
|
||||
case DMN_EventKind_CreateProcess:
|
||||
{
|
||||
CTRL_EvalScope *eval_scope = ctrl_thread__eval_scope_begin(scratch.arena, &ctrl_entity_nil);
|
||||
CTRL_EvalScope *eval_scope = ctrl_thread__eval_scope_begin(scratch.arena, &msg->user_bps, &ctrl_entity_nil);
|
||||
{
|
||||
DMN_TrapChunkList new_traps = {0};
|
||||
ctrl_thread__append_resolved_process_user_bp_traps(scratch.arena, eval_scope, ctrl_handle_make(CTRL_MachineID_Local, event->process), &msg->user_bps, &new_traps);
|
||||
@@ -5762,7 +5958,7 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg)
|
||||
case DMN_EventKind_LoadModule:
|
||||
{
|
||||
CTRL_Entity *thread = ctrl_entity_from_handle(entity_ctx, ctrl_handle_make(CTRL_MachineID_Local, event->thread));
|
||||
CTRL_EvalScope *eval_scope = ctrl_thread__eval_scope_begin(scratch.arena, thread);
|
||||
CTRL_EvalScope *eval_scope = ctrl_thread__eval_scope_begin(scratch.arena, &msg->user_bps, thread);
|
||||
{
|
||||
DMN_TrapChunkList new_traps = {0};
|
||||
ctrl_thread__append_resolved_module_user_bp_traps(scratch.arena, eval_scope, ctrl_handle_make(CTRL_MachineID_Local, event->process), ctrl_handle_make(CTRL_MachineID_Local, event->module), &msg->user_bps, &new_traps);
|
||||
@@ -5823,7 +6019,7 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg)
|
||||
U64 module_base_vaddr = module->vaddr_range.min;
|
||||
CTRL_Entity *dbg_path = ctrl_entity_child_from_kind(module, CTRL_EntityKind_DebugInfoPath);
|
||||
DI_Key dbgi_key = {dbg_path->string, dbg_path->timestamp};
|
||||
RDI_Parsed *rdi = di_rdi_from_key(di_scope, &dbgi_key, max_U64);
|
||||
RDI_Parsed *rdi = di_rdi_from_key(di_scope, &dbgi_key, 1, max_U64);
|
||||
RDI_NameMap *unparsed_map = rdi_element_from_name_idx(rdi, NameMaps, RDI_NameMapKind_Procedures);
|
||||
RDI_ParsedNameMap map = {0};
|
||||
rdi_parsed_from_name_map(rdi, unparsed_map, &map);
|
||||
@@ -6156,10 +6352,18 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg)
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: programmatic user breakpoints (we do not have state for it,
|
||||
// but the target program(s) did something breakpoint-like, and we
|
||||
// want to treat it as if we did)
|
||||
if(event->address != 0)
|
||||
{
|
||||
hit_user_bp = 1;
|
||||
}
|
||||
|
||||
// rjf: evaluate hit stop conditions
|
||||
if(conditions.node_count != 0) ProfScope("evaluate hit stop conditions")
|
||||
{
|
||||
CTRL_EvalScope *eval_scope = ctrl_thread__eval_scope_begin(temp.arena, thread);
|
||||
CTRL_EvalScope *eval_scope = ctrl_thread__eval_scope_begin(temp.arena, &msg->user_bps, thread);
|
||||
for(String8Node *condition_n = conditions.first; condition_n != 0; condition_n = condition_n->next)
|
||||
{
|
||||
// rjf: evaluate
|
||||
@@ -6638,6 +6842,7 @@ ctrl_u2ms_dequeue_req(HS_Key *out_key, CTRL_Handle *out_process, Rng1U64 *out_va
|
||||
|
||||
ASYNC_WORK_DEF(ctrl_mem_stream_work)
|
||||
{
|
||||
#define CTRL_MEM_STREAM_WORK_DEBUG 0
|
||||
ProfBeginFunction();
|
||||
CTRL_ProcessMemoryCache *cache = &ctrl_state->process_memory_cache;
|
||||
|
||||
@@ -6673,7 +6878,12 @@ ASYNC_WORK_DEF(ctrl_mem_stream_work)
|
||||
void *range_base = 0;
|
||||
U64 zero_terminated_size = 0;
|
||||
U64 pre_read_mem_gen = ctrl_mem_gen();
|
||||
U64 post_read_mem_gen = 0;
|
||||
B32 pre_run_state = ins_atomic_u64_eval(&ctrl_state->ctrl_thread_run_state);
|
||||
#if CTRL_MEM_STREAM_WORK_DEBUG
|
||||
Log *log = log_alloc();
|
||||
log_select(log);
|
||||
log_scope_begin();
|
||||
#endif
|
||||
{
|
||||
range_size = dim_1u64(vaddr_range_clamped);
|
||||
U64 page_size = os_get_system_info()->page_size;
|
||||
@@ -6733,8 +6943,25 @@ ASYNC_WORK_DEF(ctrl_mem_stream_work)
|
||||
}
|
||||
}
|
||||
}
|
||||
post_read_mem_gen = dmn_mem_gen();
|
||||
}
|
||||
U64 post_read_mem_gen = ctrl_mem_gen();
|
||||
B32 post_run_state = ins_atomic_u64_eval(&ctrl_state->ctrl_thread_run_state);
|
||||
// NOTE(rjf): debugging
|
||||
#if CTRL_MEM_STREAM_WORK_DEBUG
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
String8 sample_data_str = str8_lit("no data");
|
||||
if(range_base != 0)
|
||||
{
|
||||
String8 sample_data = str8((U8*)range_base + 0x100, 16);
|
||||
String8List sample_data_strs = numeric_str8_list_from_data(scratch.arena, 16, sample_data, 1);
|
||||
sample_data_str = str8_list_join(scratch.arena, &sample_data_strs, &(StringJoin){.sep = str8_lit(", ")});
|
||||
}
|
||||
LogScopeResult log = log_scope_end(scratch.arena);
|
||||
raddbg_log("[0x%I64x, 0x%I64x) { pre_gen: %I64u, post_gen: %I64u, pre_run: %i, post_run: %i, bytes: [%S], info:```%S``` }\n", vaddr_range.min, vaddr_range.max, pre_read_mem_gen, post_read_mem_gen, pre_run_state, post_run_state, sample_data_str, log.strings[LogMsgKind_Info]);
|
||||
scratch_end(scratch);
|
||||
}
|
||||
#endif
|
||||
|
||||
//- rjf: read successful -> submit to hash store
|
||||
U128 hash = {0};
|
||||
@@ -6764,6 +6991,7 @@ ASYNC_WORK_DEF(ctrl_mem_stream_work)
|
||||
{
|
||||
range_n->mem_gen = post_read_mem_gen;
|
||||
}
|
||||
range_n->working_count -= 1;
|
||||
goto commit__break_all;
|
||||
}
|
||||
}
|
||||
|
||||
+24
-4
@@ -756,6 +756,17 @@ struct CTRL_TCTX
|
||||
CTRL_ScopeCallStackTouch *free_call_stack_touch;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Module Requirement Cache Types
|
||||
|
||||
typedef struct CTRL_ModuleReqCacheNode CTRL_ModuleReqCacheNode;
|
||||
struct CTRL_ModuleReqCacheNode
|
||||
{
|
||||
CTRL_ModuleReqCacheNode *next;
|
||||
CTRL_Handle module;
|
||||
B32 required;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Wakeup Hook Function Types
|
||||
|
||||
@@ -781,6 +792,11 @@ struct CTRL_State
|
||||
CTRL_CallStackCache call_stack_cache;
|
||||
CTRL_ModuleImageInfoCache module_image_info_cache;
|
||||
|
||||
// rjf: generations
|
||||
U64 run_gen;
|
||||
U64 mem_gen;
|
||||
U64 reg_gen;
|
||||
|
||||
// rjf: user -> ctrl msg ring buffer
|
||||
U64 u2c_ring_size;
|
||||
U8 *u2c_ring_base;
|
||||
@@ -806,6 +822,7 @@ struct CTRL_State
|
||||
OS_Handle ctrl_thread_entity_ctx_rw_mutex;
|
||||
CTRL_EntityCtxRWStore *ctrl_thread_entity_store;
|
||||
E_Cache *ctrl_thread_eval_cache;
|
||||
Arena *ctrl_thread_msg_process_arena;
|
||||
Arena *dmn_event_arena;
|
||||
DMN_EventNode *first_dmn_event_node;
|
||||
DMN_EventNode *last_dmn_event_node;
|
||||
@@ -816,6 +833,10 @@ struct CTRL_State
|
||||
U64 process_counter;
|
||||
Arena *dbg_dir_arena;
|
||||
CTRL_DbgDirNode *dbg_dir_root;
|
||||
U64 module_req_cache_slots_count;
|
||||
CTRL_ModuleReqCacheNode **module_req_cache_slots;
|
||||
String8List msg_user_bp_touched_files;
|
||||
String8List msg_user_bp_touched_symbols;
|
||||
|
||||
// rjf: user -> memstream ring buffer
|
||||
U64 u2ms_ring_size;
|
||||
@@ -852,7 +873,7 @@ thread_static CTRL_EntityCtxLookupAccel *ctrl_entity_ctx_lookup_accel = 0;
|
||||
////////////////////////////////
|
||||
//~ rjf: Logging Markup
|
||||
|
||||
#define CTRL_CtrlThreadLogScope DeferLoop(log_scope_begin(), ctrl_thread__end_and_flush_info_log())
|
||||
#define CTRL_CtrlThreadLogScope DeferLoop(log_scope_begin(), ctrl_thread__end_and_flush_log())
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Type Functions
|
||||
@@ -1099,12 +1120,11 @@ internal DMN_Event *ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_
|
||||
internal B32 ctrl_eval_space_read(void *u, E_Space space, void *out, Rng1U64 vaddr_range);
|
||||
|
||||
//- rjf: control thread eval scopes
|
||||
internal CTRL_EvalScope *ctrl_thread__eval_scope_begin(Arena *arena, CTRL_Entity *thread);
|
||||
internal CTRL_EvalScope *ctrl_thread__eval_scope_begin(Arena *arena, CTRL_UserBreakpointList *user_bps, CTRL_Entity *thread);
|
||||
internal void ctrl_thread__eval_scope_end(CTRL_EvalScope *scope);
|
||||
|
||||
//- rjf: log flusher
|
||||
internal void ctrl_thread__flush_info_log(String8 string);
|
||||
internal void ctrl_thread__end_and_flush_info_log(void);
|
||||
internal void ctrl_thread__end_and_flush_log(void);
|
||||
|
||||
//- rjf: msg kind implementations
|
||||
internal void ctrl_thread__launch(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg);
|
||||
|
||||
@@ -533,7 +533,7 @@ ASYNC_WORK_DEF(dasm_parse_work)
|
||||
RDI_Parsed *rdi = &rdi_parsed_nil;
|
||||
if(params.dbgi_key.path.size != 0)
|
||||
{
|
||||
rdi = di_rdi_from_key(di_scope, ¶ms.dbgi_key, max_U64);
|
||||
rdi = di_rdi_from_key(di_scope, ¶ms.dbgi_key, 1, max_U64);
|
||||
}
|
||||
|
||||
//- rjf: hash -> data
|
||||
|
||||
@@ -65,6 +65,7 @@ D_CmdTable: // | | | |
|
||||
@table(name)
|
||||
D_DevToggleTable:
|
||||
{
|
||||
{always_refresh}
|
||||
{simulate_lag}
|
||||
{draw_ui_text_pos}
|
||||
{draw_ui_focus_debug}
|
||||
|
||||
@@ -475,7 +475,7 @@ d_trap_net_from_thread__step_over_line(Arena *arena, CTRL_Entity *thread)
|
||||
}
|
||||
|
||||
// rjf: push trap for natural linear flow
|
||||
if(good_line_info)
|
||||
if(good_line_info && good_machine_code)
|
||||
{
|
||||
CTRL_Trap trap = {CTRL_TrapFlag_EndStepping, line_vaddr_rng.max};
|
||||
ctrl_trap_list_push(arena, &result, &trap);
|
||||
@@ -631,7 +631,7 @@ d_trap_net_from_thread__step_into_line(Arena *arena, CTRL_Entity *thread)
|
||||
}
|
||||
|
||||
// rjf: push trap for natural linear flow
|
||||
if(good_line_info)
|
||||
if(good_line_info && good_machine_code)
|
||||
{
|
||||
CTRL_Trap trap = {CTRL_TrapFlag_EndStepping, line_vaddr_rng.max};
|
||||
ctrl_trap_list_push(arena, &result, &trap);
|
||||
@@ -654,7 +654,7 @@ d_voff_from_dbgi_key_symbol_name(DI_Key *dbgi_key, String8 symbol_name)
|
||||
DI_Scope *scope = di_scope_open();
|
||||
U64 result = 0;
|
||||
{
|
||||
RDI_Parsed *rdi = di_rdi_from_key(scope, dbgi_key, 0);
|
||||
RDI_Parsed *rdi = di_rdi_from_key(scope, dbgi_key, 1, 0);
|
||||
RDI_NameMapKind name_map_kinds[] =
|
||||
{
|
||||
RDI_NameMapKind_GlobalVariables,
|
||||
@@ -734,7 +734,7 @@ d_lines_from_dbgi_key_voff(Arena *arena, DI_Key *dbgi_key, U64 voff)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
DI_Scope *scope = di_scope_open();
|
||||
RDI_Parsed *rdi = di_rdi_from_key(scope, dbgi_key, 0);
|
||||
RDI_Parsed *rdi = di_rdi_from_key(scope, dbgi_key, 1, 0);
|
||||
D_LineList result = {0};
|
||||
{
|
||||
//- rjf: gather line tables
|
||||
@@ -843,7 +843,7 @@ d_lines_array_from_dbgi_key_file_path_line_range(Arena *arena, DI_Key dbgi_key,
|
||||
String8 file_path_normalized = lower_from_str8(scratch.arena, path_normalized_from_string(scratch.arena, file_path));
|
||||
|
||||
// rjf: binary -> rdi
|
||||
RDI_Parsed *rdi = di_rdi_from_key(scope, &dbgi_key, 0);
|
||||
RDI_Parsed *rdi = di_rdi_from_key(scope, &dbgi_key, 1, 0);
|
||||
|
||||
// rjf: file_path_normalized * rdi -> src_id
|
||||
B32 good_src_id = 0;
|
||||
@@ -941,7 +941,7 @@ d_lines_array_from_file_path_line_range(Arena *arena, String8 file_path, Rng1S64
|
||||
{
|
||||
// rjf: binary -> rdi
|
||||
DI_Key key = dbgi_key_n->v;
|
||||
RDI_Parsed *rdi = di_rdi_from_key(scope, &key, 0);
|
||||
RDI_Parsed *rdi = di_rdi_from_key(scope, &key, 1, 0);
|
||||
|
||||
// rjf: file_path_normalized * rdi -> src_id
|
||||
B32 good_src_id = 0;
|
||||
@@ -1302,7 +1302,7 @@ d_query_cached_locals_map_from_dbgi_key_voff(DI_Key *dbgi_key, U64 voff)
|
||||
if(node == 0)
|
||||
{
|
||||
DI_Scope *scope = di_scope_open();
|
||||
RDI_Parsed *rdi = di_rdi_from_key(scope, dbgi_key, 0);
|
||||
RDI_Parsed *rdi = di_rdi_from_key(scope, dbgi_key, 1, 0);
|
||||
E_String2NumMap *map = e_push_locals_map_from_rdi_voff(cache->arena, rdi, voff);
|
||||
if(map->slots_count != 0)
|
||||
{
|
||||
@@ -1356,7 +1356,7 @@ d_query_cached_member_map_from_dbgi_key_voff(DI_Key *dbgi_key, U64 voff)
|
||||
if(node == 0)
|
||||
{
|
||||
DI_Scope *scope = di_scope_open();
|
||||
RDI_Parsed *rdi = di_rdi_from_key(scope, dbgi_key, 0);
|
||||
RDI_Parsed *rdi = di_rdi_from_key(scope, dbgi_key, 1, 0);
|
||||
E_String2NumMap *map = e_push_member_map_from_rdi_voff(cache->arena, rdi, voff);
|
||||
if(map->slots_count != 0)
|
||||
{
|
||||
@@ -1843,7 +1843,7 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P
|
||||
{
|
||||
need_run = 1;
|
||||
run_kind = D_RunKind_Run;
|
||||
run_thread = &ctrl_entity_nil;
|
||||
run_thread = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, params->thread);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1970,7 +1970,7 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P
|
||||
CTRL_EntityArray processes = ctrl_entity_array_from_kind(&d_state->ctrl_entity_store->ctx, CTRL_EntityKind_Process);
|
||||
if(processes.count != 0)
|
||||
{
|
||||
d_cmd(D_CmdKind_Continue);
|
||||
d_cmd(D_CmdKind_Continue, .machine = params->machine, .process = params->process, .thread = params->thread);
|
||||
}
|
||||
else if(!d_ctrl_targets_running())
|
||||
{
|
||||
|
||||
@@ -44,6 +44,7 @@ D_CmdKind_Attach,
|
||||
D_CmdKind_COUNT,
|
||||
} D_CmdKind;
|
||||
|
||||
global B32 DEV_always_refresh = 0;
|
||||
global B32 DEV_simulate_lag = 0;
|
||||
global B32 DEV_draw_ui_text_pos = 0;
|
||||
global B32 DEV_draw_ui_focus_debug = 0;
|
||||
@@ -54,6 +55,7 @@ global B32 DEV_cmd_context_tooltips = 0;
|
||||
global B32 DEV_updating_indicator = 0;
|
||||
struct {B32 *value_ptr; String8 name;} DEV_toggle_table[] =
|
||||
{
|
||||
{&DEV_always_refresh, str8_lit_comp("always_refresh")},
|
||||
{&DEV_simulate_lag, str8_lit_comp("simulate_lag")},
|
||||
{&DEV_draw_ui_text_pos, str8_lit_comp("draw_ui_text_pos")},
|
||||
{&DEV_draw_ui_focus_debug, str8_lit_comp("draw_ui_focus_debug")},
|
||||
|
||||
+112
-38
@@ -462,25 +462,24 @@ di_open(DI_Key *key)
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
if(key->path.size != 0)
|
||||
{
|
||||
DI_Key key_normalized = di_normalized_key_from_key(scratch.arena, key);
|
||||
U64 hash = di_hash_from_key(&key_normalized);
|
||||
U64 hash = di_hash_from_key(key);
|
||||
U64 slot_idx = hash%di_shared->slots_count;
|
||||
U64 stripe_idx = slot_idx%di_shared->stripes_count;
|
||||
DI_Slot *slot = &di_shared->slots[slot_idx];
|
||||
DI_Stripe *stripe = &di_shared->stripes[stripe_idx];
|
||||
log_infof("open_debug_info: {\"%S\", 0x%I64x}\n", key_normalized.path, key_normalized.min_timestamp);
|
||||
log_infof("open_debug_info: {\"%S\", 0x%I64x}\n", key->path, key->min_timestamp);
|
||||
OS_MutexScopeW(stripe->rw_mutex)
|
||||
{
|
||||
//- rjf: find existing node
|
||||
DI_Node *node = di_node_from_key_slot__stripe_mutex_r_guarded(slot, &key_normalized);
|
||||
DI_Node *node = di_node_from_key_slot__stripe_mutex_r_guarded(slot, key);
|
||||
|
||||
//- rjf: allocate node if none exists; insert into slot
|
||||
if(node == 0)
|
||||
{
|
||||
U64 current_timestamp = os_properties_from_file_path(key_normalized.path).modified;
|
||||
U64 current_timestamp = os_properties_from_file_path(key->path).modified;
|
||||
if(current_timestamp == 0)
|
||||
{
|
||||
current_timestamp = key_normalized.min_timestamp;
|
||||
current_timestamp = key->min_timestamp;
|
||||
}
|
||||
node = stripe->free_node;
|
||||
if(node != 0)
|
||||
@@ -493,7 +492,7 @@ di_open(DI_Key *key)
|
||||
}
|
||||
MemoryZeroStruct(node);
|
||||
DLLPushBack(slot->first, slot->last, node);
|
||||
String8 path_stored = di_string_alloc__stripe_mutex_w_guarded(stripe, key_normalized.path);
|
||||
String8 path_stored = di_string_alloc__stripe_mutex_w_guarded(stripe, key->path);
|
||||
node->key.path = path_stored;
|
||||
node->key.min_timestamp = current_timestamp;
|
||||
}
|
||||
@@ -504,7 +503,7 @@ di_open(DI_Key *key)
|
||||
node->ref_count += 1;
|
||||
if(node->ref_count == 1)
|
||||
{
|
||||
di_u2p_enqueue_key(&key_normalized, max_U64);
|
||||
di_u2p_enqueue_key(key, max_U64);
|
||||
ins_atomic_u64_eval_assign(&node->is_working, 1);
|
||||
DeferLoop(os_rw_mutex_drop_w(stripe->rw_mutex), os_rw_mutex_take_w(stripe->rw_mutex))
|
||||
{
|
||||
@@ -524,18 +523,16 @@ di_close(DI_Key *key)
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
if(key->path.size != 0)
|
||||
{
|
||||
DI_Key key_normalized = di_normalized_key_from_key(scratch.arena, key);
|
||||
U64 hash = di_hash_from_key(&key_normalized);
|
||||
U64 hash = di_hash_from_key(key);
|
||||
U64 slot_idx = hash%di_shared->slots_count;
|
||||
U64 stripe_idx = slot_idx%di_shared->stripes_count;
|
||||
DI_Slot *slot = &di_shared->slots[slot_idx];
|
||||
DI_Stripe *stripe = &di_shared->stripes[stripe_idx];
|
||||
log_infof("close_debug_info: {\"%S\", 0x%I64x}\n", key_normalized.path, key_normalized.min_timestamp);
|
||||
B32 closed = 0;
|
||||
log_infof("close_debug_info: {\"%S\", 0x%I64x}\n", key->path, key->min_timestamp);
|
||||
OS_MutexScopeW(stripe->rw_mutex)
|
||||
{
|
||||
//- rjf: find existing node
|
||||
DI_Node *node = di_node_from_key_slot__stripe_mutex_r_guarded(slot, &key_normalized);
|
||||
DI_Node *node = di_node_from_key_slot__stripe_mutex_r_guarded(slot, key);
|
||||
|
||||
//- rjf: node exists -> decrement reference count; release
|
||||
if(node != 0)
|
||||
@@ -568,7 +565,7 @@ di_close(DI_Key *key)
|
||||
break;
|
||||
}
|
||||
|
||||
//- rjf: wait for touch count to go to 0
|
||||
//- rjf: wait for touch count / working marker to go to 0
|
||||
os_condition_variable_wait_rw_w(stripe->cv, stripe->rw_mutex, max_U64);
|
||||
}
|
||||
}
|
||||
@@ -582,15 +579,14 @@ di_close(DI_Key *key)
|
||||
//~ rjf: Debug Info Cache Lookups
|
||||
|
||||
internal RDI_Parsed *
|
||||
di_rdi_from_key(DI_Scope *scope, DI_Key *key, U64 endt_us)
|
||||
di_rdi_from_key(DI_Scope *scope, DI_Key *key, B32 high_priority, U64 endt_us)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
RDI_Parsed *result = &rdi_parsed_nil;
|
||||
if(key->path.size != 0)
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
DI_Key key_normalized = di_normalized_key_from_key(scratch.arena, key);
|
||||
U64 hash = di_hash_from_key(&key_normalized);
|
||||
U64 hash = di_hash_from_key(key);
|
||||
U64 slot_idx = hash%di_shared->slots_count;
|
||||
U64 stripe_idx = slot_idx%di_shared->stripes_count;
|
||||
DI_Slot *slot = &di_shared->slots[slot_idx];
|
||||
@@ -598,7 +594,7 @@ di_rdi_from_key(DI_Scope *scope, DI_Key *key, U64 endt_us)
|
||||
ProfScope("grab node") OS_MutexScopeR(stripe->rw_mutex) for(;;)
|
||||
{
|
||||
//- rjf: find existing node
|
||||
DI_Node *node = di_node_from_key_slot__stripe_mutex_r_guarded(slot, &key_normalized);
|
||||
DI_Node *node = di_node_from_key_slot__stripe_mutex_r_guarded(slot, key);
|
||||
|
||||
//- rjf: no node? this path is not opened
|
||||
if(node == 0)
|
||||
@@ -624,14 +620,14 @@ di_rdi_from_key(DI_Scope *scope, DI_Key *key, U64 endt_us)
|
||||
if(node != 0 &&
|
||||
!node->parse_done &&
|
||||
!ins_atomic_u64_eval(&node->is_working) &&
|
||||
di_u2p_enqueue_key(&key_normalized, endt_us))
|
||||
di_u2p_enqueue_key(key, endt_us))
|
||||
{
|
||||
ProfScope("ask for parse")
|
||||
{
|
||||
ins_atomic_u64_eval_assign(&node->is_working, 1);
|
||||
DeferLoop(os_rw_mutex_drop_r(stripe->rw_mutex), os_rw_mutex_take_r(stripe->rw_mutex))
|
||||
{
|
||||
async_push_work(di_parse_work);
|
||||
async_push_work(di_parse_work, .priority = high_priority ? ASYNC_Priority_High : ASYNC_Priority_Low);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1129,6 +1125,16 @@ ASYNC_WORK_DEF(di_parse_work)
|
||||
node->rdi = rdi_parsed;
|
||||
node->parse_done = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(rdi_parsed_arena != 0)
|
||||
{
|
||||
arena_release(rdi_parsed_arena);
|
||||
}
|
||||
os_file_map_view_close(file_map, file_base, r1u64(0, file_props.size));
|
||||
os_file_map_close(file_map);
|
||||
os_file_close(file);
|
||||
}
|
||||
}
|
||||
os_condition_variable_broadcast(stripe->cv);
|
||||
|
||||
@@ -1253,6 +1259,10 @@ ASYNC_WORK_DEF(di_search_work)
|
||||
{
|
||||
// NOTE(rjf): name must be determined from self_type_idx
|
||||
}break;
|
||||
case RDI_SectionKind_SourceFiles:
|
||||
{
|
||||
// NOTE(rjf): name must be determined from file path node chain
|
||||
}break;
|
||||
}
|
||||
|
||||
//- rjf: loop through table, gather matches
|
||||
@@ -1281,17 +1291,42 @@ ASYNC_WORK_DEF(di_search_work)
|
||||
|
||||
//- rjf: get element, map to string; if empty, continue to next element
|
||||
void *element = (U8 *)table_base + element_size*idx;
|
||||
U32 *name_idx_ptr = (U32 *)((U8 *)element + element_name_idx_off);
|
||||
if(in->section_kind == RDI_SectionKind_UDTs)
|
||||
String8 name = {0};
|
||||
switch(in->section_kind)
|
||||
{
|
||||
RDI_UDT *udt = (RDI_UDT *)element;
|
||||
RDI_TypeNode *type_node = rdi_element_from_name_idx(in->rdi, TypeNodes, udt->self_type_idx);
|
||||
name_idx_ptr = &type_node->user_defined.name_string_idx;
|
||||
case RDI_SectionKind_UDTs:
|
||||
{
|
||||
RDI_UDT *udt = (RDI_UDT *)element;
|
||||
RDI_TypeNode *type_node = rdi_element_from_name_idx(in->rdi, TypeNodes, udt->self_type_idx);
|
||||
name.str = rdi_string_from_idx(in->rdi, type_node->user_defined.name_string_idx, &name.size);
|
||||
name = str8_copy(arena, name);
|
||||
}break;
|
||||
case RDI_SectionKind_SourceFiles:
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
RDI_SourceFile *file = (RDI_SourceFile *)element;
|
||||
String8List path_parts = {0};
|
||||
for(RDI_FilePathNode *fpn = rdi_element_from_name_idx(in->rdi, FilePathNodes, file->file_path_node_idx);
|
||||
fpn != rdi_element_from_name_idx(in->rdi, FilePathNodes, 0);
|
||||
fpn = rdi_element_from_name_idx(in->rdi, FilePathNodes, fpn->parent_path_node))
|
||||
{
|
||||
String8 path_part = {0};
|
||||
path_part.str = rdi_string_from_idx(in->rdi, fpn->name_string_idx, &path_part.size);
|
||||
str8_list_push_front(scratch.arena, &path_parts, path_part);
|
||||
}
|
||||
StringJoin join = {0};
|
||||
join.sep = str8_lit("/");
|
||||
name = str8_list_join(arena, &path_parts, &join);
|
||||
scratch_end(scratch);
|
||||
}break;
|
||||
default:
|
||||
{
|
||||
U32 name_idx = *(U32 *)((U8 *)element + element_name_idx_off);
|
||||
U64 name_size = 0;
|
||||
U8 *name_base = rdi_string_from_idx(in->rdi, name_idx, &name_size);
|
||||
name = str8(name_base, name_size);
|
||||
}break;
|
||||
}
|
||||
U32 name_idx = *name_idx_ptr;
|
||||
U64 name_size = 0;
|
||||
U8 *name_base = rdi_string_from_idx(in->rdi, name_idx, &name_size);
|
||||
String8 name = str8(name_base, name_size);
|
||||
if(name.size == 0) { continue; }
|
||||
|
||||
//- rjf: fuzzy match against query
|
||||
@@ -1313,7 +1348,7 @@ ASYNC_WORK_DEF(di_search_work)
|
||||
chunk->v[chunk->count].idx = idx;
|
||||
chunk->v[chunk->count].dbgi_idx = in->dbgi_idx;
|
||||
chunk->v[chunk->count].match_ranges = matches;
|
||||
chunk->v[chunk->count].missed_size = (name_size > matches.total_dim) ? (name_size-matches.total_dim) : 0;
|
||||
chunk->v[chunk->count].missed_size = (name.size > matches.total_dim) ? (name.size-matches.total_dim) : 0;
|
||||
chunk->count += 1;
|
||||
out->items.total_count += 1;
|
||||
}
|
||||
@@ -1392,7 +1427,7 @@ di_search_thread__entry_point(void *p)
|
||||
RDI_Parsed **rdis = push_array(scratch.arena, RDI_Parsed *, rdis_count);
|
||||
for EachIndex(idx, rdis_count)
|
||||
{
|
||||
rdis[idx] = di_rdi_from_key(di_scope, ¶ms.dbgi_keys.v[idx], max_U64);
|
||||
rdis[idx] = di_rdi_from_key(di_scope, ¶ms.dbgi_keys.v[idx], 1, max_U64);
|
||||
}
|
||||
|
||||
//- rjf: kick off search tasks
|
||||
@@ -1584,6 +1619,10 @@ di_match_store_alloc(void)
|
||||
store->u2m_ring_mutex = os_mutex_alloc();
|
||||
store->u2m_ring_size = KB(2);
|
||||
store->u2m_ring_base = push_array_no_zero(arena, U8, store->u2m_ring_size);
|
||||
store->m2u_ring_cv = os_condition_variable_alloc();
|
||||
store->m2u_ring_mutex = os_mutex_alloc();
|
||||
store->m2u_ring_size = KB(2);
|
||||
store->m2u_ring_base = push_array_no_zero(arena, U8, store->m2u_ring_size);
|
||||
return store;
|
||||
}
|
||||
|
||||
@@ -1632,13 +1671,22 @@ di_match_store_begin(DI_MatchStore *store, DI_KeyArray keys)
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: pop new matches
|
||||
#if 0
|
||||
for(;;)
|
||||
{
|
||||
U64 unconsumed_size = store->m2u_ring_write_pos - store->m2u_ring_read_pos;
|
||||
}
|
||||
#endif
|
||||
|
||||
ProfEnd();
|
||||
}
|
||||
|
||||
internal RDI_SectionKind
|
||||
di_match_store_section_kind_from_name(DI_MatchStore *store, String8 name, U64 endt_us)
|
||||
internal DI_Match
|
||||
di_match_from_name(DI_MatchStore *store, String8 name, U64 endt_us)
|
||||
{
|
||||
RDI_SectionKind result = 0;
|
||||
DI_Match result = {0};
|
||||
if(name.size != 0)
|
||||
{
|
||||
// rjf: unpack name
|
||||
U64 hash = di_hash_from_string(name, 0);
|
||||
@@ -1737,7 +1785,12 @@ di_match_store_section_kind_from_name(DI_MatchStore *store, String8 name, U64 en
|
||||
}
|
||||
|
||||
// rjf: return node present info
|
||||
result = node->section_kind;
|
||||
result = node->primary_match;
|
||||
if(node->cmp_params_hash != store->params_hash)
|
||||
{
|
||||
result.dbgi_idx = 0;
|
||||
result.idx = 0;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -1777,11 +1830,18 @@ ASYNC_WORK_DEF(di_match_work)
|
||||
params_hash = store->params_hash;
|
||||
}
|
||||
|
||||
//- rjf: do match
|
||||
//- rjf: zero match info
|
||||
ins_atomic_u64_eval_assign(&node->primary_match.dbgi_idx, 0);
|
||||
ins_atomic_u32_eval_assign(&node->primary_match.idx, 0);
|
||||
|
||||
//- rjf: gather matches
|
||||
DI_MatchNode *first_match = 0;
|
||||
DI_MatchNode *last_match = 0;
|
||||
RDI_NameMapKind name_map_kinds[] =
|
||||
{
|
||||
RDI_NameMapKind_GlobalVariables,
|
||||
RDI_NameMapKind_ThreadVariables,
|
||||
RDI_NameMapKind_Constants,
|
||||
RDI_NameMapKind_Procedures,
|
||||
RDI_NameMapKind_Types,
|
||||
};
|
||||
@@ -1789,6 +1849,7 @@ ASYNC_WORK_DEF(di_match_work)
|
||||
{
|
||||
RDI_SectionKind_GlobalVariables,
|
||||
RDI_SectionKind_ThreadVariables,
|
||||
RDI_SectionKind_Constants,
|
||||
RDI_SectionKind_Procedures,
|
||||
RDI_SectionKind_TypeNodes,
|
||||
};
|
||||
@@ -1798,7 +1859,7 @@ ASYNC_WORK_DEF(di_match_work)
|
||||
{
|
||||
DI_Scope *di_scope = di_scope_open();
|
||||
DI_Key key = params_keys.v[dbgi_idx];
|
||||
RDI_Parsed *rdi = di_rdi_from_key(di_scope, &key, os_now_microseconds()+1000);
|
||||
RDI_Parsed *rdi = di_rdi_from_key(di_scope, &key, 1, os_now_microseconds()+1000);
|
||||
for EachElement(name_map_kind_idx, name_map_kinds)
|
||||
{
|
||||
RDI_NameMap *name_map = rdi_element_from_name_idx(rdi, NameMaps, name_map_kinds[name_map_kind_idx]);
|
||||
@@ -1809,7 +1870,20 @@ ASYNC_WORK_DEF(di_match_work)
|
||||
U32 *run = rdi_matches_from_map_node(rdi, map_node, &num);
|
||||
if(num != 0)
|
||||
{
|
||||
ins_atomic_u32_eval_assign(&node->section_kind, name_map_section_kinds[name_map_kind_idx]);
|
||||
// rjf: atomically update the node's primary match
|
||||
ins_atomic_u64_eval_assign(&node->primary_match.dbgi_idx, dbgi_idx);
|
||||
ins_atomic_u32_eval_assign(&node->primary_match.section, name_map_section_kinds[name_map_kind_idx]);
|
||||
ins_atomic_u32_eval_assign(&node->primary_match.idx, run[0]);
|
||||
|
||||
// rjf: gather all alternate matches
|
||||
for(U32 match_idx = 1; match_idx < num; match_idx += 1)
|
||||
{
|
||||
DI_MatchNode *m = push_array(scratch.arena, DI_MatchNode, 1);
|
||||
SLLQueuePush(first_match, last_match, m);
|
||||
m->v.dbgi_idx = dbgi_idx;
|
||||
m->v.section = name_map_section_kinds[name_map_kind_idx];
|
||||
m->v.idx = run[match_idx];
|
||||
}
|
||||
}
|
||||
}
|
||||
di_scope_close(di_scope);
|
||||
|
||||
+20
-7
@@ -263,13 +263,18 @@ struct DI_SearchThread
|
||||
typedef struct DI_Match DI_Match;
|
||||
struct DI_Match
|
||||
{
|
||||
DI_Match *next;
|
||||
DI_Match *prev;
|
||||
U64 dbgi_idx;
|
||||
RDI_SectionKind section;
|
||||
U32 idx;
|
||||
};
|
||||
|
||||
typedef struct DI_MatchNode DI_MatchNode;
|
||||
struct DI_MatchNode
|
||||
{
|
||||
DI_MatchNode *next;
|
||||
DI_Match v;
|
||||
};
|
||||
|
||||
typedef struct DI_MatchNameNode DI_MatchNameNode;
|
||||
struct DI_MatchNameNode
|
||||
{
|
||||
@@ -289,9 +294,9 @@ struct DI_MatchNameNode
|
||||
// rjf: atomically written by match work
|
||||
U64 cmp_count;
|
||||
U64 cmp_params_hash;
|
||||
RDI_SectionKind section_kind;
|
||||
// DI_Match *first_match;
|
||||
// DI_Match *last_match;
|
||||
DI_Match primary_match;
|
||||
// DI_MatchNode *first_alt_match;
|
||||
// DI_MatchNode *last_alt_match;
|
||||
};
|
||||
|
||||
typedef struct DI_MatchNameSlot DI_MatchNameSlot;
|
||||
@@ -332,6 +337,14 @@ struct DI_MatchStore
|
||||
U8 *u2m_ring_base;
|
||||
U64 u2m_ring_write_pos;
|
||||
U64 u2m_ring_read_pos;
|
||||
|
||||
// rjf: match -> user work ring buffer
|
||||
OS_Handle m2u_ring_cv;
|
||||
OS_Handle m2u_ring_mutex;
|
||||
U64 m2u_ring_size;
|
||||
U8 *m2u_ring_base;
|
||||
U64 m2u_ring_write_pos;
|
||||
U64 m2u_ring_read_pos;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
@@ -435,7 +448,7 @@ internal void di_close(DI_Key *key);
|
||||
////////////////////////////////
|
||||
//~ rjf: Debug Info Cache Lookups
|
||||
|
||||
internal RDI_Parsed *di_rdi_from_key(DI_Scope *scope, DI_Key *key, U64 endt_us);
|
||||
internal RDI_Parsed *di_rdi_from_key(DI_Scope *scope, DI_Key *key, B32 high_priority, U64 endt_us);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Search Cache Lookups
|
||||
@@ -470,7 +483,7 @@ internal void di_search_evictor_thread__entry_point(void *p);
|
||||
|
||||
internal DI_MatchStore *di_match_store_alloc(void);
|
||||
internal void di_match_store_begin(DI_MatchStore *store, DI_KeyArray keys);
|
||||
internal RDI_SectionKind di_match_store_section_kind_from_name(DI_MatchStore *store, String8 name, U64 endt_us);
|
||||
internal DI_Match di_match_from_name(DI_MatchStore *store, String8 name, U64 endt_us);
|
||||
ASYNC_WORK_DEF(di_match_work);
|
||||
|
||||
#endif // DBGI_H
|
||||
|
||||
@@ -139,6 +139,7 @@ struct DMN_TrapChunkList
|
||||
typedef struct DMN_RunCtrls DMN_RunCtrls;
|
||||
struct DMN_RunCtrls
|
||||
{
|
||||
DMN_Handle priority_thread;
|
||||
DMN_Handle single_step_thread;
|
||||
B8 ignore_previous_exception;
|
||||
B8 run_entities_are_unfrozen;
|
||||
@@ -221,11 +222,6 @@ internal void dmn_halt(U64 code, U64 user_data);
|
||||
////////////////////////////////
|
||||
//~ rjf: @dmn_os_hooks Introspection Functions (Implemented Per-OS)
|
||||
|
||||
//- rjf: run/memory/register counters
|
||||
internal U64 dmn_run_gen(void);
|
||||
internal U64 dmn_mem_gen(void);
|
||||
internal U64 dmn_reg_gen(void);
|
||||
|
||||
//- rjf: non-blocking-control-thread access barriers
|
||||
internal B32 dmn_access_open(void);
|
||||
internal void dmn_access_close(void);
|
||||
|
||||
+1661
-29
File diff suppressed because it is too large
Load Diff
@@ -4,4 +4,334 @@
|
||||
#ifndef DEMON_CORE_LINUX_H
|
||||
#define DEMON_CORE_LINUX_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Includes
|
||||
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/uio.h>
|
||||
#include <unistd.h>
|
||||
#include <elf.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: ptrace options
|
||||
|
||||
#define DMN_LNX_PTRACE_OPTIONS (PTRACE_O_TRACEEXIT|\
|
||||
PTRACE_O_EXITKILL|\
|
||||
PTRACE_O_TRACEFORK|\
|
||||
PTRACE_O_TRACEVFORK|\
|
||||
PTRACE_O_TRACECLONE)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Register Layouts
|
||||
//
|
||||
// These are defined in <sys/user.h>, but only for one architecture at a time
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
typedef struct DMN_LNX_UserRegsX64 DMN_LNX_UserRegsX64;
|
||||
struct DMN_LNX_UserRegsX64
|
||||
{
|
||||
U64 r15;
|
||||
U64 r14;
|
||||
U64 r13;
|
||||
U64 r12;
|
||||
U64 rbp;
|
||||
U64 rbx;
|
||||
U64 r11;
|
||||
U64 r10;
|
||||
U64 r9;
|
||||
U64 r8;
|
||||
U64 rax;
|
||||
U64 rcx;
|
||||
U64 rdx;
|
||||
U64 rsi;
|
||||
U64 rdi;
|
||||
U64 orig_rax;
|
||||
U64 rip;
|
||||
U64 cs;
|
||||
U64 rflags;
|
||||
U64 rsp;
|
||||
U64 ss;
|
||||
U64 fsbase;
|
||||
U64 gsbase;
|
||||
U64 ds;
|
||||
U64 es;
|
||||
U64 fs;
|
||||
U64 gs;
|
||||
};
|
||||
|
||||
typedef struct DMN_LNX_XSaveLegacy DMN_LNX_XSaveLegacy;
|
||||
struct DMN_LNX_XSaveLegacy
|
||||
{
|
||||
U16 fcw;
|
||||
U16 fsw;
|
||||
U16 ftw;
|
||||
U16 fop;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
U64 fip;
|
||||
U64 fdp;
|
||||
} b64;
|
||||
struct
|
||||
{
|
||||
U32 fip;
|
||||
U16 fcs, _pad0;
|
||||
U32 fdp;
|
||||
U16 fds, _pad1;
|
||||
} b32;
|
||||
};
|
||||
U32 mxcsr;
|
||||
U32 mxcsr_mask;
|
||||
U128 st_space;
|
||||
U256 xmm_space;
|
||||
U8 padding[96];
|
||||
};
|
||||
|
||||
typedef struct DMN_LNX_XSaveHeader DMN_LNX_XSaveHeader;
|
||||
struct DMN_LNX_XSaveHeader
|
||||
{
|
||||
U64 xstate_bv;
|
||||
U64 xcomp_bv;
|
||||
U8 reserved[48];
|
||||
};
|
||||
|
||||
// TODO(rjf):
|
||||
//
|
||||
// this one is hacked; ymmh is not gauranteed to be at a fixed location
|
||||
// and there can be more after that. Requires CPUID to be totally compliant to the standard.
|
||||
// See intel's manual on the xsave format for more info.
|
||||
//
|
||||
typedef struct DMN_LNX_XSave DMN_LNX_XSave;
|
||||
struct DMN_LNX_XSave
|
||||
{
|
||||
DMN_LNX_XSaveLegacy legacy;
|
||||
DMN_LNX_XSaveHeader header;
|
||||
U8 ymmh[256];
|
||||
};
|
||||
|
||||
typedef struct DMN_LNX_UserX64 DMN_LNX_UserX64;
|
||||
struct DMN_LNX_UserX64
|
||||
{
|
||||
DMN_LNX_UserRegsX64 regs;
|
||||
S32 u_fpvalid, _pad0;
|
||||
DMN_LNX_XSaveLegacy i387;
|
||||
U64 u_tsize, u_dsize, u_ssize, start_code, start_stack;
|
||||
U64 signal;
|
||||
S32 reserved, _pad1;
|
||||
U64 u_ar0, u_fpstate;
|
||||
U64 magic;
|
||||
U8 u_comm[32];
|
||||
U64 u_debugreg[8];
|
||||
};
|
||||
|
||||
typedef struct DMN_LNX_UserRegsX86 DMN_LNX_UserRegsX86;
|
||||
struct DMN_LNX_UserRegsX86
|
||||
{
|
||||
U32 ebx;
|
||||
U32 ecx;
|
||||
U32 edx;
|
||||
U32 esi;
|
||||
U32 edi;
|
||||
U32 ebp;
|
||||
U32 eax;
|
||||
U32 ds;
|
||||
U32 es;
|
||||
U32 fs;
|
||||
U32 gs;
|
||||
U32 orig_eax;
|
||||
U32 eip;
|
||||
U32 cs;
|
||||
U32 eflags;
|
||||
U32 sp;
|
||||
U32 ss;
|
||||
};
|
||||
|
||||
// NOTE(rjf): (32-Bit Protected Mode Format)
|
||||
typedef struct DMN_LNX_FSave DMN_LNX_FSave;
|
||||
struct DMN_LNX_FSave
|
||||
{
|
||||
// control registers
|
||||
U16 fcw;
|
||||
U16 _pad0;
|
||||
U16 fsw;
|
||||
U16 _pad1;
|
||||
U16 ftw;
|
||||
U16 _pad2;
|
||||
U32 fip;
|
||||
U16 fips;
|
||||
U16 fop;
|
||||
U32 fdp;
|
||||
U16 fds;
|
||||
U16 _pad3;
|
||||
|
||||
// data registers
|
||||
U8 st[80];
|
||||
};
|
||||
|
||||
typedef struct DMN_LNX_UserX86 DMN_LNX_UserX86;
|
||||
struct DMN_LNX_UserX86
|
||||
{
|
||||
DMN_LNX_UserRegsX86 regs;
|
||||
S32 u_fpvalid;
|
||||
DMN_LNX_FSave i387;
|
||||
U32 u_tsize, u_dsize, u_ssize, start_code, start_stack;
|
||||
S32 signal, reserved;
|
||||
U32 u_ar0, u_fpstate;
|
||||
U32 magic;
|
||||
U8 u_comm[32];
|
||||
U32 u_debugreg[8];
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Process Info Extraction Types
|
||||
|
||||
typedef struct DMN_LNX_ProcessAux DMN_LNX_ProcessAux;
|
||||
struct DMN_LNX_ProcessAux
|
||||
{
|
||||
B32 filled;
|
||||
U64 phnum;
|
||||
U64 phent;
|
||||
U64 phdr;
|
||||
U64 execfn;
|
||||
U64 pagesz;
|
||||
};
|
||||
|
||||
typedef struct DMN_LNX_PhdrInfo DMN_LNX_PhdrInfo;
|
||||
struct DMN_LNX_PhdrInfo
|
||||
{
|
||||
Rng1U64 range;
|
||||
U64 dynamic;
|
||||
};
|
||||
|
||||
typedef struct DMN_LNX_ModuleInfo DMN_LNX_ModuleInfo;
|
||||
struct DMN_LNX_ModuleInfo
|
||||
{
|
||||
Rng1U64 vaddr_range;
|
||||
U64 name;
|
||||
};
|
||||
|
||||
typedef struct DMN_LNX_ModuleInfoNode DMN_LNX_ModuleInfoNode;
|
||||
struct DMN_LNX_ModuleInfoNode
|
||||
{
|
||||
DMN_LNX_ModuleInfoNode *next;
|
||||
DMN_LNX_ModuleInfo v;
|
||||
};
|
||||
|
||||
typedef struct DMN_LNX_ModuleInfoList DMN_LNX_ModuleInfoList;
|
||||
struct DMN_LNX_ModuleInfoList
|
||||
{
|
||||
DMN_LNX_ModuleInfoNode *first;
|
||||
DMN_LNX_ModuleInfoNode *last;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Entity Types
|
||||
|
||||
typedef enum DMN_LNX_EntityKind
|
||||
{
|
||||
DMN_LNX_EntityKind_Null,
|
||||
DMN_LNX_EntityKind_Root,
|
||||
DMN_LNX_EntityKind_Process,
|
||||
DMN_LNX_EntityKind_Thread,
|
||||
DMN_LNX_EntityKind_Module,
|
||||
DMN_LNX_EntityKind_COUNT
|
||||
}
|
||||
DMN_LNX_EntityKind;
|
||||
|
||||
typedef struct DMN_LNX_Entity DMN_LNX_Entity;
|
||||
struct DMN_LNX_Entity
|
||||
{
|
||||
DMN_LNX_Entity *first;
|
||||
DMN_LNX_Entity *last;
|
||||
DMN_LNX_Entity *next;
|
||||
DMN_LNX_Entity *prev;
|
||||
DMN_LNX_Entity *parent;
|
||||
DMN_LNX_EntityKind kind;
|
||||
U32 gen;
|
||||
Arch arch;
|
||||
U64 id;
|
||||
int fd;
|
||||
B32 expecting_dummy_sigstop;
|
||||
};
|
||||
|
||||
typedef struct DMN_LNX_EntityNode DMN_LNX_EntityNode;
|
||||
struct DMN_LNX_EntityNode
|
||||
{
|
||||
DMN_LNX_EntityNode *next;
|
||||
DMN_LNX_Entity *v;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Main State Bundle
|
||||
|
||||
typedef struct DMN_LNX_State DMN_LNX_State;
|
||||
struct DMN_LNX_State
|
||||
{
|
||||
Arena *arena;
|
||||
|
||||
// rjf: access locking mechanism
|
||||
OS_Handle access_mutex;
|
||||
B32 access_run_state;
|
||||
|
||||
// rjf: deferred events
|
||||
Arena *deferred_events_arena;
|
||||
DMN_EventList deferred_events;
|
||||
|
||||
// rjf: entity storage
|
||||
Arena *entities_arena;
|
||||
DMN_LNX_Entity *entities_base;
|
||||
U64 entities_count;
|
||||
DMN_LNX_Entity *free_entity;
|
||||
|
||||
// rjf: halting mechanism
|
||||
B32 has_halt_injection;
|
||||
U64 halt_code;
|
||||
U64 halt_user_data;
|
||||
};
|
||||
|
||||
read_only global DMN_LNX_Entity dmn_lnx_nil_entity = {&dmn_lnx_nil_entity, &dmn_lnx_nil_entity, &dmn_lnx_nil_entity, &dmn_lnx_nil_entity, &dmn_lnx_nil_entity};
|
||||
global DMN_LNX_State *dmn_lnx_state = 0;
|
||||
thread_static B32 dmn_lnx_ctrl_thread = 0;
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Helpers
|
||||
|
||||
//- rjf: file descriptor memory reading/writing helpers
|
||||
internal U64 dmn_lnx_read(int memory_fd, Rng1U64 range, void *dst);
|
||||
internal B32 dmn_lnx_write(int memory_fd, Rng1U64 range, void *src);
|
||||
#define dmn_lnx_read_struct(fd, vaddr, ptr) dmn_lnx_read((fd), r1u64((vaddr), (vaddr)+sizeof(*(ptr))), (ptr))
|
||||
#define dmn_lnx_write_struct(fd, vaddr, ptr) dmn_lnx_write((fd), r1u64((vaddr), (vaddr)+sizeof(*(ptr))), (ptr))
|
||||
internal String8 dmn_lnx_read_string(Arena *arena, int memory_fd, U64 base_vaddr);
|
||||
|
||||
//- rjf: pid => info extraction
|
||||
internal String8 dmn_lnx_exe_path_from_pid(Arena *arena, pid_t pid);
|
||||
internal Arch dmn_lnx_arch_from_pid(pid_t pid);
|
||||
internal DMN_LNX_ProcessAux dmn_lnx_aux_from_pid(pid_t pid, Arch arch);
|
||||
|
||||
//- rjf: phdr info extraction
|
||||
internal DMN_LNX_PhdrInfo dmn_lnx_phdr_info_from_memory(int memory_fd, B32 is_32bit, U64 phvaddr, U64 phsize, U64 phcount);
|
||||
|
||||
//- rjf: process entity => info extraction
|
||||
internal DMN_LNX_ModuleInfoList dmn_lnx_module_info_list_from_process(Arena *arena, DMN_LNX_Entity *process);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Entity Functions
|
||||
|
||||
internal DMN_LNX_Entity *dmn_lnx_entity_alloc(DMN_LNX_Entity *parent, DMN_LNX_EntityKind kind);
|
||||
internal void dmn_lnx_entity_release(DMN_LNX_Entity *entity);
|
||||
internal DMN_Handle dmn_lnx_handle_from_entity(DMN_LNX_Entity *entity);
|
||||
internal DMN_LNX_Entity *dmn_lnx_entity_from_handle(DMN_Handle handle);
|
||||
internal DMN_LNX_Entity *dmn_lnx_thread_from_pid(pid_t pid);
|
||||
internal B32 dmn_lnx_thread_read_reg_block(DMN_LNX_Entity *thread, void *reg_block);
|
||||
internal B32 dmn_lnx_thread_write_reg_block(DMN_LNX_Entity *thread, void *reg_block);
|
||||
|
||||
#endif // DEMON_CORE_LINUX_H
|
||||
|
||||
@@ -320,7 +320,10 @@ dmn_w32_process_read(HANDLE process, Rng1U64 range, void *dst)
|
||||
SIZE_T actual_read = 0;
|
||||
if(!ReadProcessMemory(process, (LPCVOID)cursor, ptr, to_read, &actual_read))
|
||||
{
|
||||
DWORD error = GetLastError();
|
||||
log_infof("'Win32 ReadProcessMemory failure': { [0x%I64x, 0x%I64x), code: %i }\n", range.min, range.max, error);
|
||||
bytes_read += actual_read;
|
||||
(void)error;
|
||||
break;
|
||||
}
|
||||
ptr += actual_read;
|
||||
@@ -349,7 +352,6 @@ dmn_w32_process_write(HANDLE process, Rng1U64 range, void *src)
|
||||
ptr += actual_write;
|
||||
cursor += actual_write;
|
||||
}
|
||||
ins_atomic_u64_inc_eval(&dmn_w32_shared->mem_gen);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -766,8 +768,8 @@ dmn_w32_thread_read_reg_block(Arch arch, HANDLE thread, void *reg_block)
|
||||
dst->fop.u16 = xsave->ErrorOpcode;
|
||||
dst->fcs.u16 = xsave->ErrorSelector;
|
||||
dst->fds.u16 = xsave->DataSelector;
|
||||
dst->fip.u32 = xsave->ErrorOffset;
|
||||
dst->fdp.u32 = xsave->DataOffset;
|
||||
dst->fip.u64 = xsave->ErrorOffset;
|
||||
dst->fdp.u64 = xsave->DataOffset;
|
||||
dst->mxcsr.u32 = xsave->MxCsr;
|
||||
dst->mxcsr_mask.u32 = xsave->MxCsr_Mask;
|
||||
{
|
||||
@@ -1035,8 +1037,8 @@ dmn_w32_thread_write_reg_block(Arch arch, HANDLE thread, void *reg_block)
|
||||
fxsave->ErrorOpcode = src->fop.u16;
|
||||
fxsave->ErrorSelector = src->fcs.u16;
|
||||
fxsave->DataSelector = src->fds.u16;
|
||||
fxsave->ErrorOffset = src->fip.u32;
|
||||
fxsave->DataOffset = src->fdp.u32;
|
||||
fxsave->ErrorOffset = src->fip.u64;
|
||||
fxsave->DataOffset = src->fdp.u64;
|
||||
{
|
||||
M128A *float_d = fxsave->FloatRegisters;
|
||||
REGS_Reg80 *float_s = &src->fpr0;
|
||||
@@ -1112,7 +1114,6 @@ dmn_w32_thread_write_reg_block(Arch arch, HANDLE thread, void *reg_block)
|
||||
scratch_end(scratch);
|
||||
}break;
|
||||
}
|
||||
ins_atomic_u64_inc_eval(&dmn_w32_shared->reg_gen);
|
||||
ProfEnd();
|
||||
return result;
|
||||
}
|
||||
@@ -1541,7 +1542,6 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
|
||||
U64 new_rflags = rflags | 0x100;
|
||||
single_step_thread_ctx->EFlags = new_rflags;
|
||||
SetThreadContext(thread->handle, single_step_thread_ctx);
|
||||
ins_atomic_u64_inc_eval(&dmn_w32_shared->reg_gen);
|
||||
}
|
||||
}break;
|
||||
}
|
||||
@@ -1684,6 +1684,7 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
|
||||
}break;
|
||||
case DMN_TrapFlag_BreakOnRead|DMN_TrapFlag_BreakOnWrite|DMN_TrapFlag_BreakOnExecute:
|
||||
case DMN_TrapFlag_BreakOnRead|DMN_TrapFlag_BreakOnWrite:
|
||||
case DMN_TrapFlag_BreakOnRead:
|
||||
{
|
||||
regs.dr7.u64 |= (((U64)bit17) << (trap_idx*4));
|
||||
regs.dr7.u64 |= (((U64)bit18) << (trap_idx*4));
|
||||
@@ -1801,40 +1802,14 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////
|
||||
//- rjf: resume threads which will run
|
||||
//
|
||||
ProfScope("resume threads which will run")
|
||||
{
|
||||
for(DMN_W32_EntityNode *n = first_run_thread; n != 0; n = n->next)
|
||||
{
|
||||
DMN_W32_Entity *thread = n->v;
|
||||
DWORD resume_result = ResumeThread(thread->handle);
|
||||
switch(resume_result)
|
||||
{
|
||||
case 0xffffffffu:
|
||||
{
|
||||
// TODO(rjf): error - unknown cause. need to do GetLastError, FormatMessage
|
||||
}break;
|
||||
default:
|
||||
{
|
||||
DWORD desired_counter = 0;
|
||||
DWORD current_counter = resume_result - 1;
|
||||
if(current_counter != desired_counter)
|
||||
{
|
||||
// NOTE(rjf): Warning. The user has manually suspended this thread,
|
||||
// so even though from Demon's perspective it thinks this thread
|
||||
// should run, it will not, because the user has manually called
|
||||
// SuspendThread or used CREATE_SUSPENDED or whatever.
|
||||
}
|
||||
}break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////
|
||||
//- rjf: loop, consume win32 debug events until we produce the relevant demon events
|
||||
//
|
||||
B32 priority_mode = !dmn_handle_match(dmn_handle_zero(), ctrls->priority_thread);
|
||||
B32 did_priority_mode = priority_mode;
|
||||
B32 do_threads_resume = 1;
|
||||
DMN_W32_EntityNode *first_ran_thread = 0;
|
||||
DMN_W32_EntityNode *last_ran_thread = 0;
|
||||
U64 begin_time = os_now_microseconds();
|
||||
String8List debug_strings = {0};
|
||||
DMN_Event *debug_strings_event = 0;
|
||||
@@ -1842,6 +1817,54 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
|
||||
{
|
||||
keep_going = 0;
|
||||
|
||||
////////////////////////
|
||||
//- rjf: resume threads that we want to run
|
||||
//
|
||||
// if priority mode? => first, just resume priority thread
|
||||
// if not? => resume all non-priority threads
|
||||
//
|
||||
if(do_threads_resume) ProfScope("resume threads that we want to run")
|
||||
{
|
||||
do_threads_resume = 0;
|
||||
for(DMN_W32_EntityNode *n = first_run_thread; n != 0; n = n->next)
|
||||
{
|
||||
DMN_W32_Entity *thread = n->v;
|
||||
B32 thread_is_priority = dmn_handle_match(dmn_w32_handle_from_entity(thread), ctrls->priority_thread);
|
||||
if((priority_mode && !thread_is_priority) ||
|
||||
(!priority_mode && did_priority_mode && thread_is_priority))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
DWORD resume_result = ResumeThread(thread->handle);
|
||||
DMN_W32_EntityNode *n = push_array(scratch.arena, DMN_W32_EntityNode, 1);
|
||||
SLLQueuePush(first_ran_thread, last_ran_thread, n);
|
||||
n->v = thread;
|
||||
switch(resume_result)
|
||||
{
|
||||
case 0xffffffffu:
|
||||
{
|
||||
// TODO(rjf): error - unknown cause. need to do GetLastError, FormatMessage
|
||||
}break;
|
||||
default:
|
||||
{
|
||||
DWORD desired_counter = 0;
|
||||
DWORD current_counter = resume_result - 1;
|
||||
if(current_counter != desired_counter)
|
||||
{
|
||||
// NOTE(rjf): Warning. The user has manually suspended this thread,
|
||||
// so even though from Demon's perspective it thinks this thread
|
||||
// should run, it will not, because the user has manually called
|
||||
// SuspendThread or used CREATE_SUSPENDED or whatever.
|
||||
}
|
||||
}break;
|
||||
}
|
||||
if(priority_mode && thread_is_priority)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////
|
||||
//- rjf: choose win32 resume code
|
||||
//
|
||||
@@ -1878,7 +1901,12 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
|
||||
}
|
||||
if(resume_good)
|
||||
{
|
||||
evt_good = !!WaitForDebugEvent(&evt, 100);
|
||||
DWORD wait_ms = 100;
|
||||
if(priority_mode)
|
||||
{
|
||||
wait_ms = 30;
|
||||
}
|
||||
evt_good = !!WaitForDebugEvent(&evt, wait_ms);
|
||||
if(evt_good)
|
||||
{
|
||||
dmn_w32_shared->resume_needed = 1;
|
||||
@@ -1891,9 +1919,11 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
|
||||
(void)err;
|
||||
keep_going = 1;
|
||||
}
|
||||
ins_atomic_u64_inc_eval(&dmn_w32_shared->run_gen);
|
||||
ins_atomic_u64_inc_eval(&dmn_w32_shared->mem_gen);
|
||||
ins_atomic_u64_inc_eval(&dmn_w32_shared->reg_gen);
|
||||
if(priority_mode)
|
||||
{
|
||||
priority_mode = 0;
|
||||
do_threads_resume = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2327,7 +2357,6 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
|
||||
U64 new_rip = instruction_pointer;
|
||||
ctx->Rip = new_rip;
|
||||
SetThreadContext(thread->handle, ctx);
|
||||
ins_atomic_u64_inc_eval(&dmn_w32_shared->reg_gen);
|
||||
}
|
||||
}break;
|
||||
}
|
||||
@@ -2387,7 +2416,6 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
|
||||
// hit - so if we have data breakpoints set, we need to
|
||||
// check this thread's debug registers, to determine if this
|
||||
// is a regular single-step or a data breakpoint hit.
|
||||
if(first_flagged_trap_task != 0)
|
||||
{
|
||||
// rjf: first determine the flagged trap index
|
||||
U64 flagged_trap_idx = 0;
|
||||
@@ -2402,10 +2430,10 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
|
||||
{
|
||||
e->kind = DMN_EventKind_Breakpoint;
|
||||
if(0){}
|
||||
else if(regs.dr7.u64 & (1ull<<0) && regs.dr6.u64 & (1ull<<0)) { flagged_trap_idx = 0; }
|
||||
else if(regs.dr7.u64 & (1ull<<2) && regs.dr6.u64 & (1ull<<1)) { flagged_trap_idx = 1; }
|
||||
else if(regs.dr7.u64 & (1ull<<4) && regs.dr6.u64 & (1ull<<2)) { flagged_trap_idx = 2; }
|
||||
else if(regs.dr7.u64 & (1ull<<8) && regs.dr6.u64 & (1ull<<3)) { flagged_trap_idx = 3; }
|
||||
else if(regs.dr7.u64 & (1ull<<0) && regs.dr6.u64 & (1ull<<0)) { flagged_trap_idx = 0; e->address = regs.dr0.u64; }
|
||||
else if(regs.dr7.u64 & (1ull<<2) && regs.dr6.u64 & (1ull<<1)) { flagged_trap_idx = 1; e->address = regs.dr1.u64; }
|
||||
else if(regs.dr7.u64 & (1ull<<4) && regs.dr6.u64 & (1ull<<2)) { flagged_trap_idx = 2; e->address = regs.dr2.u64; }
|
||||
else if(regs.dr7.u64 & (1ull<<8) && regs.dr6.u64 & (1ull<<3)) { flagged_trap_idx = 3; e->address = regs.dr3.u64; }
|
||||
}
|
||||
}break;
|
||||
}
|
||||
@@ -2649,7 +2677,7 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
|
||||
////////////////////////
|
||||
//- rjf: exit loop after a little while, so we keep pumping e.g. debug strings
|
||||
//
|
||||
if(os_now_microseconds() >= begin_time+100000)
|
||||
if(os_now_microseconds() >= begin_time+100000 && debug_strings.total_size != 0)
|
||||
{
|
||||
keep_going = 0;
|
||||
}
|
||||
@@ -2669,7 +2697,7 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
|
||||
//
|
||||
ProfScope("suspend threads which ran")
|
||||
{
|
||||
for(DMN_W32_EntityNode *n = first_run_thread; n != 0; n = n->next)
|
||||
for(DMN_W32_EntityNode *n = first_ran_thread; n != 0; n = n->next)
|
||||
{
|
||||
DMN_W32_Entity *thread = n->v;
|
||||
if(thread->kind != DMN_W32_EntityKind_Thread)
|
||||
@@ -2841,7 +2869,6 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
|
||||
U64 new_rflags = rflags & ~0x100;
|
||||
single_step_thread_ctx->EFlags = new_rflags;
|
||||
SetThreadContext(thread->handle, single_step_thread_ctx);
|
||||
ins_atomic_u64_inc_eval(&dmn_w32_shared->reg_gen);
|
||||
}
|
||||
}break;
|
||||
}
|
||||
@@ -2938,29 +2965,6 @@ dmn_halt(U64 code, U64 user_data)
|
||||
////////////////////////////////
|
||||
//~ rjf: @dmn_os_hooks Introspection Functions (Implemented Per-OS)
|
||||
|
||||
//- rjf: run/memory/register counters
|
||||
|
||||
internal U64
|
||||
dmn_run_gen(void)
|
||||
{
|
||||
U64 result = ins_atomic_u64_eval(&dmn_w32_shared->run_gen);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal U64
|
||||
dmn_mem_gen(void)
|
||||
{
|
||||
U64 result = ins_atomic_u64_eval(&dmn_w32_shared->mem_gen);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal U64
|
||||
dmn_reg_gen(void)
|
||||
{
|
||||
U64 result = ins_atomic_u64_eval(&dmn_w32_shared->reg_gen);
|
||||
return result;
|
||||
}
|
||||
|
||||
//- rjf: non-blocking-control-thread access barriers
|
||||
|
||||
internal B32
|
||||
|
||||
@@ -200,11 +200,6 @@ struct DMN_W32_Shared
|
||||
OS_Handle access_mutex;
|
||||
B32 access_run_state;
|
||||
|
||||
// rjf: run/mem/reg gens
|
||||
U64 run_gen;
|
||||
U64 mem_gen;
|
||||
U64 reg_gen;
|
||||
|
||||
// rjf: detaching info
|
||||
Arena *detach_arena;
|
||||
DMN_HandleList detach_processes;
|
||||
|
||||
+11
-4
@@ -507,12 +507,19 @@ dr_sub_bucket(DR_Bucket *bucket)
|
||||
MemoryCopyStruct(&dst_group_n->params, &src_group_n->params);
|
||||
dst_group_n->batches = src_group_n->batches;
|
||||
dst_group_n->params.xform = dr_top_xform2d();
|
||||
B32 clip_is_set = !(dst_group_n->params.clip.x0 == 0 &&
|
||||
dst_group_n->params.clip.y0 == 0 &&
|
||||
dst_group_n->params.clip.x1 == 0 &&
|
||||
dst_group_n->params.clip.y1 == 0);
|
||||
if(clip_is_set)
|
||||
{
|
||||
Rng2F32 og_clip = dst_group_n->params.clip;
|
||||
Mat3x3F32 xform = dst_group_n->params.xform;
|
||||
dst_group_n->params.clip = r2f32(xform_3f32(v3f32(og_clip.x0, og_clip.y0, 1), xform).xy,
|
||||
xform_3f32(v3f32(og_clip.x1, og_clip.y1, 1), xform).xy);
|
||||
}
|
||||
if(dst_clip_is_set)
|
||||
{
|
||||
B32 clip_is_set = !(dst_group_n->params.clip.x0 == 0 &&
|
||||
dst_group_n->params.clip.y0 == 0 &&
|
||||
dst_group_n->params.clip.x1 == 0 &&
|
||||
dst_group_n->params.clip.y1 == 0);
|
||||
dst_group_n->params.clip = clip_is_set ? intersect_2f32(dst_clip, dst_group_n->params.clip) : dst_clip;
|
||||
}
|
||||
}
|
||||
|
||||
+300
-27
@@ -70,10 +70,10 @@ dw_reg_pos_from_code(Arch arch, DW_Reg reg_code)
|
||||
}
|
||||
|
||||
internal DW_AttribClass
|
||||
dw_attrib_class_from_attrib_kind_v2(DW_AttribKind k)
|
||||
dw_attrib_class_from_attrib_v2(DW_AttribKind k)
|
||||
{
|
||||
switch (k) {
|
||||
#define X(_N,_C) case DW_Attrib_##_N: return _C;
|
||||
#define X(_N,_C) case DW_AttribKind_##_N: return _C;
|
||||
DW_AttribKind_ClassFlags_V2_XList(X)
|
||||
#undef X
|
||||
}
|
||||
@@ -81,10 +81,10 @@ dw_attrib_class_from_attrib_kind_v2(DW_AttribKind k)
|
||||
}
|
||||
|
||||
internal DW_AttribClass
|
||||
dw_attrib_class_from_attrib_kind_v3(DW_AttribKind k)
|
||||
dw_attrib_class_from_attrib_v3(DW_AttribKind k)
|
||||
{
|
||||
switch (k) {
|
||||
#define X(_N,_C) case DW_Attrib_##_N: return _C;
|
||||
#define X(_N,_C) case DW_AttribKind_##_N: return _C;
|
||||
DW_AttribKind_ClassFlags_V3_XList(X)
|
||||
#undef X
|
||||
}
|
||||
@@ -92,10 +92,10 @@ dw_attrib_class_from_attrib_kind_v3(DW_AttribKind k)
|
||||
}
|
||||
|
||||
internal DW_AttribClass
|
||||
dw_attrib_class_from_attrib_kind_v4(DW_AttribKind k)
|
||||
dw_attrib_class_from_attrib_v4(DW_AttribKind k)
|
||||
{
|
||||
switch (k) {
|
||||
#define X(_N,_C) case DW_Attrib_##_N: return _C;
|
||||
#define X(_N,_C) case DW_AttribKind_##_N: return _C;
|
||||
DW_AttribKind_ClassFlags_V4_XList(X)
|
||||
#undef X
|
||||
}
|
||||
@@ -103,10 +103,10 @@ dw_attrib_class_from_attrib_kind_v4(DW_AttribKind k)
|
||||
}
|
||||
|
||||
internal DW_AttribClass
|
||||
dw_attrib_class_from_attrib_kind_v5(DW_AttribKind k)
|
||||
dw_attrib_class_from_attrib_v5(DW_AttribKind k)
|
||||
{
|
||||
switch (k) {
|
||||
#define X(_N,_C) case DW_Attrib_##_N: return _C;
|
||||
#define X(_N,_C) case DW_AttribKind_##_N: return _C;
|
||||
DW_AttribKind_ClassFlags_V5_XList(X)
|
||||
#undef X
|
||||
}
|
||||
@@ -114,10 +114,10 @@ dw_attrib_class_from_attrib_kind_v5(DW_AttribKind k)
|
||||
}
|
||||
|
||||
internal DW_AttribClass
|
||||
dw_attrib_class_from_attrib_kind_gnu(DW_AttribKind k)
|
||||
dw_attrib_class_from_attrib_gnu(DW_AttribKind k)
|
||||
{
|
||||
switch (k) {
|
||||
#define X(_N,_C) case DW_Attrib_##_N: return _C;
|
||||
#define X(_N,_C) case DW_AttribKind_##_N: return _C;
|
||||
DW_AttribKind_ClassFlags_GNU_XList(X)
|
||||
#undef X
|
||||
}
|
||||
@@ -125,10 +125,10 @@ dw_attrib_class_from_attrib_kind_gnu(DW_AttribKind k)
|
||||
}
|
||||
|
||||
internal DW_AttribClass
|
||||
dw_attrib_class_from_attrib_kind_llvm(DW_AttribKind k)
|
||||
dw_attrib_class_from_attrib_llvm(DW_AttribKind k)
|
||||
{
|
||||
switch (k) {
|
||||
#define X(_N,_C) case DW_Attrib_##_N: return _C;
|
||||
#define X(_N,_C) case DW_AttribKind_##_N: return _C;
|
||||
DW_AttribKind_ClassFlags_LLVM_XList(X)
|
||||
#undef X
|
||||
}
|
||||
@@ -136,10 +136,10 @@ dw_attrib_class_from_attrib_kind_llvm(DW_AttribKind k)
|
||||
}
|
||||
|
||||
internal DW_AttribClass
|
||||
dw_attrib_class_from_attrib_kind_apple(DW_AttribKind k)
|
||||
dw_attrib_class_from_attrib_apple(DW_AttribKind k)
|
||||
{
|
||||
switch (k) {
|
||||
#define X(_N,_C) case DW_Attrib_##_N: return _C;
|
||||
#define X(_N,_C) case DW_AttribKind_##_N: return _C;
|
||||
DW_AttribKind_ClassFlags_APPLE_XList(X)
|
||||
#undef X
|
||||
}
|
||||
@@ -147,10 +147,10 @@ dw_attrib_class_from_attrib_kind_apple(DW_AttribKind k)
|
||||
}
|
||||
|
||||
internal DW_AttribClass
|
||||
dw_attrib_class_from_attrib_kind_mips(DW_AttribKind k)
|
||||
dw_attrib_class_from_attrib_mips(DW_AttribKind k)
|
||||
{
|
||||
switch (k) {
|
||||
#define X(_N,_C) case DW_Attrib_##_N: return _C;
|
||||
#define X(_N,_C) case DW_AttribKind_##_N: return _C;
|
||||
DW_AttribKind_ClassFlags_MIPS_XList(X)
|
||||
#undef X
|
||||
}
|
||||
@@ -158,7 +158,7 @@ dw_attrib_class_from_attrib_kind_mips(DW_AttribKind k)
|
||||
}
|
||||
|
||||
internal DW_AttribClass
|
||||
dw_attrib_class_from_attrib_kind(DW_Version ver, DW_Ext ext, DW_AttribKind k)
|
||||
dw_attrib_class_from_attrib(DW_Version ver, DW_Ext ext, DW_AttribKind k)
|
||||
{
|
||||
DW_AttribClass result = DW_AttribClass_Null;
|
||||
|
||||
@@ -172,10 +172,10 @@ dw_attrib_class_from_attrib_kind(DW_Version ver, DW_Ext ext, DW_AttribKind k)
|
||||
|
||||
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;
|
||||
case DW_Ext_GNU: result = dw_attrib_class_from_attrib_gnu(k); break;
|
||||
case DW_Ext_LLVM: result = dw_attrib_class_from_attrib_llvm(k); break;
|
||||
case DW_Ext_APPLE: result = dw_attrib_class_from_attrib_apple(k); break;
|
||||
case DW_Ext_MIPS: result = dw_attrib_class_from_attrib_mips(k); break;
|
||||
default: InvalidPath; break;
|
||||
}
|
||||
|
||||
@@ -188,10 +188,10 @@ dw_attrib_class_from_attrib_kind(DW_Version ver, DW_Ext ext, DW_AttribKind k)
|
||||
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;
|
||||
case DW_Version_2: result = dw_attrib_class_from_attrib_v2(k); break;
|
||||
case DW_Version_3: result = dw_attrib_class_from_attrib_v3(k); break;
|
||||
case DW_Version_4: result = dw_attrib_class_from_attrib_v4(k); break;
|
||||
case DW_Version_5: result = dw_attrib_class_from_attrib_v5(k); break;
|
||||
default: InvalidPath; break;
|
||||
}
|
||||
}
|
||||
@@ -302,14 +302,14 @@ dw_pick_attrib_value_class(DW_Version ver, DW_Ext ext, B32 relaxed, DW_AttribKin
|
||||
// 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 attrib_class = dw_attrib_class_from_attrib(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);
|
||||
attrib_class = dw_attrib_class_from_attrib(DW_Version_Last, ext, attrib_kind);
|
||||
form_class = dw_attrib_class_from_form_kind(DW_Version_Last, form_kind);
|
||||
}
|
||||
}
|
||||
@@ -386,3 +386,276 @@ dw_pick_default_lower_bound(DW_Language lang)
|
||||
return lower_bound;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String <=> Enum
|
||||
|
||||
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;
|
||||
if (ext & DW_Ext_GNU) {
|
||||
switch (op) {
|
||||
DW_Expr_GNU_XList(X);
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
case DW_TagKind_Null: return str8_lit("Null");
|
||||
#define X(_N,_ID) case DW_TagKind_##_N: return str8_lit(Stringify(_N));
|
||||
DW_TagKind_V3_XList(X)
|
||||
DW_TagKind_V5_XList(X)
|
||||
DW_TagKind_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_AttribKind_##_N:{result = str8_lit(Stringify(_N));}break;
|
||||
String8 result = {0};
|
||||
|
||||
//- rjf: try extensions
|
||||
if(result.size != 0)
|
||||
{
|
||||
while(ext)
|
||||
{
|
||||
U64 z = 64-clz64(ext);
|
||||
if(z == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
U64 flag = 1 << (z-1);
|
||||
ext &= ~flag;
|
||||
switch(flag)
|
||||
{
|
||||
default:{}break;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: try version
|
||||
if(result.size == 0)
|
||||
{
|
||||
for(U64 retry = 0; retry < 2; retry += 1)
|
||||
{
|
||||
DW_Version version = retry ? DW_Version_5 : ver;
|
||||
switch(version)
|
||||
{
|
||||
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: {}break;
|
||||
case DW_Version_Null:{}break;
|
||||
default:{}break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: fallback
|
||||
if(result.size == 0)
|
||||
{
|
||||
result = push_str8f(arena, "#%u", kind);
|
||||
}
|
||||
|
||||
#undef X
|
||||
return result;
|
||||
}
|
||||
|
||||
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_inl(Arena *arena, DW_InlKind kind)
|
||||
{
|
||||
switch (kind) {
|
||||
#define X(_N,_ID) case _ID: return str8_lit(Stringify(_N));
|
||||
DW_Inl_XList(X)
|
||||
#undef X
|
||||
}
|
||||
return push_str8f(arena, "%x", kind);
|
||||
}
|
||||
|
||||
internal String8
|
||||
dw_string_from_access_kind(Arena *arena, DW_AccessKind kind)
|
||||
{
|
||||
switch (kind) {
|
||||
#define X(_N,_ID) case _ID: return str8_lit(Stringify(_N));
|
||||
DW_AccessKind_XList(X)
|
||||
#undef X
|
||||
}
|
||||
return push_str8f(arena, "%llx", kind);
|
||||
}
|
||||
|
||||
internal String8
|
||||
dw_string_from_calling_convetion(Arena *arena, DW_CallingConventionKind kind)
|
||||
{
|
||||
switch (kind) {
|
||||
#define X(_N,_ID) case _ID: return str8_lit(Stringify(_N));
|
||||
DW_CallingConventionKind_XList(X)
|
||||
#undef X
|
||||
}
|
||||
return push_str8f(arena, "%llx", kind);
|
||||
}
|
||||
|
||||
internal String8
|
||||
dw_string_from_attrib_type_encoding(Arena *arena, DW_ATE kind)
|
||||
{
|
||||
switch (kind) {
|
||||
#define X(_N,_ID) case _ID: return str8_lit(Stringify(_N));
|
||||
DW_ATE_XList(X)
|
||||
#undef X
|
||||
}
|
||||
return push_str8f(arena, "%llx", 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_LLE 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_RLE 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_RegX86_##_N: reg_str = str8_lit(Stringify(_N)); break;
|
||||
DW_Regs_X86_XList(X)
|
||||
#undef X
|
||||
}
|
||||
} break;
|
||||
case Arch_x64: {
|
||||
switch (reg_id) {
|
||||
#define X(_N, _ID, ...) case DW_RegX64_##_N: reg_str = str8_lit(Stringify(_N)); 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;
|
||||
}
|
||||
|
||||
+43
-24
@@ -188,7 +188,7 @@ typedef enum DW_IDCaseKindEnum
|
||||
#undef X
|
||||
} DW_IDCaseKindEnum;
|
||||
|
||||
#define DW_Tag_V3_XList(X) \
|
||||
#define DW_TagKind_V3_XList(X) \
|
||||
X(ArrayType, 0x01) \
|
||||
X(ClassType, 0x02) \
|
||||
X(EntryPoint, 0x03) \
|
||||
@@ -247,7 +247,7 @@ X(ImportedUnit, 0x3d) \
|
||||
X(Condition, 0x3f) \
|
||||
X(SharedType, 0x40)
|
||||
|
||||
#define DW_Tag_V5_XList(X) \
|
||||
#define DW_TagKind_V5_XList(X) \
|
||||
X(TypeUnit, 0x41) \
|
||||
X(RValueReferenceType, 0x42) \
|
||||
X(TemplateAlias, 0x43) \
|
||||
@@ -260,21 +260,21 @@ X(CallSiteParameter, 0x49) \
|
||||
X(SkeletonUnit, 0x4A) \
|
||||
X(ImmutableType, 0x4B)
|
||||
|
||||
#define DW_Tag_GNU_XList(X) \
|
||||
#define DW_TagKind_GNU_XList(X) \
|
||||
X(GNU_CallSite, 0x4109) \
|
||||
X(GNU_CallSiteParameter, 0x410a)
|
||||
|
||||
typedef U64 DW_TagKind;
|
||||
typedef enum DW_TagKindEnum
|
||||
{
|
||||
DW_Tag_Null,
|
||||
#define X(_N,_ID) DW_Tag_##_N = _ID,
|
||||
DW_Tag_V3_XList(X)
|
||||
DW_Tag_V5_XList(X)
|
||||
DW_Tag_GNU_XList(X)
|
||||
DW_TagKind_Null,
|
||||
#define X(_N,_ID) DW_TagKind_##_N = _ID,
|
||||
DW_TagKind_V3_XList(X)
|
||||
DW_TagKind_V5_XList(X)
|
||||
DW_TagKind_GNU_XList(X)
|
||||
#undef X
|
||||
DW_Tag_UserLo = 0x4080,
|
||||
DW_Tag_UserHi = 0xffff
|
||||
DW_TagKind_UserLo = 0x4080,
|
||||
DW_TagKind_UserHi = 0xffff
|
||||
} DW_TagKindEnum;
|
||||
|
||||
//- Attrib Class Encodings
|
||||
@@ -581,7 +581,7 @@ X(Producer, DW_AttribClass_String)
|
||||
X(Prototyped, DW_AttribClass_Flag) \
|
||||
X(ReturnAddr, DW_AttribClass_Block|DW_AttribClass_Const) \
|
||||
X(StartScope, DW_AttribClass_Const) \
|
||||
X(BitStride, DW_AttribClass_Const) /* dwarf-v1 DW_Attrib_stride_size*/ \
|
||||
X(BitStride, DW_AttribClass_Const) /* dwarf-v1 DW_AttribKind_stride_size*/ \
|
||||
X(UpperBound, DW_AttribClass_Const|DW_AttribClass_Reference) \
|
||||
X(AbstractOrigin, DW_AttribClass_Reference) \
|
||||
X(Accessibility, DW_AttribClass_Const) \
|
||||
@@ -1159,8 +1159,8 @@ X(MIPS_AssumedSize, DW_AttribClass_Reference)
|
||||
typedef U32 DW_AttribKind;
|
||||
typedef enum DW_AttribKindEnum
|
||||
{
|
||||
DW_Attrib_Null,
|
||||
#define X(_N,_ID,...) DW_Attrib_##_N = _ID,
|
||||
DW_AttribKind_Null,
|
||||
#define X(_N,_ID,...) DW_AttribKind_##_N = _ID,
|
||||
DW_AttribKind_V2_XList(X)
|
||||
DW_AttribKind_V3_XList(X)
|
||||
DW_AttribKind_V4_XList(X)
|
||||
@@ -1170,8 +1170,8 @@ typedef enum DW_AttribKindEnum
|
||||
DW_AttribKind_APPLE_XList(X)
|
||||
DW_AttribKind_MIPS_XList(X)
|
||||
#undef X
|
||||
DW_Attrib_UserLo = 0x2000,
|
||||
DW_Attrib_UserHi = 0x3fff
|
||||
DW_AttribKind_UserLo = 0x2000,
|
||||
DW_AttribKind_UserHi = 0x3fff
|
||||
} DW_AttribKindEnum;
|
||||
|
||||
#define DW_ATE_XList(X) \
|
||||
@@ -1744,18 +1744,18 @@ internal U64 dw_reg_pos_from_code(Arch arch, DW_Reg reg_code);
|
||||
//- Attrib Class Encodings
|
||||
|
||||
// Speced Encodings
|
||||
internal DW_AttribClass dw_attrib_class_from_attrib_kind_v2(DW_AttribKind k);
|
||||
internal DW_AttribClass dw_attrib_class_from_attrib_kind_v3(DW_AttribKind k);
|
||||
internal DW_AttribClass dw_attrib_class_from_attrib_kind_v4(DW_AttribKind k);
|
||||
internal DW_AttribClass dw_attrib_class_from_attrib_kind_v5(DW_AttribKind k);
|
||||
internal DW_AttribClass dw_attrib_class_from_attrib_v2(DW_AttribKind k);
|
||||
internal DW_AttribClass dw_attrib_class_from_attrib_v3(DW_AttribKind k);
|
||||
internal DW_AttribClass dw_attrib_class_from_attrib_v4(DW_AttribKind k);
|
||||
internal DW_AttribClass dw_attrib_class_from_attrib_v5(DW_AttribKind k);
|
||||
|
||||
// Extensions
|
||||
internal DW_AttribClass dw_attrib_class_from_attrib_kind_gnu (DW_AttribKind k);
|
||||
internal DW_AttribClass dw_attrib_class_from_attrib_kind_llvm (DW_AttribKind k);
|
||||
internal DW_AttribClass dw_attrib_class_from_attrib_kind_apple(DW_AttribKind k);
|
||||
internal DW_AttribClass dw_attrib_class_from_attrib_kind_mips (DW_AttribKind k);
|
||||
internal DW_AttribClass dw_attrib_class_from_attrib_gnu (DW_AttribKind k);
|
||||
internal DW_AttribClass dw_attrib_class_from_attrib_llvm (DW_AttribKind k);
|
||||
internal DW_AttribClass dw_attrib_class_from_attrib_apple(DW_AttribKind k);
|
||||
internal DW_AttribClass dw_attrib_class_from_attrib_mips (DW_AttribKind k);
|
||||
|
||||
internal DW_AttribClass dw_attrib_class_from_attrib_kind(DW_Version ver, DW_Ext ext, DW_AttribKind v);
|
||||
internal DW_AttribClass dw_attrib_class_from_attrib(DW_Version ver, DW_Ext ext, DW_AttribKind v);
|
||||
|
||||
//- Form Class Encodings
|
||||
|
||||
@@ -1779,4 +1779,23 @@ internal DW_AttribClass dw_pick_attrib_value_class(DW_Version ver, DW_Ext ext, B
|
||||
|
||||
internal U64 dw_pick_default_lower_bound(DW_Language lang);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String <=> Enum
|
||||
|
||||
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_language(Arena *arena, DW_Language kind);
|
||||
internal String8 dw_string_from_inl(Arena *arena, DW_InlKind kind);
|
||||
internal String8 dw_string_from_access_kind(Arena *arena, DW_AccessKind kind);
|
||||
internal String8 dw_string_from_calling_convetion(Arena *arena, DW_CallingConventionKind kind);
|
||||
internal String8 dw_string_from_attrib_type_encoding(Arena *arena, DW_ATE kind);
|
||||
internal String8 dw_string_from_std_opcode(Arena *arena, DW_StdOpcode kind);
|
||||
internal String8 dw_string_from_ext_opcode(Arena *arena, DW_ExtOpcode kind);
|
||||
internal String8 dw_string_from_loc_list_entry_kind(Arena *arena, DW_LLE kind);
|
||||
internal String8 dw_string_from_section_kind(Arena *arena, DW_SectionKind kind);
|
||||
internal String8 dw_string_from_rng_list_entry_kind(Arena *arena, DW_RLE kind);
|
||||
internal String8 dw_string_from_register(Arena *arena, Arch arch, U64 reg_id);
|
||||
|
||||
#endif // DWARF_H
|
||||
|
||||
@@ -64,5 +64,3 @@ dw_input_from_coff_section_table(Arena *arena,
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#ifndef DWARF_COFF_H
|
||||
#define DWARF_COFF_H
|
||||
|
||||
internal B32 dw_is_dwarf_present_coff_section_table(String8 raw_image, String8 string_table, U64 section_count, COFF_SectionHeader *section_table);
|
||||
internal DW_Input dw_input_from_coff_section_table(Arena *arena, String8 raw_image, String8 string_table, U64 section_count, COFF_SectionHeader *section_table);
|
||||
|
||||
#endif // DWARF_COFF_H
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,86 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef DWARF_DUMP_H
|
||||
#define DWARF_DUMP_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Dump Subset Types
|
||||
|
||||
#define DW_DumpSubset_XList \
|
||||
X(DebugInfo, debug_info, "DEBUG INFO")\
|
||||
X(DebugAbbrev, debug_abbrev, "DEBUG ABBREV")\
|
||||
X(DebugLine, debug_line, "DEBUG LINE")\
|
||||
X(DebugStr, debug_str, "DEBUG STR")\
|
||||
X(DebugLoc, debug_loc, "DEBUG LOC")\
|
||||
X(DebugRanges, debug_ranges, "DEBUG RANGES")\
|
||||
X(DebugARanges, debug_aranges, "DEBUG ARANGES")\
|
||||
X(DebugAddr, debug_addr, "DEBUG ADDR")\
|
||||
X(DebugLocLists, debug_loclists, "DEBUG LOCLISTS")\
|
||||
X(DebugRngLists, debug_rnglists, "DEBUG RNGLISTS")\
|
||||
X(DebugPubNames, debug_pubnames, "DEBUG PUBNAMES")\
|
||||
X(DebugPubTypes, debug_pubtypes, "DEBUG PUBTYPES")\
|
||||
X(DebugLineStr, debug_linestr, "DEBUG LINESTR")\
|
||||
X(DebugStrOffsets, debug_stroff, "DEBUG STROFF")\
|
||||
|
||||
typedef enum DW_DumpSubset
|
||||
{
|
||||
#define X(name, name_lower, title) DW_DumpSubset_##name,
|
||||
DW_DumpSubset_XList
|
||||
#undef X
|
||||
}
|
||||
DW_DumpSubset;
|
||||
|
||||
typedef U32 DW_DumpSubsetFlags;
|
||||
enum
|
||||
{
|
||||
#define X(name, name_lower, title) DW_DumpSubsetFlag_##name = (1<<DW_DumpSubset_##name),
|
||||
DW_DumpSubset_XList
|
||||
#undef X
|
||||
DW_DumpSubsetFlag_All = 0xffffffffu,
|
||||
};
|
||||
|
||||
read_only global String8 dw_name_lowercase_from_dump_subset_table[] =
|
||||
{
|
||||
#define X(name, name_lower, title) str8_lit_comp(#name_lower),
|
||||
DW_DumpSubset_XList
|
||||
#undef X
|
||||
};
|
||||
|
||||
read_only global String8 dw_name_title_from_dump_subset_table[] =
|
||||
{
|
||||
#define X(name, name_lower, title) str8_lit_comp(title),
|
||||
DW_DumpSubset_XList
|
||||
#undef X
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Stringification Helpers
|
||||
|
||||
internal String8 dw_string_from_reg_off(Arena *arena, Arch arch, U64 reg_idx, S64 reg_off);
|
||||
internal String8List dw_string_list_from_expression (Arena *arena, String8 raw_data, U64 cu_base, U64 address_size, Arch arch, DW_Version ver, DW_Ext ext, DW_Format format);
|
||||
internal String8 dw_single_line_string_from_expression(Arena *arena, String8 raw_data, U64 cu_base, U64 address_size, Arch arch, DW_Version ver, DW_Ext ext, DW_Format format);
|
||||
internal String8 dw_string_from_eh_ptr_enc (Arena *arena, DW_EhPtrEnc enc);
|
||||
|
||||
#if 0
|
||||
internal void dw_string_from_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, DW_Format format);
|
||||
|
||||
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_loc (Arena *arena, String8List *out, String8 indent, DW_Input *input, Arch arch, ExecutableImageKind image_type, B32 relaxed);
|
||||
internal void dw_print_debug_ranges (Arena *arena, String8List *out, String8 indent, DW_Input *input, Arch arch, ExecutableImageKind image_type, B32 relaxed);
|
||||
internal void dw_print_debug_aranges (Arena *arena, String8List *out, String8 indent, DW_Input *input);
|
||||
internal void dw_print_debug_addr (Arena *arena, String8List *out, String8 indent, DW_Input *input);
|
||||
internal void dw_print_debug_loclists (Arena *arena, String8List *out, String8 indent, DW_Input *input, Rng1U64Array segment_vranges, Arch arch);
|
||||
internal void dw_print_debug_rnglists (Arena *arena, String8List *out, String8 indent, DW_Input *input, Rng1U64Array segment_vranges);
|
||||
internal void dw_print_debug_pubnames (Arena *arena, String8List *out, String8 indent, DW_Input *input);
|
||||
internal void dw_print_debug_pubtypes (Arena *arena, String8List *out, String8 indent, DW_Input *input);
|
||||
internal void dw_print_debug_line_str (Arena *arena, String8List *out, String8 indent, DW_Input *input);
|
||||
internal void dw_print_debug_str_offsets(Arena *arena, String8List *out, String8 indent, DW_Input *input);
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Dump Entry Point
|
||||
|
||||
internal String8List dw_dump_list_from_sections(Arena *arena, DW_Input *input, Arch arch, DW_DumpSubsetFlags subset_flags);
|
||||
|
||||
#endif // DWARF_DUMP_H
|
||||
+84
-102
@@ -2,34 +2,25 @@
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal B32
|
||||
dw_is_dwarf_present_elf_section_table(String8 raw_image, ELF_BinInfo *bin)
|
||||
dw_is_dwarf_present_from_elf_bin(String8 data, ELF_Bin *bin)
|
||||
{
|
||||
Temp scratch = scratch_begin(0,0);
|
||||
|
||||
B32 is_dwarf_present = 0;
|
||||
|
||||
ELF_Shdr64Array sections = elf_shdr64_array_from_bin(scratch.arena, raw_image, &bin->hdr);
|
||||
|
||||
for (U64 i = 0; i < sections.count; ++i) {
|
||||
ELF_Shdr64 *shdr = §ions.v[i];
|
||||
String8 name = elf_name_from_shdr64(raw_image, &bin->hdr, bin->sh_name_range, shdr);
|
||||
|
||||
if (shdr->sh_type != ELF_SectionCode_ProgBits) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for EachIndex(idx, bin->shdrs.count)
|
||||
{
|
||||
ELF_Shdr64 *shdr = &bin->shdrs.v[idx];
|
||||
if(shdr->sh_type != ELF_SectionCode_ProgBits) { continue; }
|
||||
String8 name = elf_name_from_shdr64(data, bin, shdr);
|
||||
DW_SectionKind s = dw_section_kind_from_string(name);
|
||||
if (s == DW_Section_Null) {
|
||||
if(s == DW_Section_Null)
|
||||
{
|
||||
s = dw_section_dwo_kind_from_string(name);
|
||||
}
|
||||
|
||||
is_dwarf_present = s != DW_Section_Null;
|
||||
if (is_dwarf_present) {
|
||||
is_dwarf_present = (s != DW_Section_Null);
|
||||
if(is_dwarf_present)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
return is_dwarf_present;
|
||||
}
|
||||
|
||||
@@ -37,99 +28,90 @@ dw_is_dwarf_present_elf_section_table(String8 raw_image, ELF_BinInfo *bin)
|
||||
#include "third_party/sinfl/sinfl.h"
|
||||
|
||||
internal DW_Input
|
||||
dw_input_from_elf_section_table(Arena *arena, String8 raw_image, ELF_BinInfo *bin)
|
||||
dw_input_from_elf_bin(Arena *arena, String8 data, ELF_Bin *bin)
|
||||
{
|
||||
DW_Input result = {0};
|
||||
B32 is_section_present[ArrayCount(result.sec)] = {0};
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
|
||||
DW_Input result = {0};
|
||||
B32 sect_status[ArrayCount(result.sec)] = {0};
|
||||
|
||||
ELF_Shdr64Array sections = elf_shdr64_array_from_bin(scratch.arena, raw_image, &bin->hdr);
|
||||
|
||||
for (U64 sect_idx = 1; sect_idx < sections.count; ++sect_idx) {
|
||||
ELF_Shdr64 *shdr = §ions.v[sect_idx];
|
||||
for(U64 section_idx = 1; section_idx < bin->shdrs.count; section_idx += 1)
|
||||
{
|
||||
ELF_Shdr64 *shdr = &bin->shdrs.v[section_idx];
|
||||
if(shdr->sh_type != ELF_SectionCode_ProgBits) { continue; } // skip BSS sections
|
||||
|
||||
// skip BSS sections
|
||||
if (shdr->sh_type != ELF_SectionCode_ProgBits) {
|
||||
continue;
|
||||
//- rjf: unpack section
|
||||
String8 section_name = elf_name_from_shdr64(data, bin, shdr);
|
||||
DW_SectionKind section_kind = dw_section_kind_from_string(section_name);
|
||||
String8 section_data__maybe_compressed = str8_substr(data, r1u64(shdr->sh_offset, shdr->sh_offset + shdr->sh_size));
|
||||
B32 is_dwo = 0;
|
||||
if(section_kind == DW_Section_Null)
|
||||
{
|
||||
section_kind = dw_section_dwo_kind_from_string(section_name);
|
||||
is_dwo = (section_kind != DW_Section_Null);
|
||||
}
|
||||
|
||||
String8 name = elf_name_from_shdr64(raw_image, &bin->hdr, bin->sh_name_range, shdr);
|
||||
|
||||
DW_SectionKind s = dw_section_kind_from_string(name);
|
||||
B32 is_dwo = 0;
|
||||
if (s == DW_Section_Null) {
|
||||
s = dw_section_dwo_kind_from_string(name);
|
||||
is_dwo = 1;
|
||||
}
|
||||
|
||||
if (s != DW_Section_Null) {
|
||||
if (sect_status[s]) {
|
||||
Assert(!"too many debug sections with identical name, picking first");
|
||||
} else {
|
||||
Rng1U64 raw_data_range = rng_1u64(shdr->sh_offset, shdr->sh_offset + shdr->sh_size);
|
||||
String8 data = str8_substr(raw_image, raw_data_range);
|
||||
|
||||
// ELF was compiled with compressed debug info
|
||||
if (shdr->sh_flags & ELF_Shf_Compressed) {
|
||||
String8 comp_data_with_header = data;
|
||||
|
||||
// read header
|
||||
ELF_Chdr64 chdr64 = {0};
|
||||
U64 chdr_size = 0;
|
||||
if (ELF_HdrIs64Bit(bin->hdr.e_ident)) {
|
||||
chdr_size = str8_deserial_read_struct(comp_data_with_header, 0, &chdr64);
|
||||
if (chdr_size != sizeof(chdr64)) {
|
||||
Assert(!"not enough bytes to read header");
|
||||
}
|
||||
} else if (ELF_HdrIs32Bit(bin->hdr.e_ident)) {
|
||||
ELF_Chdr32 chdr32 = {0};
|
||||
chdr_size = str8_deserial_read_struct(comp_data_with_header, 0, &chdr32);
|
||||
if (chdr_size == sizeof(chdr32)) {
|
||||
chdr64 = elf_chdr64_from_chdr32(chdr32);
|
||||
}
|
||||
//- rjf: decompress section data if needed
|
||||
String8 section_data__uncompressed = {0};
|
||||
if(section_kind != DW_Section_Null)
|
||||
{
|
||||
if(!(shdr->sh_flags & ELF_Shf_Compressed))
|
||||
{
|
||||
section_data__uncompressed = section_data__maybe_compressed;
|
||||
}
|
||||
else
|
||||
{
|
||||
// rjf: read compressed-section header
|
||||
ELF_Chdr64 chdr64 = {0};
|
||||
U64 chdr_size = 0;
|
||||
if(ELF_HdrIs64Bit(bin->hdr.e_ident))
|
||||
{
|
||||
chdr_size = str8_deserial_read_struct(section_data__maybe_compressed, 0, &chdr64);
|
||||
}
|
||||
else if(ELF_HdrIs32Bit(bin->hdr.e_ident))
|
||||
{
|
||||
ELF_Chdr32 chdr32 = {0};
|
||||
chdr_size = str8_deserial_read_struct(section_data__maybe_compressed, 0, &chdr32);
|
||||
if(chdr_size == sizeof(chdr32))
|
||||
{
|
||||
chdr64 = elf_chdr64_from_chdr32(chdr32);
|
||||
}
|
||||
|
||||
AssertAlways(IsPow2(chdr64.ch_addr_align));
|
||||
|
||||
// skip header
|
||||
String8 comp_data = str8_skip(comp_data_with_header, chdr_size);
|
||||
|
||||
// push buffer for the decompressor
|
||||
U8 *decomp_buffer = push_array_no_zero_aligned(arena, U8, chdr64.ch_size, chdr64.ch_addr_align);
|
||||
U64 actual_decomp_size = 0;
|
||||
|
||||
// decompress
|
||||
switch (chdr64.ch_type) {
|
||||
case ELF_CompressType_None: {
|
||||
AssertAlways(!"unexpected compression type");
|
||||
} break;
|
||||
case ELF_CompressType_ZLib: {
|
||||
actual_decomp_size = zsinflate(decomp_buffer, chdr64.ch_size, comp_data.str, comp_data.size);
|
||||
} break;
|
||||
case ELF_CompressType_ZStd: {
|
||||
// TODO: zstd lib
|
||||
NotImplemented;
|
||||
} break;
|
||||
default: InvalidPath; break;
|
||||
}
|
||||
|
||||
// TODO: error handling
|
||||
AssertAlways(actual_decomp_size == chdr64.ch_size);
|
||||
|
||||
// set decompressed section data
|
||||
data = str8(decomp_buffer, actual_decomp_size);
|
||||
}
|
||||
|
||||
sect_status[s] = 1;
|
||||
DW_Section *d = &result.sec[s];
|
||||
d->name = push_str8_copy(arena, name);
|
||||
d->data = data;
|
||||
d->is_dwo = is_dwo;
|
||||
// rjf: decompress
|
||||
{
|
||||
String8 section_data__compressed_contents = str8_skip(section_data__maybe_compressed, chdr_size);
|
||||
switch(chdr64.ch_type)
|
||||
{
|
||||
default:
|
||||
case ELF_CompressType_None:
|
||||
{
|
||||
section_data__uncompressed = section_data__compressed_contents;
|
||||
}break;
|
||||
case ELF_CompressType_ZLib:
|
||||
{
|
||||
U8 *section_data_uncompressed_buffer = push_array_no_zero_aligned(arena, U8, chdr64.ch_size, chdr64.ch_addr_align);
|
||||
U64 section_data_uncompressed_size = 0;
|
||||
section_data_uncompressed_size = zsinflate(section_data_uncompressed_buffer, chdr64.ch_size, section_data__compressed_contents.str, section_data__compressed_contents.size);
|
||||
section_data__uncompressed = str8(section_data_uncompressed_buffer, section_data_uncompressed_size);
|
||||
}break;
|
||||
case ELF_CompressType_ZStd:
|
||||
{
|
||||
NotImplemented;
|
||||
}break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: store
|
||||
if(section_kind != DW_Section_Null)
|
||||
{
|
||||
is_section_present[section_kind] = 1;
|
||||
DW_Section *d = &result.sec[section_kind];
|
||||
d->name = push_str8_copy(arena, section_name);
|
||||
d->data = section_data__uncompressed;
|
||||
d->is_dwo = is_dwo;
|
||||
}
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -4,8 +4,7 @@
|
||||
#ifndef DWARF_ELF_H
|
||||
#define DWARF_ELF_H
|
||||
|
||||
internal DW_Input dw_input_from_elf_section_table(Arena *arena, String8 raw_image, ELF_BinInfo *bin);
|
||||
internal B32 dw_is_dwarf_present_from_elf_bin(String8 raw_image, ELF_Bin *bin);
|
||||
internal DW_Input dw_input_from_elf_bin(Arena *arena, String8 raw_image, ELF_Bin *bin);
|
||||
|
||||
#endif // DWARF_ELF_H
|
||||
|
||||
|
||||
|
||||
@@ -1,268 +0,0 @@
|
||||
// Copyright (c) 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;
|
||||
if (ext & DW_Ext_GNU) {
|
||||
switch (op) {
|
||||
DW_Expr_GNU_XList(X);
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
case DW_Tag_Null: return str8_lit("Null");
|
||||
#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_inl(Arena *arena, DW_InlKind kind)
|
||||
{
|
||||
switch (kind) {
|
||||
#define X(_N,_ID) case _ID: return str8_lit(Stringify(_N));
|
||||
DW_Inl_XList(X)
|
||||
#undef X
|
||||
}
|
||||
return push_str8f(arena, "%x", kind);
|
||||
}
|
||||
|
||||
internal String8
|
||||
dw_string_from_access_kind(Arena *arena, DW_AccessKind kind)
|
||||
{
|
||||
switch (kind) {
|
||||
#define X(_N,_ID) case _ID: return str8_lit(Stringify(_N));
|
||||
DW_AccessKind_XList(X)
|
||||
#undef X
|
||||
}
|
||||
return push_str8f(arena, "%llx", kind);
|
||||
}
|
||||
|
||||
internal String8
|
||||
dw_string_from_calling_convetion(Arena *arena, DW_CallingConventionKind kind)
|
||||
{
|
||||
switch (kind) {
|
||||
#define X(_N,_ID) case _ID: return str8_lit(Stringify(_N));
|
||||
DW_CallingConventionKind_XList(X)
|
||||
#undef X
|
||||
}
|
||||
return push_str8f(arena, "%llx", kind);
|
||||
}
|
||||
|
||||
internal String8
|
||||
dw_string_from_attrib_type_encoding(Arena *arena, DW_ATE kind)
|
||||
{
|
||||
switch (kind) {
|
||||
#define X(_N,_ID) case _ID: return str8_lit(Stringify(_N));
|
||||
DW_ATE_XList(X)
|
||||
#undef X
|
||||
}
|
||||
return push_str8f(arena, "%llx", 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_LLE 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_RLE 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_RegX86_##_N: reg_str = str8_lit(Stringify(_N)); break;
|
||||
DW_Regs_X86_XList(X)
|
||||
#undef X
|
||||
}
|
||||
} break;
|
||||
case Arch_x64: {
|
||||
switch (reg_id) {
|
||||
#define X(_N, _ID, ...) case DW_RegX64_##_N: reg_str = str8_lit(Stringify(_N)); 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;
|
||||
}
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
// Copyright (c) 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_access_kind(Arena *arena, DW_AccessKind kind);
|
||||
|
||||
//internal String8 dw_string_from_register(Arena *arena, Arch arch, U64 reg_id);
|
||||
|
||||
#endif // DWARF_ENUM_H
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#include "dwarf/dwarf.c"
|
||||
#include "dwarf/dwarf_expr.c"
|
||||
#include "dwarf/dwarf_parse.c"
|
||||
#include "dwarf/dwarf_coff.c"
|
||||
#include "dwarf/dwarf_elf.c"
|
||||
#include "dwarf/dwarf_unwind.c"
|
||||
#include "dwarf/dwarf_dump.c"
|
||||
@@ -0,0 +1,15 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef DWARF_INC_H
|
||||
#define DWARF_INC_H
|
||||
|
||||
#include "dwarf/dwarf.h"
|
||||
#include "dwarf/dwarf_expr.h"
|
||||
#include "dwarf/dwarf_parse.h"
|
||||
#include "dwarf/dwarf_coff.h"
|
||||
#include "dwarf/dwarf_elf.h"
|
||||
#include "dwarf/dwarf_unwind.h"
|
||||
#include "dwarf/dwarf_dump.h"
|
||||
|
||||
#endif // DWARF_INC_H
|
||||
+62
-62
@@ -1675,7 +1675,7 @@ dw_value_class_from_attrib(DW_CompUnit *cu, DW_Attrib *attrib)
|
||||
}
|
||||
|
||||
internal String8
|
||||
dw_exprloc_from_attrib_ptr(DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib)
|
||||
dw_exprloc_from_attrib(DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib)
|
||||
{
|
||||
DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib);
|
||||
AssertAlways(value_class == DW_AttribClass_Null || value_class == DW_AttribClass_ExprLoc || value_class == DW_AttribClass_Block);
|
||||
@@ -1683,7 +1683,7 @@ dw_exprloc_from_attrib_ptr(DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib)
|
||||
}
|
||||
|
||||
internal U128
|
||||
dw_const_u128_from_attrib_ptr(DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib)
|
||||
dw_const_u128_from_attrib(DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib)
|
||||
{
|
||||
DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib);
|
||||
AssertAlways(value_class == DW_AttribClass_Null || value_class == DW_AttribClass_Const);
|
||||
@@ -1691,7 +1691,7 @@ dw_const_u128_from_attrib_ptr(DW_Input *input, DW_CompUnit *cu, DW_Attrib *attri
|
||||
}
|
||||
|
||||
internal U64
|
||||
dw_const_u64_from_attrib_ptr(DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib)
|
||||
dw_const_u64_from_attrib(DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib)
|
||||
{
|
||||
DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib);
|
||||
AssertAlways(value_class == DW_AttribClass_Null || value_class == DW_AttribClass_Const);
|
||||
@@ -1699,7 +1699,7 @@ dw_const_u64_from_attrib_ptr(DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib
|
||||
}
|
||||
|
||||
internal U32
|
||||
dw_const_u32_from_attrib_ptr(DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib)
|
||||
dw_const_u32_from_attrib(DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib)
|
||||
{
|
||||
DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib);
|
||||
AssertAlways(value_class == DW_AttribClass_Null || value_class == DW_AttribClass_Const);
|
||||
@@ -1707,7 +1707,7 @@ dw_const_u32_from_attrib_ptr(DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib
|
||||
}
|
||||
|
||||
internal S64
|
||||
dw_const_s64_from_attrib_ptr(DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib)
|
||||
dw_const_s64_from_attrib(DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib)
|
||||
{
|
||||
DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib);
|
||||
AssertAlways(value_class == DW_AttribClass_Null || value_class == DW_AttribClass_Const);
|
||||
@@ -1715,7 +1715,7 @@ dw_const_s64_from_attrib_ptr(DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib
|
||||
}
|
||||
|
||||
internal S32
|
||||
dw_const_s32_from_attrib_ptr(DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib)
|
||||
dw_const_s32_from_attrib(DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib)
|
||||
{
|
||||
DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib);
|
||||
AssertAlways(value_class == DW_AttribClass_Null || value_class == DW_AttribClass_Const);
|
||||
@@ -1723,7 +1723,7 @@ dw_const_s32_from_attrib_ptr(DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib
|
||||
}
|
||||
|
||||
internal B32
|
||||
dw_flag_from_attrib_ptr(DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib)
|
||||
dw_flag_from_attrib(DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib)
|
||||
{
|
||||
DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib);
|
||||
AssertAlways(value_class == DW_AttribClass_Null || value_class == DW_AttribClass_Flag);
|
||||
@@ -1731,7 +1731,7 @@ dw_flag_from_attrib_ptr(DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib)
|
||||
}
|
||||
|
||||
internal U64
|
||||
dw_address_from_attrib_ptr(DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib)
|
||||
dw_address_from_attrib(DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib)
|
||||
{
|
||||
DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib);
|
||||
AssertAlways(value_class == DW_AttribClass_Null ||
|
||||
@@ -1756,7 +1756,7 @@ dw_address_from_attrib_ptr(DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib)
|
||||
}
|
||||
|
||||
internal String8
|
||||
dw_block_from_attrib_ptr(DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib)
|
||||
dw_block_from_attrib(DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib)
|
||||
{
|
||||
DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib);
|
||||
AssertAlways(value_class == DW_AttribClass_Null || value_class == DW_AttribClass_Block);
|
||||
@@ -1764,7 +1764,7 @@ dw_block_from_attrib_ptr(DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib)
|
||||
}
|
||||
|
||||
internal String8
|
||||
dw_string_from_attrib_ptr(DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib)
|
||||
dw_string_from_attrib(DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib)
|
||||
{
|
||||
DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib);
|
||||
AssertAlways(value_class == DW_AttribClass_Null || value_class == DW_AttribClass_String || value_class == DW_AttribClass_StrOffsetsPtr);
|
||||
@@ -1772,7 +1772,7 @@ dw_string_from_attrib_ptr(DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib)
|
||||
}
|
||||
|
||||
internal String8
|
||||
dw_line_ptr_from_attrib_ptr(DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib)
|
||||
dw_line_ptr_from_attrib(DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib)
|
||||
{
|
||||
DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib);
|
||||
AssertAlways(value_class == DW_AttribClass_Null || value_class == DW_AttribClass_LinePtr);
|
||||
@@ -1780,7 +1780,7 @@ dw_line_ptr_from_attrib_ptr(DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib)
|
||||
}
|
||||
|
||||
internal DW_LineFile *
|
||||
dw_file_from_attrib_ptr(DW_CompUnit *cu, DW_LineVMHeader *line_vm, DW_Attrib *attrib)
|
||||
dw_file_from_attrib(DW_CompUnit *cu, DW_LineVMHeader *line_vm, DW_Attrib *attrib)
|
||||
{
|
||||
DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib);
|
||||
AssertAlways(value_class == DW_AttribClass_Null || value_class == DW_AttribClass_Const);
|
||||
@@ -1788,7 +1788,7 @@ dw_file_from_attrib_ptr(DW_CompUnit *cu, DW_LineVMHeader *line_vm, DW_Attrib *at
|
||||
}
|
||||
|
||||
internal DW_Reference
|
||||
dw_ref_from_attrib_ptr(DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib)
|
||||
dw_ref_from_attrib(DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib)
|
||||
{
|
||||
DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib);
|
||||
AssertAlways(value_class == DW_AttribClass_Null || value_class == DW_AttribClass_Reference);
|
||||
@@ -1796,7 +1796,7 @@ dw_ref_from_attrib_ptr(DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib)
|
||||
}
|
||||
|
||||
internal DW_LocList
|
||||
dw_loclist_from_attrib_ptr(Arena *arena, DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib)
|
||||
dw_loclist_from_attrib(Arena *arena, DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib)
|
||||
{
|
||||
DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib);
|
||||
AssertAlways(value_class == DW_AttribClass_Null ||
|
||||
@@ -1806,7 +1806,7 @@ dw_loclist_from_attrib_ptr(Arena *arena, DW_Input *input, DW_CompUnit *cu, DW_At
|
||||
}
|
||||
|
||||
internal Rng1U64List
|
||||
dw_rnglist_from_attrib_ptr(Arena *arena, DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib)
|
||||
dw_rnglist_from_attrib(Arena *arena, DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib)
|
||||
{
|
||||
Rng1U64List rnglist = {0};
|
||||
DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib);
|
||||
@@ -1837,10 +1837,10 @@ dw_attrib_from_tag(DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind k
|
||||
{
|
||||
DW_Attrib *attrib = dw_attrib_from_tag_(tag, kind);
|
||||
|
||||
if (attrib->attrib_kind == DW_Attrib_Null) {
|
||||
if (attrib->attrib_kind == DW_AttribKind_Null) {
|
||||
if (cu && cu->tag_ht) {
|
||||
DW_Attrib *ao_attrib = dw_attrib_from_tag_(tag, DW_Attrib_AbstractOrigin);
|
||||
if (ao_attrib->attrib_kind == DW_Attrib_AbstractOrigin) {
|
||||
DW_Attrib *ao_attrib = dw_attrib_from_tag_(tag, DW_AttribKind_AbstractOrigin);
|
||||
if (ao_attrib->attrib_kind == DW_AttribKind_AbstractOrigin) {
|
||||
DW_Reference ref = dw_interp_ref(input, cu, ao_attrib->form_kind, ao_attrib->form);
|
||||
DW_TagNode *ref_tag = dw_tag_node_from_info_off(ref.cu, ref.info_off);
|
||||
attrib = dw_attrib_from_tag_(ref_tag->tag, kind);
|
||||
@@ -1855,103 +1855,103 @@ internal B32
|
||||
dw_tag_has_attrib(DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind)
|
||||
{
|
||||
DW_Attrib *attrib = dw_attrib_from_tag(input, cu, tag, kind);
|
||||
B32 has_attrib = attrib->attrib_kind != DW_Attrib_Null;
|
||||
B32 has_attrib = attrib->attrib_kind != DW_AttribKind_Null;
|
||||
return has_attrib;
|
||||
}
|
||||
|
||||
internal String8
|
||||
dw_exprloc_from_attrib(DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind)
|
||||
dw_exprloc_from_tag_attrib_kind(DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind)
|
||||
{
|
||||
return dw_exprloc_from_attrib_ptr(input, cu, dw_attrib_from_tag(input, cu, tag, kind));
|
||||
return dw_exprloc_from_attrib(input, cu, dw_attrib_from_tag(input, cu, tag, kind));
|
||||
}
|
||||
|
||||
internal String8
|
||||
dw_block_from_attrib(DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind)
|
||||
dw_block_from_tag_attrib_kind(DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind)
|
||||
{
|
||||
return dw_block_from_attrib_ptr(input, cu, dw_attrib_from_tag(input, cu, tag, kind));
|
||||
return dw_block_from_attrib(input, cu, dw_attrib_from_tag(input, cu, tag, kind));
|
||||
}
|
||||
|
||||
internal U128
|
||||
dw_const_u128_from_attrib(DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind)
|
||||
dw_const_u128_from_tag_attrib_kind(DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind)
|
||||
{
|
||||
return dw_const_u128_from_attrib_ptr(input, cu, dw_attrib_from_tag(input, cu, tag, kind));
|
||||
return dw_const_u128_from_attrib(input, cu, dw_attrib_from_tag(input, cu, tag, kind));
|
||||
}
|
||||
|
||||
internal U64
|
||||
dw_const_u64_from_attrib(DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind)
|
||||
dw_const_u64_from_tag_attrib_kind(DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind)
|
||||
{
|
||||
return dw_const_u64_from_attrib_ptr(input, cu, dw_attrib_from_tag(input, cu, tag, kind));
|
||||
return dw_const_u64_from_attrib(input, cu, dw_attrib_from_tag(input, cu, tag, kind));
|
||||
}
|
||||
|
||||
internal U32
|
||||
dw_const_u32_from_attrib(DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind)
|
||||
dw_const_u32_from_tag_attrib_kind(DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind)
|
||||
{
|
||||
return dw_const_u32_from_attrib_ptr(input, cu, dw_attrib_from_tag(input, cu, tag, kind));
|
||||
return dw_const_u32_from_attrib(input, cu, dw_attrib_from_tag(input, cu, tag, kind));
|
||||
}
|
||||
|
||||
internal U64
|
||||
dw_address_from_attrib(DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind)
|
||||
dw_address_from_tag_attrib_kind(DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind)
|
||||
{
|
||||
return dw_address_from_attrib_ptr(input, cu, dw_attrib_from_tag(input, cu, tag, kind));
|
||||
return dw_address_from_attrib(input, cu, dw_attrib_from_tag(input, cu, tag, kind));
|
||||
}
|
||||
|
||||
internal String8
|
||||
dw_string_from_attrib(DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind)
|
||||
dw_string_from_tag_attrib_kind(DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind)
|
||||
{
|
||||
return dw_string_from_attrib_ptr(input, cu, dw_attrib_from_tag(input, cu, tag, kind));
|
||||
return dw_string_from_attrib(input, cu, dw_attrib_from_tag(input, cu, tag, kind));
|
||||
}
|
||||
|
||||
internal String8
|
||||
dw_line_ptr_from_attrib(DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind)
|
||||
dw_line_ptr_from_tag_attrib_kind(DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind)
|
||||
{
|
||||
return dw_line_ptr_from_attrib_ptr(input, cu, dw_attrib_from_tag(input, cu, tag, kind));
|
||||
return dw_line_ptr_from_attrib(input, cu, dw_attrib_from_tag(input, cu, tag, kind));
|
||||
}
|
||||
|
||||
internal DW_Reference
|
||||
dw_ref_from_attrib(DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind)
|
||||
dw_ref_from_tag_attrib_kind(DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind)
|
||||
{
|
||||
return dw_ref_from_attrib_ptr(input, cu, dw_attrib_from_tag(input, cu, tag, kind));
|
||||
return dw_ref_from_attrib(input, cu, dw_attrib_from_tag(input, cu, tag, kind));
|
||||
}
|
||||
|
||||
internal DW_LocList
|
||||
dw_loclist_from_attrib(Arena *arena, DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind)
|
||||
dw_loclist_from_tag_attrib_kind(Arena *arena, DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind)
|
||||
{
|
||||
return dw_loclist_from_attrib_ptr(arena, input, cu, dw_attrib_from_tag(input, cu, tag, kind));
|
||||
return dw_loclist_from_attrib(arena, input, cu, dw_attrib_from_tag(input, cu, tag, kind));
|
||||
}
|
||||
|
||||
internal Rng1U64List
|
||||
dw_rnglist_from_attrib(Arena *arena, DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind)
|
||||
dw_rnglist_from_tag_attrib_kind(Arena *arena, DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind)
|
||||
{
|
||||
return dw_rnglist_from_attrib_ptr(arena, input, cu, dw_attrib_from_tag(input, cu, tag, kind));
|
||||
return dw_rnglist_from_attrib(arena, input, cu, dw_attrib_from_tag(input, cu, tag, kind));
|
||||
}
|
||||
|
||||
internal B32
|
||||
dw_flag_from_attrib(DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind)
|
||||
dw_flag_from_tag_attrib_kind(DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind)
|
||||
{
|
||||
return dw_flag_from_attrib_ptr(input, cu, dw_attrib_from_tag(input, cu, tag, kind));
|
||||
return dw_flag_from_attrib(input, cu, dw_attrib_from_tag(input, cu, tag, kind));
|
||||
}
|
||||
|
||||
internal DW_LineFile *
|
||||
dw_file_from_attrib(DW_Input *input, DW_CompUnit *cu, DW_LineVMHeader *line_vm, DW_Tag tag, DW_AttribKind kind)
|
||||
dw_file_from_tag_attrib_kind(DW_Input *input, DW_CompUnit *cu, DW_LineVMHeader *line_vm, DW_Tag tag, DW_AttribKind kind)
|
||||
{
|
||||
return dw_file_from_attrib_ptr(cu, line_vm, dw_attrib_from_tag(input, cu, tag, kind));
|
||||
return dw_file_from_attrib(cu, line_vm, dw_attrib_from_tag(input, cu, tag, kind));
|
||||
}
|
||||
|
||||
internal B32
|
||||
dw_try_byte_size_from_tag(DW_Input *input, DW_CompUnit *cu, DW_Tag tag, U64 *byte_size_out)
|
||||
{
|
||||
B32 has_byte_size = dw_tag_has_attrib(input, cu, tag, DW_Attrib_ByteSize);
|
||||
B32 has_bit_size = dw_tag_has_attrib(input, cu, tag, DW_Attrib_BitSize );
|
||||
B32 has_byte_size = dw_tag_has_attrib(input, cu, tag, DW_AttribKind_ByteSize);
|
||||
B32 has_bit_size = dw_tag_has_attrib(input, cu, tag, DW_AttribKind_BitSize );
|
||||
|
||||
if (has_byte_size && has_bit_size) {
|
||||
Assert(!"ill formated byte size");
|
||||
}
|
||||
|
||||
if (has_byte_size) {
|
||||
*byte_size_out = dw_const_u64_from_attrib(input, cu, tag, DW_Attrib_ByteSize);
|
||||
*byte_size_out = dw_const_u64_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_ByteSize);
|
||||
return 1;
|
||||
} else if (has_bit_size) {
|
||||
U64 bit_size = dw_const_u64_from_attrib(input, cu, tag, DW_Attrib_BitSize);
|
||||
U64 bit_size = dw_const_u64_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_BitSize);
|
||||
*byte_size_out = bit_size / 8;
|
||||
return 1;
|
||||
}
|
||||
@@ -1985,13 +1985,13 @@ dw_u64_from_attrib(DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind k
|
||||
DW_Attrib *attrib = dw_attrib_from_tag(input, cu, tag, kind);
|
||||
DW_AttribClass attrib_class = dw_value_class_from_attrib(cu, attrib);
|
||||
if (attrib_class == DW_AttribClass_Const || attrib_class == DW_AttribClass_Block) {
|
||||
if (dw_tag_has_attrib(input, cu, tag, DW_Attrib_Type)) {
|
||||
if (dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Type)) {
|
||||
Temp scratch = scratch_begin(0,0);
|
||||
DW_Reference type_ref = dw_ref_from_attrib(input, cu, tag, DW_Attrib_Type);
|
||||
DW_Reference type_ref = dw_ref_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Type);
|
||||
DW_Tag type_tag = {0};
|
||||
dw_read_tag_cu(scratch.arena, input, type_ref.cu, type_ref.info_off, &type_tag);
|
||||
U64 type_byte_size = dw_byte_size_from_tag(input, cu, type_tag);
|
||||
DW_ATE type_encoding = dw_const_u64_from_attrib(input, type_ref.cu, type_tag, DW_Attrib_Encoding);
|
||||
DW_ATE type_encoding = dw_const_u64_from_tag_attrib_kind(input, type_ref.cu, type_tag, DW_AttribKind_Encoding);
|
||||
if (type_encoding == DW_ATE_Unsigned || type_encoding == DW_ATE_UnsignedChar) {
|
||||
result = dw_interp_const64(type_byte_size, type_encoding, attrib->form_kind, attrib->form);
|
||||
}
|
||||
@@ -2121,15 +2121,15 @@ dw_cu_from_info_off(Arena *arena, DW_Input *input, DW_ListUnitInput lu_input, U6
|
||||
dw_read_tag(arena, data, cursor, range.min, abbrev_table, abbrev_data, version, format, address_size, &cu_tag);
|
||||
|
||||
// TODO: handle these unit types
|
||||
Assert(cu_tag.kind != DW_Tag_SkeletonUnit);
|
||||
Assert(cu_tag.kind != DW_Tag_TypeUnit);
|
||||
Assert(cu_tag.kind != DW_TagKind_SkeletonUnit);
|
||||
Assert(cu_tag.kind != DW_TagKind_TypeUnit);
|
||||
|
||||
if (cu_tag.kind == DW_Tag_CompileUnit || cu_tag.kind == DW_Tag_PartialUnit) {
|
||||
if (cu_tag.kind == DW_TagKind_CompileUnit || cu_tag.kind == DW_TagKind_PartialUnit) {
|
||||
// fetch attribs for list sections
|
||||
DW_Attrib *addr_base_attrib = dw_attrib_from_tag(0, 0, cu_tag, DW_Attrib_AddrBase );
|
||||
DW_Attrib *str_offsets_base_attrib = dw_attrib_from_tag(0, 0, cu_tag, DW_Attrib_StrOffsetsBase);
|
||||
DW_Attrib *rnglists_base_attrib = dw_attrib_from_tag(0, 0, cu_tag, DW_Attrib_RngListsBase );
|
||||
DW_Attrib *loclists_base_attrib = dw_attrib_from_tag(0, 0, cu_tag, DW_Attrib_LocListsBase );
|
||||
DW_Attrib *addr_base_attrib = dw_attrib_from_tag(0, 0, cu_tag, DW_AttribKind_AddrBase );
|
||||
DW_Attrib *str_offsets_base_attrib = dw_attrib_from_tag(0, 0, cu_tag, DW_AttribKind_StrOffsetsBase);
|
||||
DW_Attrib *rnglists_base_attrib = dw_attrib_from_tag(0, 0, cu_tag, DW_AttribKind_RngListsBase );
|
||||
DW_Attrib *loclists_base_attrib = dw_attrib_from_tag(0, 0, cu_tag, DW_AttribKind_LocListsBase );
|
||||
|
||||
// interp attribs as section offsets
|
||||
U64 addr_sec_off = dw_interp_sec_offset(addr_base_attrib->form_kind, addr_base_attrib->form );
|
||||
@@ -2150,7 +2150,7 @@ dw_cu_from_info_off(Arena *arena, DW_Input *input, DW_ListUnitInput lu_input, U6
|
||||
DW_ListUnit *loclists_lu = loclists_lu_idx < lu_input.loclist_count ? &lu_input.loclists[loclists_lu_idx] : 0;
|
||||
|
||||
// find compile unit base address
|
||||
DW_Attrib *low_pc_attrib = dw_attrib_from_tag(0, 0, cu_tag, DW_Attrib_LowPc);
|
||||
DW_Attrib *low_pc_attrib = dw_attrib_from_tag(0, 0, cu_tag, DW_AttribKind_LowPc);
|
||||
U64 low_pc = dw_interp_address(address_size, max_U64, addr_lu, low_pc_attrib->form_kind, low_pc_attrib->form);
|
||||
|
||||
// fill out compile unit
|
||||
@@ -2195,7 +2195,7 @@ dw_tag_tree_from_data(Arena *arena, String8 info_data, String8 abbrev_data, DW_C
|
||||
*cursor += tag_size;
|
||||
|
||||
// is this sentinel tag?
|
||||
if (tag.kind == DW_Tag_Null) {
|
||||
if (tag.kind == DW_TagKind_Null) {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2324,7 +2324,7 @@ dw_read_line_file(String8 data,
|
||||
DW_LNCT lnct = enc_arr[enc_idx*2 + 0];
|
||||
DW_FormKind form_kind = enc_arr[enc_idx*2 + 1];
|
||||
DW_Form form = {0};
|
||||
U64 bytes_read;
|
||||
U64 bytes_read = 0;
|
||||
switch (lnct) {
|
||||
case DW_LNCT_Path: {
|
||||
bytes_read = dw_read_form(data, cursor, version, format, address_size, form_kind, max_U64, &form);
|
||||
|
||||
+29
-29
@@ -376,36 +376,36 @@ internal DW_Reference dw_interp_ref (DW_Input *input, DW_CompUnit *cu, DW
|
||||
internal DW_LocList dw_interp_loclist (Arena *arena, DW_Input *input, DW_CompUnit *cu, DW_FormKind form_kind, DW_Form form);
|
||||
internal Rng1U64List dw_interp_rnglist (Arena *arena, DW_Input *input, DW_CompUnit *cu, DW_FormKind form_kind, DW_Form form);
|
||||
|
||||
internal String8 dw_exprloc_from_attrib_ptr (DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
||||
internal U128 dw_const_u128_from_attrib_ptr(DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
||||
internal U64 dw_const_u64_from_attrib_ptr (DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
||||
internal U32 dw_const_u32_from_attrib_ptr (DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
||||
internal S64 dw_const_s64_from_attrib_ptr (DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
||||
internal S32 dw_const_s32_from_attrib_ptr (DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
||||
internal B32 dw_flag_from_attrib_ptr (DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
||||
internal U64 dw_address_from_attrib_ptr (DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
||||
internal String8 dw_block_from_attrib_ptr (DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
||||
internal String8 dw_string_from_attrib_ptr (DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
||||
internal String8 dw_line_ptr_from_attrib_ptr (DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
||||
internal DW_LineFile * dw_file_from_attrib_ptr (DW_CompUnit *cu, DW_LineVMHeader *line_vm, DW_Attrib *attrib);
|
||||
internal DW_Reference dw_ref_from_attrib_ptr (DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
||||
internal DW_LocList dw_loclist_from_attrib_ptr (Arena *arena, DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
||||
internal Rng1U64List dw_rnglist_from_attrib_ptr (Arena *arena, DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
||||
internal String8 dw_exprloc_from_attrib (DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
||||
internal U128 dw_const_u128_from_attrib(DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
||||
internal U64 dw_const_u64_from_attrib (DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
||||
internal U32 dw_const_u32_from_attrib (DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
||||
internal S64 dw_const_s64_from_attrib (DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
||||
internal S32 dw_const_s32_from_attrib (DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
||||
internal B32 dw_flag_from_attrib (DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
||||
internal U64 dw_address_from_attrib (DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
||||
internal String8 dw_block_from_attrib (DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
||||
internal String8 dw_string_from_attrib (DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
||||
internal String8 dw_line_ptr_from_attrib (DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
||||
internal DW_LineFile * dw_file_from_attrib (DW_CompUnit *cu, DW_LineVMHeader *line_vm, DW_Attrib *attrib);
|
||||
internal DW_Reference dw_ref_from_attrib (DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
||||
internal DW_LocList dw_loclist_from_attrib (Arena *arena, DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
||||
internal Rng1U64List dw_rnglist_from_attrib (Arena *arena, DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
||||
|
||||
internal String8 dw_exprloc_from_attrib (DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
||||
internal U128 dw_const_u128_from_attrib(DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
||||
internal U64 dw_const_u64_from_attrib (DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
||||
internal U32 dw_const_u32_from_attrib (DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
||||
internal B32 dw_flag_from_attrib (DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
||||
internal U64 dw_address_from_attrib (DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
||||
internal String8 dw_block_from_attrib (DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
||||
internal String8 dw_string_from_attrib (DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
||||
internal String8 dw_line_ptr_from_attrib (DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
||||
internal String8 dw_line_ptr_from_attrib (DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
||||
internal DW_LineFile * dw_file_from_attrib (DW_Input *input, DW_CompUnit *cu, DW_LineVMHeader *line_vm, DW_Tag tag, DW_AttribKind kind);
|
||||
internal DW_Reference dw_ref_from_attrib (DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
||||
internal DW_LocList dw_loclist_from_attrib (Arena *arena, DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
||||
internal Rng1U64List dw_rnglist_from_attrib (Arena *arena, DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
||||
internal String8 dw_exprloc_from_tag_attrib_kind (DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
||||
internal U128 dw_const_u128_from_tag_attrib_kind(DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
||||
internal U64 dw_const_u64_from_tag_attrib_kind (DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
||||
internal U32 dw_const_u32_from_tag_attrib_kind (DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
||||
internal B32 dw_flag_from_tag_attrib_kind (DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
||||
internal U64 dw_address_from_tag_attrib_kind (DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
||||
internal String8 dw_block_from_tag_attrib_kind (DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
||||
internal String8 dw_string_from_tag_attrib_kind (DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
||||
internal String8 dw_line_ptr_from_tag_attrib_kind (DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
||||
internal String8 dw_line_ptr_from_tag_attrib_kind (DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
||||
internal DW_LineFile * dw_file_from_tag_attrib_kind (DW_Input *input, DW_CompUnit *cu, DW_LineVMHeader *line_vm, DW_Tag tag, DW_AttribKind kind);
|
||||
internal DW_Reference dw_ref_from_tag_attrib_kind (DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
||||
internal DW_LocList dw_loclist_from_tag_attrib_kind (Arena *arena, DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
||||
internal Rng1U64List dw_rnglist_from_tag_attrib_kind (Arena *arena, DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
||||
|
||||
// compile unit
|
||||
|
||||
|
||||
+19
-17
@@ -119,10 +119,10 @@ enum
|
||||
ELF_PType_Tls = 7,
|
||||
ELF_PType_LoOs = 0x60000000,
|
||||
ELF_PType_HiOs = 0x6fffffff,
|
||||
|
||||
|
||||
ELF_PType_LowProc = 0x70000000,
|
||||
ELF_PType_HighProc = 0x7fffffff,
|
||||
|
||||
|
||||
// specific to Sun
|
||||
ELF_PType_LowSunW = 0x6ffffffa,
|
||||
ELF_PType_SunWBSS = 0x6ffffffb,
|
||||
@@ -169,7 +169,7 @@ enum
|
||||
ELF_SectionCode_SUNW_verdef = 0x6ffffffd,
|
||||
ELF_SectionCode_SUNW_verneed = 0x6ffffffe, // Versions defined by file
|
||||
ELF_SectionCode_SUNW_versym = 0x6fffffff, // Versions needed by file
|
||||
|
||||
|
||||
// Symbol versions
|
||||
ELF_SectionCode_GNU_verdef = ELF_SectionCode_SUNW_verdef,
|
||||
ELF_SectionCode_GNU_verneed = ELF_SectionCode_SUNW_verneed,
|
||||
@@ -185,22 +185,22 @@ enum
|
||||
ELF_SectionIndex_Undef = 0, // Symbol with section index is undefined and must be resolved by the link editor
|
||||
ELF_SectionIndex_Abs = 0xfff1, // Symbol has absolute value and wont change after relocations
|
||||
ELF_SectionIndex_Common = 0xfff2, // This symbol indicates to linker to allocate the storage at address multiple of st_value
|
||||
|
||||
|
||||
ELF_SectionIndex_LoReserve = 0xff00,
|
||||
ELF_SectionIndex_HiReserve = 0xffff,
|
||||
|
||||
|
||||
// Processor specific
|
||||
ELF_SectionIndex_LoProc = ELF_SectionIndex_LoReserve,
|
||||
ELF_SectionIndex_HiProc = 0xff1f,
|
||||
|
||||
|
||||
// Reserved for OS
|
||||
ELF_SectionIndex_LoOs = 0xff20,
|
||||
ELF_SectionIndex_HiOs = 0xff3f,
|
||||
|
||||
|
||||
ELF_SectionIndex_IA64_ASNI_Common = ELF_SectionIndex_LoProc,
|
||||
ELF_SectionIndex_X8664_LCommon = 0xff02,
|
||||
ELF_SectionIndex_MIPS_SCommon = 0xff03,
|
||||
|
||||
|
||||
ELF_SectionIndex_TIC6X_Common = ELF_SectionIndex_LoReserve,
|
||||
ELF_SectionIndex_MIPS_SUndefined = 0xff04,
|
||||
};
|
||||
@@ -271,7 +271,7 @@ typedef U32 ELF_DynTag;
|
||||
enum
|
||||
{
|
||||
ELF_DynTag_Null = 0,
|
||||
|
||||
|
||||
ELF_DynTag_Needed = 1,
|
||||
ELF_DynTag_PltRelsz = 2,
|
||||
ELF_DynTag_PltGot = 3,
|
||||
@@ -305,10 +305,10 @@ enum
|
||||
ELF_DynTag_PreInitArray = 32,
|
||||
ELF_DynTag_PreInitArraysz = 33,
|
||||
ELF_DynTag_SymtabShndx = 34,
|
||||
|
||||
|
||||
ELF_DynTag_LoOs = 0x6000000D,
|
||||
ELF_DynTag_HiOs = 0x6ffff000,
|
||||
|
||||
|
||||
ELF_DynTag_ValRngLo = 0x6ffffd00,
|
||||
ELF_DynTag_GNU_PreLinked = 0x6ffffdf5,
|
||||
ELF_DynTag_GNU_Conflictsz = 0x6ffffdf6,
|
||||
@@ -322,7 +322,7 @@ enum
|
||||
ELF_DynTag_SymInSz = 0x6ffffdfe,
|
||||
ELF_DynTag_SymInEnt = 0x6ffffdff,
|
||||
ELF_DynTag_ValRngHi = ELF_DynTag_SymInEnt,
|
||||
|
||||
|
||||
ELF_DynTag_AddrRngLo = 0x6ffffe00,
|
||||
ELF_DynTag_GNU_Hash = 0x6ffffef5,
|
||||
ELF_DynTag_TlsDescPlt = 0x6ffffef6,
|
||||
@@ -336,7 +336,7 @@ enum
|
||||
ELF_DynTag_MoveTab = 0x6ffffefe,
|
||||
ELF_DynTag_SymInfo = 0x6ffffeff,
|
||||
ELF_DynTag_AddrRngHi = ELF_DynTag_SymInfo,
|
||||
|
||||
|
||||
ELF_DynTag_RelaCount = 0x6ffffff9,
|
||||
ELF_DynTag_RelCount = 0x6ffffffa,
|
||||
ELF_DynTag_Flags_1 = 0x6ffffffb,
|
||||
@@ -671,6 +671,9 @@ typedef enum ELF_Identifier
|
||||
ELF_Identifier_Max = 16,
|
||||
} ELF_Identifier;
|
||||
|
||||
read_only global U8 elf_magic[] = {0x7f, 'E', 'L', 'F'};
|
||||
read_only global String8 elf_magic_string = {elf_magic, sizeof(elf_magic)};
|
||||
|
||||
typedef U16 ELF_Type;
|
||||
typedef enum ELF_TypeEnum
|
||||
{
|
||||
@@ -951,10 +954,10 @@ enum ELF_CompressTypeEnum
|
||||
ELF_CompressType_None = 0,
|
||||
ELF_CompressType_ZLib = 1,
|
||||
ELF_CompressType_ZStd = 2,
|
||||
|
||||
|
||||
ELF_CompressType_LoOs = 0x60000000,
|
||||
ELF_CompressType_HiOs = 0x6fffffff,
|
||||
|
||||
|
||||
ELF_CompressType_LoProc = 0x70000000,
|
||||
ELF_CompressType_HiProc = 0x7fffffff,
|
||||
};
|
||||
@@ -975,7 +978,7 @@ typedef struct ELF_Chdr64
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal ELF_Hdr64 elf_hdr64_from_ehdr32(ELF_Hdr32 h32);
|
||||
internal ELF_Hdr64 elf_hdr64_from_hdr32(ELF_Hdr32 h32);
|
||||
internal ELF_Shdr64 elf_shdr64_from_shdr32(ELF_Shdr32 h32);
|
||||
internal ELF_Phdr64 elf_phdr64_from_phdr32(ELF_Phdr32 h32);
|
||||
internal ELF_Dyn64 elf_dyn64_from_dyn32 (ELF_Dyn32 h32);
|
||||
@@ -993,4 +996,3 @@ internal String8 elf_string_from_class(Arena *arena, ELF_Class v);
|
||||
internal Arch arch_from_elf_machine(ELF_MachineKind machine);
|
||||
|
||||
#endif // ELF_H
|
||||
|
||||
|
||||
+128
-105
@@ -1,143 +1,166 @@
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal B32
|
||||
elf_check_magic(String8 data)
|
||||
{
|
||||
U8 sig[ELF_Identifier_Max] = {0};
|
||||
str8_deserial_read(data, 0, &sig[0], sizeof(sig), 1);
|
||||
B32 is_magic_valid = (sig[ELF_Identifier_Mag0] == 0x7f && sig[ELF_Identifier_Mag1] == 'E' && sig[ELF_Identifier_Mag2] == 'L' && sig[ELF_Identifier_Mag3] == 'F');
|
||||
return is_magic_valid;
|
||||
}
|
||||
//- rjf: top-level binary parsing
|
||||
|
||||
internal ELF_BinInfo
|
||||
elf_bin_from_data(String8 data)
|
||||
internal ELF_Bin
|
||||
elf_bin_from_data(Arena *arena, String8 data)
|
||||
{
|
||||
ELF_Hdr64 hdr64 = {0};
|
||||
Rng1U64 sh_name_range = rng_1u64(0,0);
|
||||
|
||||
if (elf_check_magic(data)) {
|
||||
ELF_Bin bin = {0};
|
||||
if(str8_match(str8_prefix(data, elf_magic_string.size), elf_magic_string, 0) &&
|
||||
data.size >= ELF_Identifier_Max)
|
||||
{
|
||||
//- rjf: parse sig/header
|
||||
U8 sig[ELF_Identifier_Max] = {0};
|
||||
str8_deserial_read(data, 0, &sig[0], sizeof(sig), 1);
|
||||
|
||||
switch (sig[ELF_Identifier_Class]) {
|
||||
case ELF_Class_None: break;
|
||||
case ELF_Class_32: {
|
||||
ELF_Hdr32 hdr32 = {0};
|
||||
U64 hdr_size = str8_deserial_read_struct(data, 0, &hdr32);
|
||||
if (hdr_size == sizeof(hdr32)) {
|
||||
hdr64 = elf_hdr64_from_hdr32(hdr32);
|
||||
|
||||
U64 shstr_off = hdr32.e_shoff + hdr32.e_shentsize*hdr32.e_shstrndx;
|
||||
ELF_Shdr32 shdr = {0};
|
||||
U64 shdr_size = str8_deserial_read_struct(data, shstr_off, &shdr);
|
||||
|
||||
if (shdr_size == sizeof(shdr)) {
|
||||
sh_name_range = rng_1u64(shdr.sh_offset, shdr.sh_offset + shdr.sh_size);
|
||||
switch(sig[ELF_Identifier_Class])
|
||||
{
|
||||
default:
|
||||
case ELF_Class_None:{}break;
|
||||
case ELF_Class_32:
|
||||
{
|
||||
ELF_Hdr32 hdr32 = {0};
|
||||
U64 hdr_size = str8_deserial_read_struct(data, 0, &hdr32);
|
||||
if(hdr_size == sizeof(hdr32))
|
||||
{
|
||||
bin.hdr = elf_hdr64_from_hdr32(hdr32);
|
||||
U64 shstr_off = hdr32.e_shoff + hdr32.e_shentsize*hdr32.e_shstrndx;
|
||||
ELF_Shdr32 shdr = {0};
|
||||
U64 shdr_size = str8_deserial_read_struct(data, shstr_off, &shdr);
|
||||
if(shdr_size == sizeof(shdr))
|
||||
{
|
||||
bin.sh_name_range = rng_1u64(shdr.sh_offset, shdr.sh_offset + shdr.sh_size);
|
||||
}
|
||||
}
|
||||
}break;
|
||||
case ELF_Class_64:
|
||||
{
|
||||
ELF_Hdr64 hdr64 = {0};
|
||||
U64 hdr_size = str8_deserial_read_struct(data, 0, &hdr64);
|
||||
if(hdr_size == sizeof(hdr64))
|
||||
{
|
||||
bin.hdr = hdr64;
|
||||
U64 shstr_off = hdr64.e_shoff + hdr64.e_shentsize*hdr64.e_shstrndx;
|
||||
ELF_Shdr64 shdr = {0};
|
||||
U64 shdr_size = str8_deserial_read_struct(data, shstr_off, &shdr);
|
||||
if(shdr_size == sizeof(shdr))
|
||||
{
|
||||
bin.sh_name_range = rng_1u64(shdr.sh_offset, shdr.sh_offset + shdr.sh_size);
|
||||
}
|
||||
}
|
||||
}break;
|
||||
}
|
||||
|
||||
//- rjf: gather all shdrs
|
||||
{
|
||||
ELF_Hdr64 *hdr = &bin.hdr;
|
||||
bin.shdrs.count = hdr->e_shnum;
|
||||
bin.shdrs.v = push_array(arena, ELF_Shdr64, hdr->e_shnum);
|
||||
Rng1U64 shdr_range = rng_1u64(hdr->e_shoff, hdr->e_shoff + hdr->e_shentsize*hdr->e_shnum);
|
||||
String8 shdr_data = str8_substr(data, shdr_range);
|
||||
for EachIndex(shdr_idx, hdr->e_shnum)
|
||||
{
|
||||
switch(hdr->e_ident[ELF_Identifier_Class])
|
||||
{
|
||||
default:
|
||||
case ELF_Class_None:
|
||||
{}break;
|
||||
case ELF_Class_32:
|
||||
{
|
||||
ELF_Shdr32 shdr32 = {0};
|
||||
str8_deserial_read_struct(shdr_data, shdr_idx * sizeof(ELF_Shdr32), &shdr32);
|
||||
bin.shdrs.v[shdr_idx] = elf_shdr64_from_shdr32(shdr32);
|
||||
}break;
|
||||
case ELF_Class_64:
|
||||
{
|
||||
str8_deserial_read_struct(shdr_data, shdr_idx * sizeof(ELF_Shdr64), &bin.shdrs.v[shdr_idx]);
|
||||
}break;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case ELF_Class_64: {
|
||||
U64 hdr_size = str8_deserial_read_struct(data, 0, &hdr64);
|
||||
if (hdr_size == sizeof(hdr64)) {
|
||||
U64 shstr_off = hdr64.e_shoff + hdr64.e_shentsize*hdr64.e_shstrndx;
|
||||
ELF_Shdr64 shdr = {0};
|
||||
U64 shdr_size = str8_deserial_read_struct(data, shstr_off, &shdr);
|
||||
|
||||
if (shdr_size == sizeof(shdr)) {
|
||||
sh_name_range = rng_1u64(shdr.sh_offset, shdr.sh_offset + shdr.sh_size);
|
||||
}
|
||||
|
||||
//- rjf: gather all phdrs
|
||||
{
|
||||
ELF_Hdr64 *hdr = &bin.hdr;
|
||||
bin.phdrs.count = hdr->e_phnum;
|
||||
bin.phdrs.v = push_array(arena, ELF_Phdr64, hdr->e_phnum);
|
||||
Rng1U64 phdr_range = rng_1u64(hdr->e_phoff, hdr->e_phoff + hdr->e_phentsize*hdr->e_phnum);
|
||||
String8 phdr_data = str8_substr(data, phdr_range);
|
||||
for EachIndex(phdr_idx, hdr->e_phnum)
|
||||
{
|
||||
switch(hdr->e_ident[ELF_Identifier_Class])
|
||||
{
|
||||
default:
|
||||
case ELF_Class_None:
|
||||
{}break;
|
||||
case ELF_Class_32:
|
||||
{
|
||||
ELF_Phdr32 phdr32 = {0};
|
||||
str8_deserial_read_struct(phdr_data, phdr_idx * sizeof(ELF_Phdr32), &phdr32);
|
||||
bin.phdrs.v[phdr_idx] = elf_phdr64_from_phdr32(phdr32);
|
||||
}break;
|
||||
case ELF_Class_64:
|
||||
{
|
||||
str8_deserial_read_struct(phdr_data, phdr_idx * sizeof(ELF_Phdr64), &bin.phdrs.v[phdr_idx]);
|
||||
}break;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
default: Assert(!"invalid elf header"); break;
|
||||
}
|
||||
}
|
||||
|
||||
ELF_BinInfo info = {0};
|
||||
info.hdr = hdr64;
|
||||
info.sh_name_range = sh_name_range;
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
internal ELF_Shdr64Array
|
||||
elf_shdr64_array_from_bin(Arena *arena, String8 raw_data, ELF_Hdr64 *hdr)
|
||||
{
|
||||
Rng1U64 shdr_range = rng_1u64(hdr->e_shoff, hdr->e_shoff + hdr->e_shentsize*hdr->e_shnum);
|
||||
String8 shdr_data = str8_substr(raw_data, shdr_range);
|
||||
|
||||
ELF_Shdr64Array result = {0};
|
||||
result.count = hdr->e_shnum;
|
||||
result.v = push_array(arena, ELF_Shdr64, hdr->e_shnum);
|
||||
|
||||
for(U64 shdr_idx = 0; shdr_idx < hdr->e_shnum; ++shdr_idx) {
|
||||
switch (hdr->e_ident[ELF_Identifier_Class]) {
|
||||
case ELF_Class_None: break;
|
||||
case ELF_Class_32: {
|
||||
ELF_Shdr32 shdr32 = {0};
|
||||
str8_deserial_read_struct(shdr_data, shdr_idx * sizeof(ELF_Shdr32), &shdr32);
|
||||
result.v[shdr_idx] = elf_shdr64_from_shdr32(shdr32);
|
||||
} break;
|
||||
case ELF_Class_64: {
|
||||
str8_deserial_read_struct(shdr_data, shdr_idx * sizeof(ELF_Shdr64), &result.v[shdr_idx]);
|
||||
} break;
|
||||
default: InvalidPath; break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return bin;
|
||||
}
|
||||
|
||||
//- rjf: extra bin info extraction
|
||||
|
||||
internal String8
|
||||
elf_name_from_shdr64(String8 raw_data, ELF_Hdr64 *hdr, Rng1U64 sh_name_range, ELF_Shdr64 *shdr)
|
||||
elf_name_from_shdr64(String8 data, ELF_Bin *bin, ELF_Shdr64 *shdr)
|
||||
{
|
||||
String8 sh_names = str8_substr(raw_data, sh_name_range);
|
||||
String8 sh_names = str8_substr(data, bin->sh_name_range);
|
||||
String8 name = {0};
|
||||
str8_deserial_read_cstr(sh_names, shdr->sh_name, &name);
|
||||
return name;
|
||||
}
|
||||
|
||||
internal U64
|
||||
elf_base_addr_from_bin(ELF_Hdr64 *hdr)
|
||||
elf_base_addr_from_bin(ELF_Bin *bin)
|
||||
{
|
||||
NotImplemented;
|
||||
return 0;
|
||||
U64 base_vaddr = 0;
|
||||
for EachIndex(phdr_idx, bin->phdrs.count)
|
||||
{
|
||||
ELF_Phdr64 *phdr = &bin->phdrs.v[phdr_idx];
|
||||
if(phdr->p_type == ELF_PType_Load &&
|
||||
(base_vaddr == 0 || phdr->p_vaddr < base_vaddr))
|
||||
{
|
||||
base_vaddr = phdr->p_vaddr;
|
||||
}
|
||||
}
|
||||
return base_vaddr;
|
||||
}
|
||||
|
||||
internal B32
|
||||
elf_parse_debug_link(String8 raw_data, ELF_BinInfo *elf, ELF_GnuDebugLink *debug_link_out)
|
||||
internal ELF_GnuDebugLink
|
||||
elf_gnu_debug_link_from_bin(String8 raw_data, ELF_Bin *bin)
|
||||
{
|
||||
Temp scratch = scratch_begin(0,0);
|
||||
|
||||
B32 is_debug_link_present = 0;
|
||||
ELF_Shdr64Array sections = elf_shdr64_array_from_bin(scratch.arena, raw_data, &elf->hdr);
|
||||
for (U64 i = 0; i < sections.count; ++i) {
|
||||
ELF_Shdr64 *shdr = §ions.v[i];
|
||||
String8 name = elf_name_from_shdr64(raw_data, &elf->hdr, elf->sh_name_range, shdr);
|
||||
|
||||
if (str8_match(name, str8_lit(".gnu_debuglink"), 0)) {
|
||||
ELF_GnuDebugLink result = {0};
|
||||
for EachIndex(idx, bin->shdrs.count)
|
||||
{
|
||||
ELF_Shdr64 *shdr = &bin->shdrs.v[idx];
|
||||
String8 name = elf_name_from_shdr64(raw_data, bin, shdr);
|
||||
if(str8_match(name, str8_lit(".gnu_debuglink"), 0))
|
||||
{
|
||||
Rng1U64 raw_data_range = rng_1u64(shdr->sh_offset, shdr->sh_offset + shdr->sh_size);
|
||||
String8 data = str8_substr(raw_data, raw_data_range);
|
||||
|
||||
String8 path = {0};
|
||||
U32 checksum = 0;
|
||||
String8 data = str8_substr(raw_data, raw_data_range);
|
||||
String8 path = {0};
|
||||
U32 checksum = 0;
|
||||
{
|
||||
U64 cursor = 0;
|
||||
cursor += str8_deserial_read_cstr(data, cursor, &path);
|
||||
|
||||
cursor = AlignPow2(cursor, 4);
|
||||
cursor += str8_deserial_read_struct(data, cursor, &checksum);
|
||||
}
|
||||
|
||||
debug_link_out->path = path;
|
||||
debug_link_out->checksum = checksum;
|
||||
|
||||
is_debug_link_present = 1;
|
||||
result.path = path;
|
||||
result.checksum = checksum;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
return is_debug_link_present;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
+33
-17
@@ -5,32 +5,48 @@
|
||||
#define ELF_PARSE_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Parsed Structure Types
|
||||
|
||||
typedef struct ELF_BinInfo
|
||||
typedef struct ELF_Shdr64Array ELF_Shdr64Array;
|
||||
struct ELF_Shdr64Array
|
||||
{
|
||||
ELF_Shdr64 *v;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
typedef struct ELF_Phdr64Array ELF_Phdr64Array;
|
||||
struct ELF_Phdr64Array
|
||||
{
|
||||
ELF_Phdr64 *v;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
typedef struct ELF_Bin ELF_Bin;
|
||||
struct ELF_Bin
|
||||
{
|
||||
ELF_Hdr64 hdr;
|
||||
Rng1U64 sh_name_range;
|
||||
} ELF_BinInfo;
|
||||
Rng1U64 sh_name_range;
|
||||
ELF_Shdr64Array shdrs;
|
||||
ELF_Phdr64Array phdrs;
|
||||
};
|
||||
|
||||
typedef struct ELF_Shdr64Array
|
||||
{
|
||||
U64 count;
|
||||
ELF_Shdr64 *v;
|
||||
} ELF_Shdr64Array;
|
||||
|
||||
typedef struct ELF_GnuDebugLink
|
||||
typedef struct ELF_GnuDebugLink ELF_GnuDebugLink;
|
||||
struct ELF_GnuDebugLink
|
||||
{
|
||||
String8 path;
|
||||
U32 checksum;
|
||||
} ELF_GnuDebugLink;
|
||||
U32 checksum;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Parsing Functions
|
||||
|
||||
internal B32 elf_check_magic(String8 data);
|
||||
internal ELF_BinInfo elf_bin_from_data(String8 data);
|
||||
//- rjf: top-level binary parsing
|
||||
internal ELF_Bin elf_bin_from_data(Arena *arena, String8 data);
|
||||
|
||||
internal ELF_Shdr64Array elf_shdr64_array_from_bin(Arena *arena, String8 raw_data, ELF_Hdr64 *hdr);
|
||||
internal String8 elf_name_from_shdr64(String8 raw_data, ELF_Hdr64 *hdr, Rng1U64 sh_name_range, ELF_Shdr64 *shdr);
|
||||
internal U64 elf_base_addr_from_bin(ELF_Hdr64 *hdr);
|
||||
//- rjf: extra bin info extraction
|
||||
internal B32 elf_is_dwarf_present_from_bin(String8 data, ELF_Bin *bin);
|
||||
internal String8 elf_name_from_shdr64(String8 raw_data, ELF_Bin *bin, ELF_Shdr64 *shdr);
|
||||
internal U64 elf_base_addr_from_bin(ELF_Bin *bin);
|
||||
internal ELF_GnuDebugLink elf_gnu_debug_link_from_bin(String8 raw_data, ELF_Bin *bin);
|
||||
|
||||
#endif // ELF_PARSE_H
|
||||
|
||||
@@ -93,6 +93,7 @@ E_ExprKindTable:
|
||||
{ Cast Null 1 "cast(" ")" "" "" }
|
||||
{ Sizeof UnaryPrefix 1 "sizeof " "" "" "" }
|
||||
{ Typeof UnaryPrefix 1 "typeof " "" "" "" }
|
||||
{ Symbolof UnaryPrefix 1 "symbolof " "" "" "" }
|
||||
{ ByteSwap UnaryPrefix 1 "bswap " "" "" "" }
|
||||
|
||||
{ Pos UnaryPrefix 2 "+" "" "" "" }
|
||||
|
||||
+28
-25
@@ -1350,38 +1350,41 @@ e_key_wrapf(E_Key key, char *fmt, ...)
|
||||
////////////////////////////////
|
||||
//~ rjf: Eval Info Extraction
|
||||
|
||||
internal U64
|
||||
e_base_offset_from_eval(E_Eval eval)
|
||||
internal Rng1U64
|
||||
e_range_from_eval(E_Eval eval)
|
||||
{
|
||||
if(e_type_kind_is_pointer_or_ref(e_type_kind_from_key(e_type_key_unwrap(eval.irtree.type_key, E_TypeUnwrapFlag_AllDecorative))))
|
||||
// rjf: choose base offset
|
||||
U64 base_offset = 0;
|
||||
{
|
||||
eval = e_value_eval_from_eval(eval);
|
||||
}
|
||||
return eval.value.u64;
|
||||
}
|
||||
|
||||
internal U64
|
||||
e_range_size_from_eval(E_Eval eval)
|
||||
{
|
||||
U64 result = KB(16);
|
||||
{
|
||||
E_TypeKey type_core = e_type_key_unwrap(eval.irtree.type_key, E_TypeUnwrapFlag_AllDecorative);
|
||||
E_TypeKind type_core_kind = e_type_kind_from_key(type_core);
|
||||
B32 got_size = 0;
|
||||
|
||||
// rjf: try getting size from intrinsic type (e.g. arrays/etc.)
|
||||
if(!got_size)
|
||||
E_Eval base_off_eval = eval;
|
||||
if(e_type_kind_is_pointer_or_ref(e_type_kind_from_key(e_type_key_unwrap(base_off_eval.irtree.type_key, E_TypeUnwrapFlag_AllDecorative))))
|
||||
{
|
||||
if(type_core_kind == E_TypeKind_Array ||
|
||||
type_core_kind == E_TypeKind_Struct ||
|
||||
type_core_kind == E_TypeKind_Union ||
|
||||
type_core_kind == E_TypeKind_Class)
|
||||
base_off_eval = e_value_eval_from_eval(base_off_eval);
|
||||
}
|
||||
base_offset = base_off_eval.value.u64;
|
||||
}
|
||||
|
||||
// rjf: choose size
|
||||
U64 size = KB(16);
|
||||
{
|
||||
E_TypeKey type_key = e_type_key_unwrap(eval.irtree.type_key, E_TypeUnwrapFlag_AllDecorative);
|
||||
E_TypeKind type_kind = e_type_kind_from_key(type_key);
|
||||
if(type_kind == E_TypeKind_Ptr)
|
||||
{
|
||||
E_Eval ptee_eval = e_eval_wrapf(eval, "*$");
|
||||
U64 ptee_size = e_type_byte_size_from_key(ptee_eval.irtree.type_key);
|
||||
if(ptee_size > 8)
|
||||
{
|
||||
result = e_type_byte_size_from_key(type_core);
|
||||
got_size = 1;
|
||||
size = ptee_size;
|
||||
}
|
||||
}
|
||||
else if(eval.irtree.mode == E_Mode_Offset)
|
||||
{
|
||||
size = e_type_byte_size_from_key(type_key);
|
||||
}
|
||||
}
|
||||
|
||||
Rng1U64 result = r1u64(base_offset, base_offset+size);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -57,9 +57,11 @@ union E_Value
|
||||
U64 u64;
|
||||
U32 u32;
|
||||
U16 u16;
|
||||
U8 u8;
|
||||
S64 s64;
|
||||
S32 s32;
|
||||
S32 s16;
|
||||
S16 s16;
|
||||
S8 s8;
|
||||
F64 f64;
|
||||
F32 f32;
|
||||
};
|
||||
@@ -760,6 +762,7 @@ struct E_BaseCtx
|
||||
E_Module *modules;
|
||||
U64 modules_count;
|
||||
E_Module *primary_module;
|
||||
DI_MatchStore *dbgi_match_store;
|
||||
|
||||
// rjf: space hooks
|
||||
void *space_rw_user_data;
|
||||
@@ -1291,8 +1294,7 @@ internal E_Key e_key_wrapf(E_Key key, char *fmt, ...);
|
||||
////////////////////////////////
|
||||
//~ rjf: Eval Info Extraction
|
||||
|
||||
internal U64 e_base_offset_from_eval(E_Eval eval);
|
||||
internal U64 e_range_size_from_eval(E_Eval eval);
|
||||
internal Rng1U64 e_range_from_eval(E_Eval eval);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Debug Functions
|
||||
|
||||
@@ -206,6 +206,10 @@ e_interpret(String8 bytecode)
|
||||
result.code = E_InterpretationCode_BadMemRead;
|
||||
goto done;
|
||||
}
|
||||
if(e_space_match(selected_space, e_interpret_ctx->reg_space))
|
||||
{
|
||||
selected_space = e_interpret_ctx->primary_space;
|
||||
}
|
||||
}break;
|
||||
|
||||
case RDI_EvalOp_RegRead:
|
||||
|
||||
+261
-256
@@ -644,51 +644,60 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I
|
||||
{
|
||||
// rjf: unpack left-hand-side
|
||||
E_Expr *lhs = expr->first;
|
||||
E_IRTreeAndType lhs_irtree = e_push_irtree_and_type_from_expr(arena, parent, &e_default_identifier_resolution_rule, 0, 1, lhs);
|
||||
e_msg_list_concat_in_place(&result.msgs, &lhs_irtree.msgs);
|
||||
|
||||
// rjf: try all IR trees in chain
|
||||
for(E_IRTreeAndType *lhs_irtree_try = &lhs_irtree; lhs_irtree_try != 0; lhs_irtree_try = lhs_irtree_try->prev)
|
||||
// rjf: try left-hand-side, first *without* autohooks, then *with* autohooks.
|
||||
for(B32 autohooks_enabled = 0; autohooks_enabled < 2; autohooks_enabled += 1)
|
||||
{
|
||||
// rjf: gather inherited lenses from the left-hand-side
|
||||
E_IRTreeAndType lhs_irtree_try = e_push_irtree_and_type_from_expr(arena, parent, &e_default_identifier_resolution_rule, !autohooks_enabled, 1, lhs);
|
||||
for(E_IRTreeAndType *lhs_irtree_try_chain = &lhs_irtree_try; lhs_irtree_try_chain != 0; lhs_irtree_try_chain = lhs_irtree_try_chain->prev)
|
||||
{
|
||||
E_TypeKey k = lhs_irtree_try->type_key;
|
||||
E_TypeKind kind = e_type_kind_from_key(k);
|
||||
for(;kind == E_TypeKind_Lens;)
|
||||
// rjf: pick access hook based on type
|
||||
E_Type *lhs_type = e_type_from_key(lhs_irtree_try_chain->type_key);
|
||||
E_TypeAccessFunctionType *lhs_access = lhs_type->access;
|
||||
for(E_Type *lens_type = lhs_type;
|
||||
lens_type->kind == E_TypeKind_Lens || lens_type->kind == E_TypeKind_Set;
|
||||
lens_type = e_type_from_key(lens_type->direct_type_key))
|
||||
{
|
||||
E_Type *lens_type = e_type_from_key(k);
|
||||
if((lens_type->flags & E_TypeFlag_InheritedByMembers && expr->kind == E_ExprKind_MemberAccess) ||
|
||||
(lens_type->flags & E_TypeFlag_InheritedByElements && expr->kind == E_ExprKind_ArrayIndex))
|
||||
if(lens_type->access != 0)
|
||||
{
|
||||
e_type_key_list_push_front(scratch.arena, &inherited_lenses, k);
|
||||
lhs_access = lens_type->access;
|
||||
break;
|
||||
}
|
||||
k = e_type_key_direct(k);
|
||||
kind = e_type_kind_from_key(k);
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: pick access hook based on type
|
||||
E_Type *lhs_type = e_type_from_key(lhs_irtree_try->type_key);
|
||||
E_TypeAccessFunctionType *lhs_access = lhs_type->access;
|
||||
for(E_Type *lens_type = lhs_type;
|
||||
lens_type->kind == E_TypeKind_Lens || lens_type->kind == E_TypeKind_Set;
|
||||
lens_type = e_type_from_key(lens_type->direct_type_key))
|
||||
{
|
||||
if(lens_type->access != 0)
|
||||
if(lhs_access == 0)
|
||||
{
|
||||
lhs_access = lens_type->access;
|
||||
lhs_access = E_TYPE_ACCESS_FUNCTION_NAME(default);
|
||||
}
|
||||
|
||||
// rjf: call into hook to do access
|
||||
E_IRTreeAndType new_result_maybe = lhs_access(arena, parent, expr, lhs_irtree_try_chain);
|
||||
|
||||
// rjf: if we got a valid result -> gather info from this irtree
|
||||
if(new_result_maybe.root != &e_irnode_nil)
|
||||
{
|
||||
E_TypeKey k = lhs_irtree_try_chain->type_key;
|
||||
E_TypeKind kind = e_type_kind_from_key(k);
|
||||
for(;kind == E_TypeKind_Lens;)
|
||||
{
|
||||
E_Type *lens_type = e_type_from_key(k);
|
||||
if((lens_type->flags & E_TypeFlag_InheritedByMembers && expr->kind == E_ExprKind_MemberAccess) ||
|
||||
(lens_type->flags & E_TypeFlag_InheritedByElements && expr->kind == E_ExprKind_ArrayIndex))
|
||||
{
|
||||
e_type_key_list_push_front(scratch.arena, &inherited_lenses, k);
|
||||
}
|
||||
k = e_type_key_direct(k);
|
||||
kind = e_type_kind_from_key(k);
|
||||
}
|
||||
e_msg_list_concat_in_place(&result.msgs, &lhs_irtree_try_chain->msgs);
|
||||
}
|
||||
|
||||
// rjf: if we got a valid result -> we're done
|
||||
if(new_result_maybe.root != &e_irnode_nil)
|
||||
{
|
||||
result = new_result_maybe;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(lhs_access == 0)
|
||||
{
|
||||
lhs_access = E_TYPE_ACCESS_FUNCTION_NAME(default);
|
||||
}
|
||||
|
||||
// rjf: call into hook to do access
|
||||
result = lhs_access(arena, parent, expr, lhs_irtree_try);
|
||||
|
||||
// rjf: end chain if we found a result
|
||||
if(result.root != &e_irnode_nil)
|
||||
{
|
||||
break;
|
||||
@@ -727,7 +736,11 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I
|
||||
String8 full_qualified_name = str8_list_join(scratch.arena, &parts, &(StringJoin){.sep = str8_lit(".")});
|
||||
E_Expr *leaf_expr_name = e_push_expr(scratch.arena, E_ExprKind_LeafIdentifier, r1u64(0, 0));
|
||||
leaf_expr_name->string = full_qualified_name;
|
||||
result = e_push_irtree_and_type_from_expr(arena, parent, &e_default_identifier_resolution_rule, disallow_autohooks, disallow_autohooks, leaf_expr_name);
|
||||
E_IRTreeAndType new_result_maybe = e_push_irtree_and_type_from_expr(arena, parent, &e_default_identifier_resolution_rule, disallow_autohooks, disallow_autohooks, leaf_expr_name);
|
||||
if(new_result_maybe.root != &e_irnode_nil)
|
||||
{
|
||||
result = new_result_maybe;
|
||||
}
|
||||
}
|
||||
}
|
||||
}break;
|
||||
@@ -828,14 +841,18 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I
|
||||
e_msg_list_concat_in_place(&result.msgs, &cast_irtree.msgs);
|
||||
E_TypeKey cast_type = cast_irtree.type_key;
|
||||
E_TypeKind cast_type_kind = e_type_kind_from_key(cast_type);
|
||||
E_TypeKey cast_type_unwrapped = e_type_key_unwrap(cast_irtree.type_key, E_TypeUnwrapFlag_AllDecorative);
|
||||
E_TypeKind cast_type_unwrapped_kind = e_type_kind_from_key(cast_type_unwrapped);
|
||||
U64 cast_type_byte_size = e_type_byte_size_from_key(cast_type);
|
||||
E_IRTreeAndType casted_tree = e_push_irtree_and_type_from_expr(arena, parent, &e_default_identifier_resolution_rule, disallow_autohooks, 1, casted_expr);
|
||||
e_msg_list_concat_in_place(&result.msgs, &casted_tree.msgs);
|
||||
E_TypeKey casted_type = e_type_key_unwrap(casted_tree.type_key, E_TypeUnwrapFlag_AllDecorative);
|
||||
E_TypeKind casted_type_kind = e_type_kind_from_key(casted_type);
|
||||
E_TypeKey casted_type_unwrapped = e_type_key_unwrap(casted_type, E_TypeUnwrapFlag_Bitfields|E_TypeUnwrapFlag_AllDecorative);
|
||||
E_TypeKind casted_type_unwrapped_kind = e_type_kind_from_key(casted_type_unwrapped);
|
||||
U64 casted_type_byte_size = e_type_byte_size_from_key(casted_type);
|
||||
U8 in_group = e_type_group_from_kind(casted_type_kind);
|
||||
U8 out_group = e_type_group_from_kind(cast_type_kind);
|
||||
U8 in_group = e_type_group_from_kind(casted_type_unwrapped_kind);
|
||||
U8 out_group = e_type_group_from_kind(cast_type_unwrapped_kind);
|
||||
RDI_EvalConversionKind conversion_rule = rdi_eval_conversion_kind_from_typegroups(in_group, out_group);
|
||||
|
||||
// rjf: bad conditions? -> error if applicable, exit
|
||||
@@ -867,7 +884,11 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I
|
||||
{
|
||||
new_tree = e_irtree_convert_lo(arena, in_tree, out_group, in_group);
|
||||
}
|
||||
if(cast_type_byte_size < casted_type_byte_size && e_type_kind_is_integer(cast_type_kind))
|
||||
if(cast_type_byte_size < casted_type_byte_size && e_type_kind_is_integer(cast_type_unwrapped_kind))
|
||||
{
|
||||
new_tree = e_irtree_trunc(arena, in_tree, cast_type);
|
||||
}
|
||||
if(e_type_kind_is_signed(cast_type_unwrapped_kind) && e_type_kind_is_integer(casted_type_unwrapped_kind) && !e_type_kind_is_signed(casted_type_unwrapped_kind))
|
||||
{
|
||||
new_tree = e_irtree_trunc(arena, in_tree, cast_type);
|
||||
}
|
||||
@@ -932,6 +953,53 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I
|
||||
result.mode = E_Mode_Null;
|
||||
}break;
|
||||
|
||||
//- rjf: symbolof
|
||||
case E_ExprKind_Symbolof:
|
||||
{
|
||||
E_IRTreeAndType r_tree = e_push_irtree_and_type_from_expr(arena, parent, &e_default_identifier_resolution_rule, disallow_autohooks, 1, expr->first);
|
||||
E_IRNode *r_value_tree = e_irtree_resolve_to_value(arena, r_tree.mode, r_tree.root, r_tree.type_key);
|
||||
E_OpList oplist = e_oplist_from_irtree(scratch.arena, r_value_tree);
|
||||
String8 bytecode = e_bytecode_from_oplist(scratch.arena, &oplist);
|
||||
E_Interpretation interpretation = e_interpret(bytecode);
|
||||
E_Module *module = &e_module_nil;
|
||||
U32 rdi_idx = 0;
|
||||
for EachIndex(idx, e_base_ctx->modules_count)
|
||||
{
|
||||
E_Module *m = &e_base_ctx->modules[idx];
|
||||
if(e_space_match(interpretation.space, m->space) && contains_1u64(m->vaddr_range, interpretation.value.u64))
|
||||
{
|
||||
module = m;
|
||||
rdi_idx = (U32)idx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(module != &e_module_nil)
|
||||
{
|
||||
U64 voff = interpretation.value.u64 - module->vaddr_range.min;
|
||||
U64 new_vaddr = 0;
|
||||
RDI_Procedure *p = rdi_procedure_from_voff(module->rdi, voff);
|
||||
RDI_GlobalVariable *g = rdi_global_variable_from_voff(module->rdi, voff);
|
||||
U32 type_idx = 0;
|
||||
if(p->name_string_idx != 0)
|
||||
{
|
||||
type_idx = p->type_idx;
|
||||
new_vaddr = module->vaddr_range.min + rdi_first_voff_from_procedure(module->rdi, p);
|
||||
}
|
||||
else if(g->name_string_idx != 0)
|
||||
{
|
||||
type_idx = g->type_idx;
|
||||
new_vaddr = module->vaddr_range.min + g->voff;
|
||||
}
|
||||
if(type_idx != 0)
|
||||
{
|
||||
RDI_TypeNode *t = rdi_element_from_name_idx(module->rdi, TypeNodes, type_idx);
|
||||
result.root = e_irtree_const_u(arena, new_vaddr);
|
||||
result.mode = E_Mode_Value;
|
||||
result.type_key = e_type_key_ext(e_type_kind_from_rdi(t->kind), type_idx, rdi_idx);
|
||||
}
|
||||
}
|
||||
}break;
|
||||
|
||||
//- rjf: byteswap
|
||||
case E_ExprKind_ByteSwap:
|
||||
{
|
||||
@@ -1385,12 +1453,15 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I
|
||||
e_msg_list_concat_in_place(&result.msgs, &casted_tree.msgs);
|
||||
E_TypeKey cast_type = lhs_irtree.type_key;
|
||||
E_TypeKind cast_type_kind = e_type_kind_from_key(cast_type);
|
||||
E_TypeKey cast_type_unwrapped = e_type_key_unwrap(lhs_irtree.type_key, E_TypeUnwrapFlag_AllDecorative);
|
||||
E_TypeKind cast_type_unwrapped_kind = e_type_kind_from_key(cast_type_unwrapped);
|
||||
U64 cast_type_byte_size = e_type_byte_size_from_key(cast_type);
|
||||
E_TypeKey casted_type = casted_tree.type_key;
|
||||
E_TypeKind casted_type_kind = e_type_kind_from_key(casted_type);
|
||||
E_TypeKey casted_type_unwrapped = e_type_key_unwrap(casted_type, E_TypeUnwrapFlag_Bitfields|E_TypeUnwrapFlag_AllDecorative);
|
||||
E_TypeKind casted_type_unwrapped_kind = e_type_kind_from_key(casted_type_unwrapped);
|
||||
U64 casted_type_byte_size = e_type_byte_size_from_key(casted_type);
|
||||
U8 in_group = e_type_group_from_kind(casted_type_kind);
|
||||
U8 out_group = e_type_group_from_kind(cast_type_kind);
|
||||
U8 in_group = e_type_group_from_kind(casted_type_unwrapped_kind);
|
||||
U8 out_group = e_type_group_from_kind(cast_type_unwrapped_kind);
|
||||
RDI_EvalConversionKind conversion_rule = rdi_eval_conversion_kind_from_typegroups(in_group, out_group);
|
||||
|
||||
// rjf: bad conditions? -> error if applicable, exit
|
||||
@@ -1414,7 +1485,7 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I
|
||||
break;
|
||||
}
|
||||
|
||||
// rjf: generate casted result
|
||||
// rjf: generate
|
||||
{
|
||||
E_IRNode *in_tree = e_irtree_resolve_to_value(arena, casted_tree.mode, casted_tree.root, casted_type);
|
||||
E_IRNode *new_tree = in_tree;
|
||||
@@ -1422,7 +1493,11 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I
|
||||
{
|
||||
new_tree = e_irtree_convert_lo(arena, in_tree, out_group, in_group);
|
||||
}
|
||||
if(cast_type_byte_size < casted_type_byte_size && e_type_kind_is_integer(cast_type_kind))
|
||||
if(cast_type_byte_size < casted_type_byte_size && e_type_kind_is_integer(cast_type_unwrapped_kind))
|
||||
{
|
||||
new_tree = e_irtree_trunc(arena, in_tree, cast_type);
|
||||
}
|
||||
if(e_type_kind_is_signed(cast_type_unwrapped_kind) && e_type_kind_is_integer(casted_type_unwrapped_kind) && !e_type_kind_is_signed(casted_type_unwrapped_kind))
|
||||
{
|
||||
new_tree = e_irtree_trunc(arena, in_tree, cast_type);
|
||||
}
|
||||
@@ -1599,7 +1674,6 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I
|
||||
String8 qualifier = expr->qualifier;
|
||||
String8 string = expr->string;
|
||||
String8 string__redirected = string;
|
||||
String8List namespaceified_strings = {0};
|
||||
B32 string_mapped = 0;
|
||||
B32 string_is_implicit_member_name = 0;
|
||||
E_TypeKey mapped_type_key = zero_struct;
|
||||
@@ -1617,7 +1691,7 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I
|
||||
{
|
||||
//- rjf: try to map identifier via this path
|
||||
E_IdentifierResolutionPath path = identifier_resolution_rule->paths[path_idx];
|
||||
switch(path)
|
||||
ProfScope("identifier resolution %i", path) switch(path)
|
||||
{
|
||||
default:{}break;
|
||||
|
||||
@@ -1673,7 +1747,8 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I
|
||||
for(E_IRTreeAndType *prev = parent; prev != 0; prev = prev->prev)
|
||||
{
|
||||
E_Expr *access = e_expr_irext_member_access(scratch.arena, &e_expr_nil, prev, string);
|
||||
E_IRTreeAndType access_irtree = e_push_irtree_and_type_from_expr(scratch.arena, root_parent, &e_default_identifier_resolution_rule, disallow_autohooks, 1, access);
|
||||
E_IRTreeAndType access_parent = {&e_irnode_nil};
|
||||
E_IRTreeAndType access_irtree = e_push_irtree_and_type_from_expr(scratch.arena, prev->prev ? prev->prev : &access_parent, &e_default_identifier_resolution_rule, 1, 1, access);
|
||||
if(access_irtree.root != &e_irnode_nil)
|
||||
{
|
||||
string_mapped = 1;
|
||||
@@ -1682,7 +1757,10 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I
|
||||
mapped_bytecode = e_bytecode_from_oplist(arena, &oplist);
|
||||
mapped_bytecode_mode = access_irtree.mode;
|
||||
e_msg_list_concat_in_place(&result.msgs, &access_irtree.msgs);
|
||||
break;
|
||||
if(!prev->auto_hook)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}break;
|
||||
@@ -1739,239 +1817,166 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I
|
||||
}
|
||||
}break;
|
||||
|
||||
//- rjf: globals / procedures / types / constants
|
||||
case E_IdentifierResolutionPath_Globals:
|
||||
case E_IdentifierResolutionPath_Procedures:
|
||||
case E_IdentifierResolutionPath_ThreadLocals:
|
||||
case E_IdentifierResolutionPath_Constants:
|
||||
//- rjf: built-in constants
|
||||
case E_IdentifierResolutionPath_BuiltInConstants:
|
||||
{
|
||||
//- rjf: form namespaceified fallback versions of this lookup string
|
||||
if(!string_mapped)
|
||||
// rjf: "true"
|
||||
if(!string_mapped && str8_match(string, str8_lit("true"), 0))
|
||||
{
|
||||
E_Module *module = e_base_ctx->primary_module;
|
||||
RDI_Parsed *rdi = module->rdi;
|
||||
RDI_Procedure *procedure = e_cache->thread_ip_procedure;
|
||||
U64 name_size = 0;
|
||||
U8 *name_ptr = rdi_string_from_idx(rdi, procedure->name_string_idx, &name_size);
|
||||
String8 containing_procedure_name = str8(name_ptr, name_size);
|
||||
U64 last_past_scope_resolution_pos = 0;
|
||||
for(;;)
|
||||
{
|
||||
U64 past_next_dbl_colon_pos = str8_find_needle(containing_procedure_name, last_past_scope_resolution_pos, str8_lit("::"), 0)+2;
|
||||
U64 past_next_dot_pos = str8_find_needle(containing_procedure_name, last_past_scope_resolution_pos, str8_lit("."), 0)+1;
|
||||
U64 past_next_scope_resolution_pos = Min(past_next_dbl_colon_pos, past_next_dot_pos);
|
||||
if(past_next_scope_resolution_pos >= containing_procedure_name.size)
|
||||
{
|
||||
break;
|
||||
}
|
||||
String8 new_namespace_prefix_possibility = str8_prefix(containing_procedure_name, past_next_scope_resolution_pos);
|
||||
String8 namespaceified_string = push_str8f(scratch.arena, "%S%S", new_namespace_prefix_possibility, string);
|
||||
str8_list_push_front(scratch.arena, &namespaceified_strings, namespaceified_string);
|
||||
last_past_scope_resolution_pos = past_next_scope_resolution_pos;
|
||||
}
|
||||
string_mapped = 1;
|
||||
E_OpList oplist = {0};
|
||||
e_oplist_push_uconst(arena, &oplist, 1);
|
||||
mapped_type_key = e_type_key_basic(E_TypeKind_Bool);
|
||||
mapped_bytecode = e_bytecode_from_oplist(arena, &oplist);
|
||||
mapped_bytecode_mode = E_Mode_Value;
|
||||
}
|
||||
|
||||
//- rjf: try globals
|
||||
if(path == E_IdentifierResolutionPath_Globals && !string_mapped && (qualifier.size == 0 || str8_match(qualifier, str8_lit("global"), 0)))
|
||||
// rjf: "false"
|
||||
if(!string_mapped && str8_match(string, str8_lit("false"), 0))
|
||||
{
|
||||
for(U64 module_idx = 0; module_idx < e_base_ctx->modules_count; module_idx += 1)
|
||||
{
|
||||
E_Module *module = &e_base_ctx->modules[module_idx];
|
||||
RDI_Parsed *rdi = module->rdi;
|
||||
RDI_NameMap *name_map = rdi_element_from_name_idx(rdi, NameMaps, RDI_NameMapKind_GlobalVariables);
|
||||
RDI_ParsedNameMap parsed_name_map = {0};
|
||||
rdi_parsed_from_name_map(rdi, name_map, &parsed_name_map);
|
||||
RDI_NameMapNode *node = rdi_name_map_lookup(rdi, &parsed_name_map, string.str, string.size);
|
||||
U32 matches_count = 0;
|
||||
U32 *matches = rdi_matches_from_map_node(rdi, node, &matches_count);
|
||||
for(String8Node *n = namespaceified_strings.first;
|
||||
n != 0 && matches_count == 0;
|
||||
n = n->next)
|
||||
{
|
||||
node = rdi_name_map_lookup(rdi, &parsed_name_map, n->string.str, n->string.size);
|
||||
matches_count = 0;
|
||||
matches = rdi_matches_from_map_node(rdi, node, &matches_count);
|
||||
}
|
||||
if(matches_count != 0)
|
||||
{
|
||||
U32 match_idx = matches[matches_count-1];
|
||||
RDI_GlobalVariable *global_var = rdi_element_from_name_idx(rdi, GlobalVariables, match_idx);
|
||||
U32 type_idx = global_var->type_idx;
|
||||
RDI_TypeNode *type_node = rdi_element_from_name_idx(rdi, TypeNodes, type_idx);
|
||||
E_OpList oplist = {0};
|
||||
e_oplist_push_op(arena, &oplist, RDI_EvalOp_ConstU64, e_value_u64(module->vaddr_range.min + global_var->voff));
|
||||
string_mapped = 1;
|
||||
mapped_type_key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), type_idx, (U32)module_idx);
|
||||
mapped_bytecode = e_bytecode_from_oplist(arena, &oplist);
|
||||
mapped_bytecode_mode = E_Mode_Offset;
|
||||
mapped_bytecode_space = module->space;
|
||||
break;
|
||||
}
|
||||
}
|
||||
string_mapped = 1;
|
||||
E_OpList oplist = {0};
|
||||
e_oplist_push_uconst(arena, &oplist, 0);
|
||||
mapped_type_key = e_type_key_basic(E_TypeKind_Bool);
|
||||
mapped_bytecode = e_bytecode_from_oplist(arena, &oplist);
|
||||
mapped_bytecode_mode = E_Mode_Value;
|
||||
}
|
||||
|
||||
//- rjf: try thread-locals
|
||||
if(path == E_IdentifierResolutionPath_ThreadLocals && !string_mapped && (qualifier.size == 0 || str8_match(qualifier, str8_lit("thread_local"), 0)))
|
||||
}break;
|
||||
|
||||
//- rjf: built-in types
|
||||
case E_IdentifierResolutionPath_BuiltInTypes:
|
||||
{
|
||||
mapped_type_key = e_leaf_builtin_type_key_from_name(string);
|
||||
string_mapped = !e_type_key_match(mapped_type_key, e_type_key_zero());
|
||||
}break;
|
||||
|
||||
//- rjf: debug info matches
|
||||
case E_IdentifierResolutionPath_DebugInfoMatch:
|
||||
{
|
||||
if(!string_mapped && e_base_ctx->dbgi_match_store != 0 && (qualifier.size == 0 || str8_match(qualifier, str8_lit("symbol"), 0)))
|
||||
{
|
||||
for(U64 module_idx = 0; module_idx < e_base_ctx->modules_count; module_idx += 1)
|
||||
DI_Match match = di_match_from_name(e_base_ctx->dbgi_match_store, string, 0);
|
||||
if(match.idx == 0)
|
||||
{
|
||||
E_Module *module = &e_base_ctx->modules[module_idx];
|
||||
RDI_Parsed *rdi = module->rdi;
|
||||
RDI_NameMap *name_map = rdi_element_from_name_idx(rdi, NameMaps, RDI_NameMapKind_ThreadVariables);
|
||||
RDI_ParsedNameMap parsed_name_map = {0};
|
||||
rdi_parsed_from_name_map(rdi, name_map, &parsed_name_map);
|
||||
RDI_NameMapNode *node = rdi_name_map_lookup(rdi, &parsed_name_map, string.str, string.size);
|
||||
U32 matches_count = 0;
|
||||
U32 *matches = rdi_matches_from_map_node(rdi, node, &matches_count);
|
||||
for(String8Node *n = namespaceified_strings.first;
|
||||
n != 0 && matches_count == 0;
|
||||
n = n->next)
|
||||
String8List namespaceified_strings = {0};
|
||||
{
|
||||
node = rdi_name_map_lookup(rdi, &parsed_name_map, n->string.str, n->string.size);
|
||||
matches_count = 0;
|
||||
matches = rdi_matches_from_map_node(rdi, node, &matches_count);
|
||||
}
|
||||
if(matches_count != 0)
|
||||
{
|
||||
U32 match_idx = matches[matches_count-1];
|
||||
RDI_ThreadVariable *thread_var = rdi_element_from_name_idx(rdi, ThreadVariables, match_idx);
|
||||
U32 type_idx = thread_var->type_idx;
|
||||
RDI_TypeNode *type_node = rdi_element_from_name_idx(rdi, TypeNodes, type_idx);
|
||||
E_OpList oplist = {0};
|
||||
e_oplist_push_op(arena, &oplist, RDI_EvalOp_TLSOff, e_value_u64(thread_var->tls_off));
|
||||
string_mapped = 1;
|
||||
mapped_type_key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), type_idx, (U32)module_idx);
|
||||
mapped_bytecode = e_bytecode_from_oplist(arena, &oplist);
|
||||
mapped_bytecode_mode = E_Mode_Offset;
|
||||
mapped_bytecode_space = module->space;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: try constants
|
||||
if(path == E_IdentifierResolutionPath_Constants && !string_mapped && (qualifier.size == 0 || str8_match(qualifier, str8_lit("constant"), 0)))
|
||||
{
|
||||
if(str8_match(string, str8_lit("true"), 0))
|
||||
{
|
||||
string_mapped = 1;
|
||||
E_OpList oplist = {0};
|
||||
e_oplist_push_uconst(arena, &oplist, 1);
|
||||
mapped_type_key = e_type_key_basic(E_TypeKind_Bool);
|
||||
mapped_bytecode = e_bytecode_from_oplist(arena, &oplist);
|
||||
mapped_bytecode_mode = E_Mode_Value;
|
||||
}
|
||||
else if(str8_match(string, str8_lit("false"), 0))
|
||||
{
|
||||
string_mapped = 1;
|
||||
E_OpList oplist = {0};
|
||||
e_oplist_push_uconst(arena, &oplist, 0);
|
||||
mapped_type_key = e_type_key_basic(E_TypeKind_Bool);
|
||||
mapped_bytecode = e_bytecode_from_oplist(arena, &oplist);
|
||||
mapped_bytecode_mode = E_Mode_Value;
|
||||
}
|
||||
else for(U64 module_idx = 0; module_idx < e_base_ctx->modules_count; module_idx += 1)
|
||||
{
|
||||
E_Module *module = &e_base_ctx->modules[module_idx];
|
||||
RDI_Parsed *rdi = module->rdi;
|
||||
RDI_NameMap *name_map = rdi_element_from_name_idx(rdi, NameMaps, RDI_NameMapKind_Constants);
|
||||
RDI_ParsedNameMap parsed_name_map = {0};
|
||||
rdi_parsed_from_name_map(rdi, name_map, &parsed_name_map);
|
||||
RDI_NameMapNode *node = rdi_name_map_lookup(rdi, &parsed_name_map, string.str, string.size);
|
||||
U32 matches_count = 0;
|
||||
U32 *matches = rdi_matches_from_map_node(rdi, node, &matches_count);
|
||||
for(String8Node *n = namespaceified_strings.first;
|
||||
n != 0 && matches_count == 0;
|
||||
n = n->next)
|
||||
{
|
||||
node = rdi_name_map_lookup(rdi, &parsed_name_map, n->string.str, n->string.size);
|
||||
matches_count = 0;
|
||||
matches = rdi_matches_from_map_node(rdi, node, &matches_count);
|
||||
}
|
||||
if(matches_count != 0)
|
||||
{
|
||||
U32 match_idx = matches[matches_count-1];
|
||||
RDI_Constant *constant = rdi_element_from_name_idx(rdi, Constants, match_idx);
|
||||
U32 type_idx = constant->type_idx;
|
||||
RDI_TypeNode *type_node = rdi_element_from_name_idx(rdi, TypeNodes, type_idx);
|
||||
RDI_U32 constant_value_off = *rdi_element_from_name_idx(rdi, ConstantValueTable, constant->constant_value_idx);
|
||||
RDI_U32 constant_value_size = *rdi_element_from_name_idx(rdi, ConstantValueTable, constant->constant_value_idx+1) - constant_value_off;
|
||||
if(constant_value_size <= 8)
|
||||
E_Module *module = e_base_ctx->primary_module;
|
||||
RDI_Parsed *rdi = module->rdi;
|
||||
RDI_Procedure *procedure = e_cache->thread_ip_procedure;
|
||||
U64 name_size = 0;
|
||||
U8 *name_ptr = rdi_string_from_idx(rdi, procedure->name_string_idx, &name_size);
|
||||
String8 containing_procedure_name = str8(name_ptr, name_size);
|
||||
U64 last_past_scope_resolution_pos = 0;
|
||||
for(;;)
|
||||
{
|
||||
RDI_U64 constant_value_data_size = 0;
|
||||
RDI_U8 *constant_value_data = rdi_table_from_name(rdi, ConstantValueData, &constant_value_data_size);
|
||||
if(0 <= constant_value_off && constant_value_off + constant_value_size <= constant_value_data_size)
|
||||
U64 past_next_dbl_colon_pos = str8_find_needle(containing_procedure_name, last_past_scope_resolution_pos, str8_lit("::"), 0)+2;
|
||||
U64 past_next_dot_pos = str8_find_needle(containing_procedure_name, last_past_scope_resolution_pos, str8_lit("."), 0)+1;
|
||||
U64 past_next_scope_resolution_pos = Min(past_next_dbl_colon_pos, past_next_dot_pos);
|
||||
if(past_next_scope_resolution_pos >= containing_procedure_name.size)
|
||||
{
|
||||
RDI_U64 value = 0;
|
||||
MemoryCopy(&value, constant_value_data+constant_value_off, constant_value_size);
|
||||
E_OpList oplist = {0};
|
||||
e_oplist_push_op(arena, &oplist, RDI_EvalOp_ConstU64, e_value_u64(value));
|
||||
string_mapped = 1;
|
||||
mapped_type_key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), type_idx, (U32)module_idx);
|
||||
mapped_bytecode = e_bytecode_from_oplist(arena, &oplist);
|
||||
mapped_bytecode_mode = E_Mode_Value;
|
||||
mapped_bytecode_space = module->space;
|
||||
break;
|
||||
}
|
||||
String8 new_namespace_prefix_possibility = str8_prefix(containing_procedure_name, past_next_scope_resolution_pos);
|
||||
String8 namespaceified_string = push_str8f(scratch.arena, "%S%S", new_namespace_prefix_possibility, string);
|
||||
str8_list_push_front(scratch.arena, &namespaceified_strings, namespaceified_string);
|
||||
last_past_scope_resolution_pos = past_next_scope_resolution_pos;
|
||||
}
|
||||
}
|
||||
for(String8Node *n = namespaceified_strings.first; n != 0; n = n->next)
|
||||
{
|
||||
match = di_match_from_name(e_base_ctx->dbgi_match_store, n->string, 0);
|
||||
if(match.idx != 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: try procedures
|
||||
if(path == E_IdentifierResolutionPath_Procedures && !string_mapped && (qualifier.size == 0 || str8_match(qualifier, str8_lit("procedure"), 0)))
|
||||
{
|
||||
for(U64 module_idx = 0; module_idx < e_base_ctx->modules_count; module_idx += 1)
|
||||
if(match.idx != 0 && match.dbgi_idx < e_base_ctx->modules_count)
|
||||
{
|
||||
E_Module *module = &e_base_ctx->modules[module_idx];
|
||||
E_Module *module = &e_base_ctx->modules[match.dbgi_idx];
|
||||
RDI_Parsed *rdi = module->rdi;
|
||||
RDI_NameMap *name_map = rdi_element_from_name_idx(rdi, NameMaps, RDI_NameMapKind_Procedures);
|
||||
RDI_ParsedNameMap parsed_name_map = {0};
|
||||
rdi_parsed_from_name_map(rdi, name_map, &parsed_name_map);
|
||||
RDI_NameMapNode *node = rdi_name_map_lookup(rdi, &parsed_name_map, string.str, string.size);
|
||||
U32 matches_count = 0;
|
||||
U32 *matches = rdi_matches_from_map_node(rdi, node, &matches_count);
|
||||
for(String8Node *n = namespaceified_strings.first;
|
||||
n != 0 && matches_count == 0;
|
||||
n = n->next)
|
||||
switch(match.section)
|
||||
{
|
||||
node = rdi_name_map_lookup(rdi, &parsed_name_map, n->string.str, n->string.size);
|
||||
matches_count = 0;
|
||||
matches = rdi_matches_from_map_node(rdi, node, &matches_count);
|
||||
}
|
||||
if(matches_count != 0)
|
||||
{
|
||||
U32 match_idx = matches[matches_count-1];
|
||||
RDI_Procedure *procedure = rdi_element_from_name_idx(rdi, Procedures, match_idx);
|
||||
RDI_Scope *scope = rdi_element_from_name_idx(rdi, Scopes, procedure->root_scope_idx);
|
||||
U64 voff = *rdi_element_from_name_idx(rdi, ScopeVOffData, scope->voff_range_first);
|
||||
U32 type_idx = procedure->type_idx;
|
||||
RDI_TypeNode *type_node = rdi_element_from_name_idx(rdi, TypeNodes, type_idx);
|
||||
E_OpList oplist = {0};
|
||||
e_oplist_push_op(arena, &oplist, RDI_EvalOp_ConstU64, e_value_u64(module->vaddr_range.min + voff));
|
||||
string_mapped = 1;
|
||||
mapped_type_key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), type_idx, (U32)module_idx);
|
||||
mapped_bytecode = e_bytecode_from_oplist(arena, &oplist);
|
||||
mapped_bytecode_mode = E_Mode_Value;
|
||||
mapped_bytecode_space = module->space;
|
||||
break;
|
||||
default:{}break;
|
||||
case RDI_SectionKind_GlobalVariables:
|
||||
{
|
||||
RDI_GlobalVariable *global_var = rdi_element_from_name_idx(rdi, GlobalVariables, match.idx);
|
||||
U32 type_idx = global_var->type_idx;
|
||||
RDI_TypeNode *type_node = rdi_element_from_name_idx(rdi, TypeNodes, type_idx);
|
||||
E_OpList oplist = {0};
|
||||
e_oplist_push_op(arena, &oplist, RDI_EvalOp_ConstU64, e_value_u64(module->vaddr_range.min + global_var->voff));
|
||||
string_mapped = 1;
|
||||
mapped_type_key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), type_idx, (U32)match.dbgi_idx);
|
||||
mapped_bytecode = e_bytecode_from_oplist(arena, &oplist);
|
||||
mapped_bytecode_mode = E_Mode_Offset;
|
||||
mapped_bytecode_space = module->space;
|
||||
}break;
|
||||
case RDI_SectionKind_ThreadVariables:
|
||||
{
|
||||
RDI_ThreadVariable *thread_var = rdi_element_from_name_idx(rdi, ThreadVariables, match.idx);
|
||||
U32 type_idx = thread_var->type_idx;
|
||||
RDI_TypeNode *type_node = rdi_element_from_name_idx(rdi, TypeNodes, type_idx);
|
||||
E_OpList oplist = {0};
|
||||
e_oplist_push_op(arena, &oplist, RDI_EvalOp_TLSOff, e_value_u64(thread_var->tls_off));
|
||||
string_mapped = 1;
|
||||
mapped_type_key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), type_idx, (U32)match.dbgi_idx);
|
||||
mapped_bytecode = e_bytecode_from_oplist(arena, &oplist);
|
||||
mapped_bytecode_mode = E_Mode_Offset;
|
||||
mapped_bytecode_space = module->space;
|
||||
}break;
|
||||
case RDI_SectionKind_Constants:
|
||||
{
|
||||
RDI_Constant *constant = rdi_element_from_name_idx(rdi, Constants, match.idx);
|
||||
U32 type_idx = constant->type_idx;
|
||||
RDI_TypeNode *type_node = rdi_element_from_name_idx(rdi, TypeNodes, type_idx);
|
||||
RDI_U32 constant_value_off = *rdi_element_from_name_idx(rdi, ConstantValueTable, constant->constant_value_idx);
|
||||
RDI_U32 constant_value_size = *rdi_element_from_name_idx(rdi, ConstantValueTable, constant->constant_value_idx+1) - constant_value_off;
|
||||
if(constant_value_size <= 8)
|
||||
{
|
||||
RDI_U64 constant_value_data_size = 0;
|
||||
RDI_U8 *constant_value_data = rdi_table_from_name(rdi, ConstantValueData, &constant_value_data_size);
|
||||
if(0 <= constant_value_off && constant_value_off + constant_value_size <= constant_value_data_size)
|
||||
{
|
||||
RDI_U64 value = 0;
|
||||
MemoryCopy(&value, constant_value_data+constant_value_off, constant_value_size);
|
||||
E_OpList oplist = {0};
|
||||
e_oplist_push_op(arena, &oplist, RDI_EvalOp_ConstU64, e_value_u64(value));
|
||||
string_mapped = 1;
|
||||
mapped_type_key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), type_idx, (U32)match.dbgi_idx);
|
||||
mapped_bytecode = e_bytecode_from_oplist(arena, &oplist);
|
||||
mapped_bytecode_mode = E_Mode_Value;
|
||||
mapped_bytecode_space = module->space;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}break;
|
||||
case RDI_SectionKind_Procedures:
|
||||
{
|
||||
RDI_Procedure *procedure = rdi_element_from_name_idx(rdi, Procedures, match.idx);
|
||||
RDI_Scope *scope = rdi_element_from_name_idx(rdi, Scopes, procedure->root_scope_idx);
|
||||
U64 voff = *rdi_element_from_name_idx(rdi, ScopeVOffData, scope->voff_range_first);
|
||||
U32 type_idx = procedure->type_idx;
|
||||
RDI_TypeNode *type_node = rdi_element_from_name_idx(rdi, TypeNodes, type_idx);
|
||||
E_OpList oplist = {0};
|
||||
e_oplist_push_op(arena, &oplist, RDI_EvalOp_ConstU64, e_value_u64(module->vaddr_range.min + voff));
|
||||
string_mapped = 1;
|
||||
mapped_type_key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), type_idx, (U32)match.dbgi_idx);
|
||||
mapped_bytecode = e_bytecode_from_oplist(arena, &oplist);
|
||||
mapped_bytecode_mode = E_Mode_Value;
|
||||
mapped_bytecode_space = module->space;
|
||||
}break;
|
||||
case RDI_SectionKind_TypeNodes:
|
||||
{
|
||||
U32 type_idx = match.idx;
|
||||
RDI_TypeNode *type_node = rdi_element_from_name_idx(rdi, TypeNodes, type_idx);
|
||||
mapped_type_key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), type_idx, (U32)match.dbgi_idx);
|
||||
string_mapped = 1;
|
||||
}break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}break;
|
||||
|
||||
//- rjf: try types
|
||||
case E_IdentifierResolutionPath_Types:
|
||||
if(!string_mapped && (qualifier.size == 0 || str8_match(qualifier, str8_lit("type"), 0)))
|
||||
{
|
||||
mapped_type_key = e_leaf_type_from_name(string);
|
||||
if(!e_type_key_match(e_type_key_zero(), mapped_type_key))
|
||||
{
|
||||
string_mapped = 1;
|
||||
}
|
||||
}break;
|
||||
|
||||
|
||||
//- rjf: try registers
|
||||
case E_IdentifierResolutionPath_Registers:
|
||||
if(!string_mapped && (qualifier.size == 0 || str8_match(qualifier, str8_lit("reg"), 0)))
|
||||
|
||||
+9
-15
@@ -14,11 +14,9 @@ typedef enum E_IdentifierResolutionPath
|
||||
E_IdentifierResolutionPath_ParentExprMember,
|
||||
E_IdentifierResolutionPath_ImplicitThisMember,
|
||||
E_IdentifierResolutionPath_Local,
|
||||
E_IdentifierResolutionPath_Globals,
|
||||
E_IdentifierResolutionPath_ThreadLocals,
|
||||
E_IdentifierResolutionPath_Constants,
|
||||
E_IdentifierResolutionPath_Procedures,
|
||||
E_IdentifierResolutionPath_Types,
|
||||
E_IdentifierResolutionPath_DebugInfoMatch,
|
||||
E_IdentifierResolutionPath_BuiltInConstants,
|
||||
E_IdentifierResolutionPath_BuiltInTypes,
|
||||
E_IdentifierResolutionPath_Registers,
|
||||
E_IdentifierResolutionPath_RegisterAliases,
|
||||
E_IdentifierResolutionPath_Macros,
|
||||
@@ -87,11 +85,9 @@ E_IdentifierResolutionPath e_default_identifier_resolution_paths[] =
|
||||
E_IdentifierResolutionPath_ParentExprMember,
|
||||
E_IdentifierResolutionPath_ImplicitThisMember,
|
||||
E_IdentifierResolutionPath_Local,
|
||||
E_IdentifierResolutionPath_Globals,
|
||||
E_IdentifierResolutionPath_ThreadLocals,
|
||||
E_IdentifierResolutionPath_Constants,
|
||||
E_IdentifierResolutionPath_Procedures,
|
||||
E_IdentifierResolutionPath_Types,
|
||||
E_IdentifierResolutionPath_BuiltInConstants,
|
||||
E_IdentifierResolutionPath_BuiltInTypes,
|
||||
E_IdentifierResolutionPath_DebugInfoMatch,
|
||||
E_IdentifierResolutionPath_Registers,
|
||||
E_IdentifierResolutionPath_RegisterAliases,
|
||||
E_IdentifierResolutionPath_Macros,
|
||||
@@ -110,11 +106,9 @@ E_IdentifierResolutionPath e_callable_identifier_resolution_paths[] =
|
||||
E_IdentifierResolutionPath_ParentExprMember,
|
||||
E_IdentifierResolutionPath_ImplicitThisMember,
|
||||
E_IdentifierResolutionPath_Local,
|
||||
E_IdentifierResolutionPath_Globals,
|
||||
E_IdentifierResolutionPath_ThreadLocals,
|
||||
E_IdentifierResolutionPath_Constants,
|
||||
E_IdentifierResolutionPath_Procedures,
|
||||
E_IdentifierResolutionPath_Types,
|
||||
E_IdentifierResolutionPath_BuiltInConstants,
|
||||
E_IdentifierResolutionPath_BuiltInTypes,
|
||||
E_IdentifierResolutionPath_DebugInfoMatch,
|
||||
E_IdentifierResolutionPath_Registers,
|
||||
E_IdentifierResolutionPath_RegisterAliases,
|
||||
};
|
||||
|
||||
+81
-145
@@ -526,152 +526,73 @@ e_string_from_expr(Arena *arena, E_Expr *expr, String8 parent_expr_string)
|
||||
//~ rjf: Parsing Functions
|
||||
|
||||
internal E_TypeKey
|
||||
e_leaf_type_from_name(String8 name)
|
||||
e_leaf_builtin_type_key_from_name(String8 name)
|
||||
{
|
||||
E_TypeKey key = zero_struct;
|
||||
B32 found = 0;
|
||||
if(!found)
|
||||
E_TypeKey result = {0};
|
||||
if(0){}
|
||||
#define BuiltInType_XList \
|
||||
BasicCase("uint8", U8)\
|
||||
BasicCase("uint8_t", U8)\
|
||||
BasicCase("uchar", UChar8)\
|
||||
BasicCase("uchar8", UChar8)\
|
||||
BasicCase("uint16", U16)\
|
||||
BasicCase("uint16_t", U16)\
|
||||
BasicCase("uchar16", UChar16)\
|
||||
BasicCase("uint32", U32)\
|
||||
BasicCase("uint32_t", U32)\
|
||||
BasicCase("uchar32", UChar32)\
|
||||
BasicCase("uint64", U64)\
|
||||
BasicCase("uint64_t", U64)\
|
||||
BasicCase("uint128", U128)\
|
||||
BasicCase("uint128_t", U128)\
|
||||
BasicCase("uint256", U256)\
|
||||
BasicCase("uint256_t", U256)\
|
||||
BasicCase("uint512", U512)\
|
||||
BasicCase("uint512_t", U512)\
|
||||
BasicCase("int8", S8)\
|
||||
BasicCase("int8_t", S8)\
|
||||
BasicCase("char", Char8)\
|
||||
BasicCase("char8", Char8)\
|
||||
BasicCase("int16", S16)\
|
||||
BasicCase("int16_t", S16)\
|
||||
BasicCase("char16", Char16)\
|
||||
BasicCase("int32", S32)\
|
||||
BasicCase("int32_t", S32)\
|
||||
BasicCase("char32", Char32)\
|
||||
BasicCase("int64", S64)\
|
||||
BasicCase("int64_t", S64)\
|
||||
BasicCase("int128", S128)\
|
||||
BasicCase("int128_t", S128)\
|
||||
BasicCase("int256", S256)\
|
||||
BasicCase("int256_t", S256)\
|
||||
BasicCase("int512", S512)\
|
||||
BasicCase("int512_t", S512)\
|
||||
BasicCase("void", Void)\
|
||||
BasicCase("bool", Bool)\
|
||||
BasicCase("float", F32)\
|
||||
BasicCase("float32", F32)\
|
||||
BasicCase("double", F64)\
|
||||
BasicCase("float64", F64)
|
||||
#define BasicCase(str, kind) else if(str8_match(name, str8_lit(str), 0)) {result = e_type_key_basic(E_TypeKind_##kind);}
|
||||
BuiltInType_XList
|
||||
#undef BasicCase
|
||||
return result;
|
||||
}
|
||||
|
||||
internal E_TypeKey
|
||||
e_leaf_type_key_from_name(String8 name)
|
||||
{
|
||||
E_TypeKey key = e_leaf_builtin_type_key_from_name(name);
|
||||
if(!e_type_key_match(e_type_key_zero(), key))
|
||||
{
|
||||
#define Case(str) (str8_match(name, str8_lit(str), 0))
|
||||
if(0){}
|
||||
else if(Case("uint8") || Case("uint8_t"))
|
||||
DI_Match match = di_match_from_name(e_base_ctx->dbgi_match_store, name, 0);
|
||||
if(match.section == RDI_SectionKind_TypeNodes)
|
||||
{
|
||||
found = 1;
|
||||
key = e_type_key_basic(E_TypeKind_U8);
|
||||
}
|
||||
else if(Case("uchar8") || Case("uchar"))
|
||||
{
|
||||
found = 1;
|
||||
key = e_type_key_basic(E_TypeKind_UChar8);
|
||||
}
|
||||
else if(Case("uint16") || Case("uint16_t"))
|
||||
{
|
||||
found = 1;
|
||||
key = e_type_key_basic(E_TypeKind_U16);
|
||||
}
|
||||
else if(Case("uchar16"))
|
||||
{
|
||||
found = 1;
|
||||
key = e_type_key_basic(E_TypeKind_UChar16);
|
||||
}
|
||||
else if(Case("uint32") || Case("uint32_t"))
|
||||
{
|
||||
found = 1;
|
||||
key = e_type_key_basic(E_TypeKind_U32);
|
||||
}
|
||||
else if(Case("uchar32"))
|
||||
{
|
||||
found = 1;
|
||||
key = e_type_key_basic(E_TypeKind_UChar32);
|
||||
}
|
||||
else if(Case("uint64") || Case("uint64_t"))
|
||||
{
|
||||
found = 1;
|
||||
key = e_type_key_basic(E_TypeKind_U64);
|
||||
}
|
||||
else if(Case("uint128") || Case("uint128_t"))
|
||||
{
|
||||
found = 1;
|
||||
key = e_type_key_basic(E_TypeKind_U128);
|
||||
}
|
||||
else if(Case("uint256") || Case("uint256_t"))
|
||||
{
|
||||
found = 1;
|
||||
key = e_type_key_basic(E_TypeKind_U256);
|
||||
}
|
||||
else if(Case("uint512") || Case("uint512_t"))
|
||||
{
|
||||
found = 1;
|
||||
key = e_type_key_basic(E_TypeKind_U512);
|
||||
}
|
||||
else if(Case("s8") || Case("b8") || Case("B8") || Case("i8") || Case("int8") || Case("int8_t"))
|
||||
{
|
||||
found = 1;
|
||||
key = e_type_key_basic(E_TypeKind_S8);
|
||||
}
|
||||
else if(Case("char8") || Case("char"))
|
||||
{
|
||||
found = 1;
|
||||
key = e_type_key_basic(E_TypeKind_Char8);
|
||||
}
|
||||
else if(Case("int16") || Case("int16_t"))
|
||||
{
|
||||
found = 1;
|
||||
key = e_type_key_basic(E_TypeKind_S16);
|
||||
}
|
||||
else if(Case("char16"))
|
||||
{
|
||||
found = 1;
|
||||
key = e_type_key_basic(E_TypeKind_Char16);
|
||||
}
|
||||
else if(Case("int32") || Case("int32_t") || Case("char32"))
|
||||
{
|
||||
found = 1;
|
||||
key = e_type_key_basic(E_TypeKind_S32);
|
||||
}
|
||||
else if(Case("char32"))
|
||||
{
|
||||
found = 1;
|
||||
key = e_type_key_basic(E_TypeKind_Char32);
|
||||
}
|
||||
else if(Case("int64") || Case("int64_t"))
|
||||
{
|
||||
found = 1;
|
||||
key = e_type_key_basic(E_TypeKind_S64);
|
||||
}
|
||||
else if(Case("int256") || Case("int256_t"))
|
||||
{
|
||||
found = 1;
|
||||
key = e_type_key_basic(E_TypeKind_S256);
|
||||
}
|
||||
else if(Case("int512") || Case("int512_t"))
|
||||
{
|
||||
found = 1;
|
||||
key = e_type_key_basic(E_TypeKind_S512);
|
||||
}
|
||||
else if(Case("void"))
|
||||
{
|
||||
found = 1;
|
||||
key = e_type_key_basic(E_TypeKind_Void);
|
||||
}
|
||||
else if(Case("bool"))
|
||||
{
|
||||
found = 1;
|
||||
key = e_type_key_basic(E_TypeKind_Bool);
|
||||
}
|
||||
else if(Case("float") || Case("float32"))
|
||||
{
|
||||
found = 1;
|
||||
key = e_type_key_basic(E_TypeKind_F32);
|
||||
}
|
||||
else if(Case("double") || Case("float64"))
|
||||
{
|
||||
found = 1;
|
||||
key = e_type_key_basic(E_TypeKind_F64);
|
||||
}
|
||||
#undef Case
|
||||
}
|
||||
if(!found)
|
||||
{
|
||||
for(U64 module_idx = 0; module_idx < e_base_ctx->modules_count; module_idx += 1)
|
||||
{
|
||||
RDI_Parsed *rdi = e_base_ctx->modules[module_idx].rdi;
|
||||
RDI_NameMap *name_map = rdi_element_from_name_idx(rdi, NameMaps, RDI_NameMapKind_Types);
|
||||
RDI_ParsedNameMap parsed_name_map = {0};
|
||||
rdi_parsed_from_name_map(rdi, name_map, &parsed_name_map);
|
||||
RDI_NameMapNode *node = rdi_name_map_lookup(rdi, &parsed_name_map, name.str, name.size);
|
||||
if(node != 0)
|
||||
{
|
||||
U32 match_count = 0;
|
||||
U32 *matches = rdi_matches_from_map_node(rdi, node, &match_count);
|
||||
if(match_count != 0)
|
||||
{
|
||||
RDI_TypeNode *type_node = rdi_element_from_name_idx(rdi, TypeNodes, matches[0]);
|
||||
found = (type_node->kind != RDI_TypeKind_NULL);
|
||||
key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), matches[0], module_idx);
|
||||
break;
|
||||
}
|
||||
}
|
||||
E_Module *module = &e_base_ctx->modules[match.dbgi_idx];
|
||||
RDI_Parsed *rdi = module->rdi;
|
||||
U32 type_idx = match.idx;
|
||||
RDI_TypeNode *type_node = rdi_element_from_name_idx(rdi, TypeNodes, type_idx);
|
||||
key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), type_idx, (U32)match.dbgi_idx);
|
||||
}
|
||||
}
|
||||
return key;
|
||||
@@ -688,7 +609,7 @@ e_type_key_from_expr(E_Expr *expr)
|
||||
default:{}break;
|
||||
case E_ExprKind_LeafIdentifier:
|
||||
{
|
||||
result = e_leaf_type_from_name(expr->string);
|
||||
result = e_leaf_type_key_from_name(expr->string);
|
||||
}break;
|
||||
case E_ExprKind_TypeIdent:
|
||||
{
|
||||
@@ -742,7 +663,7 @@ e_push_type_parse_from_text_tokens(Arena *arena, String8 text, E_TokenArray toke
|
||||
{
|
||||
token_string = str8_substr(token_string, r1u64(1, token_string.size-1));
|
||||
}
|
||||
E_TypeKey type_key = e_leaf_type_from_name(token_string);
|
||||
E_TypeKey type_key = e_leaf_type_key_from_name(token_string);
|
||||
if(!e_type_key_match(e_type_key_zero(), type_key))
|
||||
{
|
||||
token_it += 1;
|
||||
@@ -1080,6 +1001,21 @@ e_push_parse_from_string_tokens__prec(Arena *arena, String8 text, E_TokenArray t
|
||||
{
|
||||
E_Token token = e_token_at_it(it, &tokens);
|
||||
String8 token_string = str8_substr(text, token.range);
|
||||
|
||||
// rjf: skip no-op prefix keywords
|
||||
if(token.kind == E_TokenKind_Identifier &&
|
||||
(str8_match(token_string, str8_lit("struct"), 0) ||
|
||||
str8_match(token_string, str8_lit("union"), 0) ||
|
||||
str8_match(token_string, str8_lit("enum"), 0) ||
|
||||
str8_match(token_string, str8_lit("class"), 0) ||
|
||||
str8_match(token_string, str8_lit("typename"), 0)))
|
||||
{
|
||||
it += 1;
|
||||
token = e_token_at_it(it, &tokens);
|
||||
token_string = str8_substr(text, token.range);
|
||||
}
|
||||
|
||||
// rjf: build identifier atom
|
||||
if(token.kind == E_TokenKind_Identifier)
|
||||
{
|
||||
String8 identifier_string = token_string;
|
||||
|
||||
@@ -34,7 +34,8 @@ internal String8 e_string_from_expr(Arena *arena, E_Expr *expr, String8 parent_e
|
||||
////////////////////////////////
|
||||
//~ rjf: Parsing Functions
|
||||
|
||||
internal E_TypeKey e_leaf_type_from_name(String8 name);
|
||||
internal E_TypeKey e_leaf_builtin_type_key_from_name(String8 name);
|
||||
internal E_TypeKey e_leaf_type_key_from_name(String8 name);
|
||||
internal E_TypeKey e_type_key_from_expr(E_Expr *expr);
|
||||
internal E_Parse e_push_type_parse_from_text_tokens(Arena *arena, String8 text, E_TokenArray tokens);
|
||||
internal E_Parse e_push_parse_from_string_tokens__prec(Arena *arena, String8 text, E_TokenArray tokens, S64 max_precedence, U64 max_chain_count);
|
||||
|
||||
@@ -927,7 +927,7 @@ e_push_type_from_key(Arena *arena, E_TypeKey key)
|
||||
type->byte_size = bit_size_from_arch(e_base_ctx->modules[rdi_idx].arch)/8;
|
||||
type->direct_type_key = direct_type_key;
|
||||
type->count = count;
|
||||
type->param_type_keys = push_array_no_zero(arena, E_TypeKey, type->count);
|
||||
type->param_type_keys = push_array(arena, E_TypeKey, type->count);
|
||||
type->arch = e_base_ctx->modules[rdi_idx].arch;
|
||||
for(U32 idx = 0; idx < type->count; idx += 1)
|
||||
{
|
||||
@@ -1509,6 +1509,7 @@ e_type_key_unwrap(E_TypeKey key, E_TypeUnwrapFlags flags)
|
||||
case E_TypeKind_MetaExpr: {done = !(flags & E_TypeUnwrapFlag_Meta);}break;
|
||||
case E_TypeKind_Enum: {done = !(flags & E_TypeUnwrapFlag_Enums);}break;
|
||||
case E_TypeKind_Alias: {done = !(flags & E_TypeUnwrapFlag_Aliases);}break;
|
||||
case E_TypeKind_Bitfield: {done = !(flags & E_TypeUnwrapFlag_Bitfields);}break;
|
||||
case E_TypeKind_Array:
|
||||
case E_TypeKind_Ptr:
|
||||
case E_TypeKind_RRef:
|
||||
@@ -2541,7 +2542,7 @@ E_TYPE_EXPAND_INFO_FUNCTION_DEF(array)
|
||||
{
|
||||
E_Type *type = e_type_from_key(eval.irtree.type_key);
|
||||
U64 count = 1;
|
||||
if(type->args != 0 && type->count > 0) E_ParentKey(e_key_match(e_key_zero(), eval.parent_key) ? eval.key : eval.parent_key)
|
||||
if(type->args != 0 && type->count > 0) E_ParentKey(eval.key)
|
||||
{
|
||||
E_Key count_key = e_key_from_expr(type->args[0]);
|
||||
E_Value count_value = e_value_from_key(count_key);
|
||||
|
||||
@@ -16,8 +16,9 @@ enum
|
||||
E_TypeUnwrapFlag_Meta = (1<<3),
|
||||
E_TypeUnwrapFlag_Enums = (1<<4),
|
||||
E_TypeUnwrapFlag_Aliases = (1<<5),
|
||||
E_TypeUnwrapFlag_Bitfields = (1<<6),
|
||||
E_TypeUnwrapFlag_All = 0xffffffff,
|
||||
E_TypeUnwrapFlag_AllDecorative = (E_TypeUnwrapFlag_All & ~E_TypeUnwrapFlag_Pointers)
|
||||
E_TypeUnwrapFlag_AllDecorative = (E_TypeUnwrapFlag_All & ~(E_TypeUnwrapFlag_Pointers|E_TypeUnwrapFlag_Bitfields))
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
@@ -144,7 +144,7 @@ U8 e_type_kind_basic_byte_size_table[61] =
|
||||
0,
|
||||
};
|
||||
|
||||
String8 e_expr_kind_strings[49] =
|
||||
String8 e_expr_kind_strings[50] =
|
||||
{
|
||||
str8_lit_comp("Nil"),
|
||||
str8_lit_comp("Ref"),
|
||||
@@ -155,6 +155,7 @@ str8_lit_comp("Address"),
|
||||
str8_lit_comp("Cast"),
|
||||
str8_lit_comp("Sizeof"),
|
||||
str8_lit_comp("Typeof"),
|
||||
str8_lit_comp("Symbolof"),
|
||||
str8_lit_comp("ByteSwap"),
|
||||
str8_lit_comp("Pos"),
|
||||
str8_lit_comp("Neg"),
|
||||
@@ -197,7 +198,7 @@ str8_lit_comp("Unsigned"),
|
||||
str8_lit_comp("Define"),
|
||||
};
|
||||
|
||||
E_OpInfo e_expr_kind_op_info_table[49] =
|
||||
E_OpInfo e_expr_kind_op_info_table[50] =
|
||||
{
|
||||
{ E_OpKind_Null, 0, str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("") },
|
||||
{ E_OpKind_Null, 0, str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("") },
|
||||
@@ -208,6 +209,7 @@ E_OpInfo e_expr_kind_op_info_table[49] =
|
||||
{ E_OpKind_Null, 1, str8_lit_comp("cast("), str8_lit_comp(")"), str8_lit_comp(""), str8_lit_comp("") },
|
||||
{ E_OpKind_UnaryPrefix, 1, str8_lit_comp("sizeof "), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("") },
|
||||
{ E_OpKind_UnaryPrefix, 1, str8_lit_comp("typeof "), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("") },
|
||||
{ E_OpKind_UnaryPrefix, 1, str8_lit_comp("symbolof "), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("") },
|
||||
{ E_OpKind_UnaryPrefix, 1, str8_lit_comp("bswap "), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("") },
|
||||
{ E_OpKind_UnaryPrefix, 2, str8_lit_comp("+"), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("") },
|
||||
{ E_OpKind_UnaryPrefix, 2, str8_lit_comp("-"), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("") },
|
||||
|
||||
@@ -107,6 +107,7 @@ E_ExprKind_Address,
|
||||
E_ExprKind_Cast,
|
||||
E_ExprKind_Sizeof,
|
||||
E_ExprKind_Typeof,
|
||||
E_ExprKind_Symbolof,
|
||||
E_ExprKind_ByteSwap,
|
||||
E_ExprKind_Pos,
|
||||
E_ExprKind_Neg,
|
||||
@@ -170,8 +171,8 @@ C_LINKAGE_BEGIN
|
||||
extern String8 e_token_kind_strings[6];
|
||||
extern String8 e_type_kind_basic_string_table[61];
|
||||
extern U8 e_type_kind_basic_byte_size_table[61];
|
||||
extern String8 e_expr_kind_strings[49];
|
||||
extern E_OpInfo e_expr_kind_op_info_table[49];
|
||||
extern String8 e_expr_kind_strings[50];
|
||||
extern E_OpInfo e_expr_kind_op_info_table[50];
|
||||
extern String8 e_interpretation_code_display_strings[11];
|
||||
|
||||
C_LINKAGE_END
|
||||
|
||||
@@ -528,6 +528,18 @@ ev_block_tree_from_eval(Arena *arena, EV_View *view, String8 filter, E_Eval root
|
||||
// rjf: unpack eval
|
||||
E_Mode mode = t->eval.irtree.mode;
|
||||
E_Eval eval = t->eval;
|
||||
|
||||
// rjf: pointers/reference evaluations -> dereference for expansion
|
||||
{
|
||||
E_TypeKey type_key = e_type_key_unwrap(eval.irtree.type_key, E_TypeUnwrapFlag_Modifiers|E_TypeUnwrapFlag_Meta);
|
||||
E_TypeKind type_kind = e_type_kind_from_key(type_key);
|
||||
if(e_type_kind_is_pointer_or_ref(type_kind))
|
||||
{
|
||||
eval = e_eval_wrapf(eval, "*($)");
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: unpack type key we'll use for expanding this eval
|
||||
E_TypeKey expansion_type_key = ev_expansion_type_from_key(eval.irtree.type_key);
|
||||
if(!e_type_key_match(expansion_type_key, e_type_key_zero()))
|
||||
{
|
||||
@@ -1292,6 +1304,8 @@ ev_string_from_simple_typed_eval(Arena *arena, EV_StringParams *params, E_Eval e
|
||||
{
|
||||
digit_group_separator = 0;
|
||||
}
|
||||
S64 s64 = 0;
|
||||
U64 u64 = 0;
|
||||
F64 f64 = 0;
|
||||
switch(type_kind)
|
||||
{
|
||||
@@ -1366,20 +1380,22 @@ ev_string_from_simple_typed_eval(Arena *arena, EV_StringParams *params, E_Eval e
|
||||
}
|
||||
}break;
|
||||
|
||||
case E_TypeKind_S8:
|
||||
case E_TypeKind_S16:
|
||||
case E_TypeKind_S32:
|
||||
case E_TypeKind_S64:
|
||||
case E_TypeKind_S8: s64 = (S64)eval.value.s8; goto sint_path;
|
||||
case E_TypeKind_S16: s64 = (S64)eval.value.s16; goto sint_path;
|
||||
case E_TypeKind_S32: s64 = (S64)eval.value.s32; goto sint_path;
|
||||
case E_TypeKind_S64: s64 = (S64)eval.value.s64; goto sint_path;
|
||||
sint_path:;
|
||||
{
|
||||
result = str8_from_s64(arena, eval.value.s64, params->radix, params->min_digits, digit_group_separator);
|
||||
result = str8_from_s64(arena, s64, params->radix, params->min_digits, digit_group_separator);
|
||||
}break;
|
||||
|
||||
case E_TypeKind_U8:
|
||||
case E_TypeKind_U16:
|
||||
case E_TypeKind_U32:
|
||||
case E_TypeKind_U64:
|
||||
case E_TypeKind_U8: u64 = (U64)eval.value.u8; goto uint_path;
|
||||
case E_TypeKind_U16: u64 = (U64)eval.value.u16; goto uint_path;
|
||||
case E_TypeKind_U32: u64 = (U64)eval.value.u32; goto uint_path;
|
||||
case E_TypeKind_U64: u64 = (U64)eval.value.u64; goto uint_path;
|
||||
uint_path:;
|
||||
{
|
||||
result = str8_from_u64(arena, eval.value.u64, params->radix, params->min_digits, digit_group_separator);
|
||||
result = str8_from_u64(arena, u64, params->radix, params->min_digits, digit_group_separator);
|
||||
}break;
|
||||
|
||||
case E_TypeKind_U128:
|
||||
@@ -1776,6 +1792,7 @@ ev_string_iter_next(Arena *arena, EV_StringIter *it, String8 *out_string)
|
||||
B32 ptee_has_content;
|
||||
B32 ptee_has_string;
|
||||
B32 did_prefix_content;
|
||||
B32 did_prefix_string;
|
||||
B32 did_redirect;
|
||||
};
|
||||
EV_StringPtrData *ptr_data = it->top_task->user_data;
|
||||
@@ -1849,6 +1866,10 @@ ev_string_iter_next(Arena *arena, EV_StringIter *it, String8 *out_string)
|
||||
{
|
||||
string = str8_prefix(string, params->limit_strings_size);
|
||||
}
|
||||
else if(type_kind == E_TypeKind_Array && ptr_data->type->count != 0)
|
||||
{
|
||||
string = str8_prefix(string, ptr_data->type->count);
|
||||
}
|
||||
|
||||
// rjf: escape and quote
|
||||
B32 string__is_escaped_and_quoted = (!(params->flags & EV_StringFlag_DisableStringQuotes) || depth > 0);
|
||||
@@ -1862,6 +1883,7 @@ ev_string_iter_next(Arena *arena, EV_StringIter *it, String8 *out_string)
|
||||
// rjf: report
|
||||
*out_string = push_str8_copy(arena, string__escaped_and_quoted);
|
||||
ptr_data->did_prefix_content = 1;
|
||||
ptr_data->did_prefix_string = 1;
|
||||
|
||||
scratch_end(scratch);
|
||||
}
|
||||
@@ -1929,7 +1951,8 @@ ev_string_iter_next(Arena *arena, EV_StringIter *it, String8 *out_string)
|
||||
}
|
||||
if(inline_site != 0)
|
||||
{
|
||||
E_TypeKey type = e_type_key_ext(E_TypeKind_Function, inline_site->type_idx, module_idx);
|
||||
RDI_TypeNode *type_node = rdi_element_from_name_idx(rdi, TypeNodes, inline_site->type_idx);
|
||||
E_TypeKey type = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), inline_site->type_idx, module_idx);
|
||||
String8 name = {0};
|
||||
name.str = rdi_string_from_idx(rdi, inline_site->name_string_idx, &name.size);
|
||||
if(inline_site->type_idx != 0)
|
||||
@@ -1958,7 +1981,8 @@ ev_string_iter_next(Arena *arena, EV_StringIter *it, String8 *out_string)
|
||||
RDI_Scope *scope = rdi_element_from_name_idx(rdi, Scopes, scope_idx);
|
||||
U64 proc_idx = scope->proc_idx;
|
||||
RDI_Procedure *procedure = rdi_element_from_name_idx(rdi, Procedures, proc_idx);
|
||||
E_TypeKey type = e_type_key_ext(E_TypeKind_Function, procedure->type_idx, module_idx);
|
||||
RDI_TypeNode *type_node = rdi_element_from_name_idx(rdi, TypeNodes, procedure->type_idx);
|
||||
E_TypeKey type = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), procedure->type_idx, module_idx);
|
||||
String8 name = {0};
|
||||
name.str = rdi_string_from_idx(rdi, procedure->name_string_idx, &name.size);
|
||||
if(procedure->type_idx != 0)
|
||||
@@ -2043,7 +2067,9 @@ ev_string_iter_next(Arena *arena, EV_StringIter *it, String8 *out_string)
|
||||
//
|
||||
|
||||
// rjf: [read only] if we did prefix content, do a parenthesized pointer value
|
||||
if(!(params->flags & EV_StringFlag_DisableAddresses) && params->flags & EV_StringFlag_ReadOnlyDisplayRules && ptr_data->did_prefix_content)
|
||||
if(!(params->flags & EV_StringFlag_DisableAddresses) && params->flags & EV_StringFlag_ReadOnlyDisplayRules &&
|
||||
ptr_data->did_prefix_content &&
|
||||
(!ptr_data->did_prefix_string || ptr_data->value_eval.value.u64 == 0))
|
||||
{
|
||||
*out_string = push_str8f(arena, " (%S)", ptr_value_string);
|
||||
}
|
||||
|
||||
@@ -68,9 +68,9 @@ fp_metrics_from_font(FP_Handle handle)
|
||||
FP_Metrics result = {0};
|
||||
if(font.face != 0)
|
||||
{
|
||||
result.design_units_per_em = (F32)(font.face->units_per_EM * 72.f/96.f);
|
||||
result.design_units_per_em = (F32)(font.face->units_per_EM);
|
||||
result.ascent = (F32)font.face->ascender;
|
||||
result.descent = (F32)font.face->descender;
|
||||
result.descent = -(F32)font.face->descender;
|
||||
result.line_gap = (F32)(font.face->height - font.face->ascender + font.face->descender);
|
||||
result.capital_height = (F32)(font.face->ascender);
|
||||
}
|
||||
|
||||
@@ -70,6 +70,7 @@
|
||||
//~ Global Symbols
|
||||
|
||||
#if !defined(RADDBG_MARKUP_STUBS)
|
||||
extern unsigned char raddbg_is_attached_byte_marker[1];
|
||||
int raddbg_is_attached__impl(void);
|
||||
int raddbg_thread_id__impl(void);
|
||||
void raddbg_thread_name__impl(int id, char *fmt, ...);
|
||||
@@ -97,8 +98,9 @@ void raddbg_annotate_vaddr_range__impl(void *ptr, unsigned __int64 size, char *f
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
//- first byte of exe data section -> is attached
|
||||
static raddbg_exe_data unsigned char raddbg_is_attached_byte_marker[1];
|
||||
//- special section gets "is attached" byte
|
||||
#pragma section(".rdbgia", read, write)
|
||||
__declspec(allocate(".rdbgia")) unsigned char raddbg_is_attached_byte_marker[1] = {0};
|
||||
|
||||
//- types
|
||||
|
||||
@@ -316,7 +318,7 @@ raddbg_thread_name__impl(int id, char *fmt, ...)
|
||||
#pragma warning(disable: 6320 6322)
|
||||
__try
|
||||
{
|
||||
RaiseException(0x406D1388, 0, sizeof(info) / sizeof(void *), (const ULONG_PTR *)&info);
|
||||
RaiseException(0x406D1388u, 0, sizeof(info) / sizeof(void *), (const ULONG_PTR *)&info);
|
||||
}
|
||||
__except(1)
|
||||
{
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
//~ RAD Debug Info, (R)AD(D)BG(I) Format Library
|
||||
//~ (R)AD (D)ebug (I)nfo Format Library
|
||||
//
|
||||
// Defines standard RDI debug information format types and
|
||||
// functions.
|
||||
|
||||
#ifndef RDI_FORMAT_C
|
||||
#define RDI_FORMAT_C
|
||||
#ifndef RDI_C
|
||||
#define RDI_C
|
||||
|
||||
RDI_U16 rdi_section_element_size_table[40] =
|
||||
{
|
||||
@@ -357,4 +357,4 @@ rdi_explanation_string_from_eval_conversion_kind(RDI_EvalConversionKind kind, RD
|
||||
return rdi_eval_conversion_kind_message_string_table[kind].str;
|
||||
}
|
||||
|
||||
#endif // RDI_FORMAT_C
|
||||
#endif // RDI_C
|
||||
@@ -2,13 +2,13 @@
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
//~ RAD Debug Info, (R)AD(D)BG(I) Format Library
|
||||
//~ (R)AD (D)ebug (I)nfo Format Library
|
||||
//
|
||||
// Defines standard RDI debug information format types and
|
||||
// functions.
|
||||
|
||||
#ifndef RDI_FORMAT_H
|
||||
#define RDI_FORMAT_H
|
||||
#ifndef RDI_H
|
||||
#define RDI_H
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
//~ Overridable Procedure Decoration
|
||||
@@ -1571,4 +1571,4 @@ extern RDI_U16 rdi_section_element_size_table[40];
|
||||
extern RDI_U8 rdi_section_is_required_table[40];
|
||||
extern RDI_U16 rdi_eval_op_ctrlbits_table[52];
|
||||
|
||||
#endif // RDI_FORMAT_H
|
||||
#endif // RDI_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,233 +1,236 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
//~ RAD Debug Info, (R)AD(D)BG(I) Format Parsing Library
|
||||
//
|
||||
// Defines helper types and functions for extracting data from
|
||||
// RDI files.
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
//~ Usage Samples
|
||||
//
|
||||
#if 0
|
||||
// Procedure Name -> Line
|
||||
{
|
||||
RDI_Parsed *rdi = ...;
|
||||
char *name = "mule_main";
|
||||
RDI_Procedure *procedure = rdi_procedure_from_name_cstr(rdi, name); // 1. name -> procedure
|
||||
RDI_U64 procedure_first_voff = rdi_first_voff_from_procedure(rdi, procedure); // 2. procedure -> virtual offset
|
||||
RDI_Line line = rdi_line_from_voff(rdi, procedure_first_voff); // 3. virtual offset -> line
|
||||
RDI_SourceFile *file = rdi_source_file_from_line(rdi, &line); // 4. line -> source file
|
||||
RDI_U64 file_path_size = 0; // 5. source file -> path
|
||||
RDI_U8 *file_path = rdi_normal_path_from_source_file(rdi, file, &file_path_size);
|
||||
printf("%s is at %.*s:%u\n", name, (int)file_path_size, file_path, line.line_num);
|
||||
}
|
||||
|
||||
// Line -> Procedure Name
|
||||
{
|
||||
RDI_Parsed *rdi = ...;
|
||||
char *path = "c:/devel/raddebugger/src/mule/mule_main.cpp";
|
||||
RDI_U32 line_num = 2557;
|
||||
RDI_SourceFile *file = rdi_source_file_from_normal_path_cstr(rdi, path); // 1. path -> source file
|
||||
RDI_U64 voff = rdi_first_voff_from_source_file_line_num(rdi, file, line_num); // 2. (source file, line) -> virtual offset
|
||||
RDI_Procedure *procedure = rdi_procedure_from_voff(rdi, voff); // 3. virtual offset -> procedure
|
||||
RDI_U64 name_size = 0; // 4. procedure -> name
|
||||
RDI_U8 *name = rdi_name_from_procedure(rdi, procedure, &name_size);
|
||||
printf("%s:%u is inside %.*s\n", path, line_num, (int)name_size, name);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef RDI_FORMAT_PARSE_H
|
||||
#define RDI_FORMAT_PARSE_H
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
//~ Parsed Information Types
|
||||
|
||||
typedef enum RDI_ParseStatus
|
||||
{
|
||||
RDI_ParseStatus_Good = 0,
|
||||
RDI_ParseStatus_HeaderDoesNotMatch = 1,
|
||||
RDI_ParseStatus_UnsupportedVersionNumber = 2,
|
||||
RDI_ParseStatus_InvalidDataSecionLayout = 3,
|
||||
RDI_ParseStatus_MissingRequiredSection = 4,
|
||||
}
|
||||
RDI_ParseStatus;
|
||||
|
||||
typedef struct RDI_Parsed RDI_Parsed;
|
||||
struct RDI_Parsed
|
||||
{
|
||||
RDI_U8 *raw_data;
|
||||
RDI_U64 raw_data_size;
|
||||
RDI_Section *sections;
|
||||
RDI_U64 sections_count;
|
||||
};
|
||||
|
||||
typedef struct RDI_ParsedLineTable RDI_ParsedLineTable;
|
||||
struct RDI_ParsedLineTable
|
||||
{
|
||||
// NOTE: Mapping VOFF -> LINE_INFO
|
||||
//
|
||||
// * [ voff[i], voff[i + 1] ) forms the voff range
|
||||
// * for the line info at lines[i] (and cols[i] if i < col_count)
|
||||
RDI_U64* voffs; // [count + 1] sorted
|
||||
RDI_Line* lines; // [count]
|
||||
RDI_Column* cols; // [col_count]
|
||||
RDI_U64 count;
|
||||
RDI_U64 col_count;
|
||||
};
|
||||
|
||||
typedef struct RDI_ParsedSourceLineMap RDI_ParsedSourceLineMap;
|
||||
struct RDI_ParsedSourceLineMap
|
||||
{
|
||||
// NOTE: Mapping LINE_NUMBER -> VOFFs
|
||||
//
|
||||
// * nums[i] gives a line number
|
||||
// * that line number has one or more associated voffs
|
||||
//
|
||||
// * to find all associated voffs for the line number nums[i] :
|
||||
// * let k span over the range [ ranges[i], ranges[i + 1] )
|
||||
// * voffs[k] gives the associated voffs
|
||||
RDI_U32* nums; // [count] sorted
|
||||
RDI_U32* ranges; // [count + 1]
|
||||
RDI_U64* voffs; // [voff_count]
|
||||
RDI_U64 count;
|
||||
RDI_U64 voff_count;
|
||||
};
|
||||
|
||||
typedef struct RDI_ParsedNameMap RDI_ParsedNameMap;
|
||||
struct RDI_ParsedNameMap
|
||||
{
|
||||
RDI_NameMapBucket *buckets;
|
||||
RDI_NameMapNode *nodes;
|
||||
RDI_U64 bucket_count;
|
||||
RDI_U64 node_count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ Global Nils
|
||||
|
||||
static union
|
||||
{
|
||||
RDI_TopLevelInfo top_level_info;
|
||||
RDI_BinarySection binary_section;
|
||||
RDI_FilePathNode file_path_node;
|
||||
RDI_SourceFile source_file;
|
||||
RDI_LineTable line_table;
|
||||
RDI_SourceLineMap source_line_map;
|
||||
RDI_Line line;
|
||||
RDI_Column column;
|
||||
RDI_Unit unit;
|
||||
RDI_VMapEntry vmap_entry;
|
||||
RDI_TypeNode type_node;
|
||||
RDI_UDT udt;
|
||||
RDI_Member member;
|
||||
RDI_EnumMember enum_member;
|
||||
RDI_GlobalVariable global_variable;
|
||||
RDI_ThreadVariable thread_variable;
|
||||
RDI_Procedure procedure;
|
||||
RDI_Scope scope;
|
||||
RDI_U64 voff;
|
||||
RDI_LocationBlock location_block;
|
||||
RDI_Local local;
|
||||
}
|
||||
rdi_nil_element_union = {0};
|
||||
static RDI_Parsed rdi_parsed_nil = {0};
|
||||
|
||||
////////////////////////////////
|
||||
//~ Top-Level Parsing API
|
||||
|
||||
RDI_PROC RDI_ParseStatus rdi_parse(RDI_U8 *data, RDI_U64 size, RDI_Parsed *out);
|
||||
|
||||
////////////////////////////////
|
||||
//~ Base Parsed Info Extraction Helpers
|
||||
|
||||
//- section table/element raw data extraction
|
||||
RDI_PROC void *rdi_section_raw_data_from_kind(RDI_Parsed *rdi, RDI_SectionKind kind, RDI_SectionEncoding *encoding_out, RDI_U64 *size_out);
|
||||
RDI_PROC void *rdi_section_raw_table_from_kind(RDI_Parsed *rdi, RDI_SectionKind kind, RDI_U64 *count_out);
|
||||
RDI_PROC void *rdi_section_raw_element_from_kind_idx(RDI_Parsed *rdi, RDI_SectionKind kind, RDI_U64 idx);
|
||||
#define rdi_table_from_name(rdi, name, count_out) ((RDI_SectionElementType_##name *)rdi_section_raw_table_from_kind((rdi), RDI_SectionKind_##name, (count_out)))
|
||||
#define rdi_element_from_name_idx(rdi, name, idx) ((RDI_SectionElementType_##name *)rdi_section_raw_element_from_kind_idx((rdi), RDI_SectionKind_##name, (idx)))
|
||||
|
||||
//- info about whole parse
|
||||
RDI_PROC RDI_U64 rdi_decompressed_size_from_parsed(RDI_Parsed *rdi);
|
||||
|
||||
//- strings
|
||||
RDI_PROC RDI_U8 *rdi_string_from_idx(RDI_Parsed *rdi, RDI_U32 idx, RDI_U64 *len_out);
|
||||
|
||||
//- index runs
|
||||
RDI_PROC RDI_U32 *rdi_idx_run_from_first_count(RDI_Parsed *rdi, RDI_U32 raw_first, RDI_U32 raw_count, RDI_U32 *n_out);
|
||||
|
||||
//- line info
|
||||
RDI_PROC void rdi_parsed_from_line_table(RDI_Parsed *rdi, RDI_LineTable *line_table, RDI_ParsedLineTable *out);
|
||||
RDI_PROC RDI_U64 rdi_line_info_idx_range_from_voff(RDI_ParsedLineTable *line_info, RDI_U64 voff, RDI_U64 *n_out);
|
||||
RDI_PROC RDI_U64 rdi_line_info_idx_from_voff(RDI_ParsedLineTable *line_info, RDI_U64 voff);
|
||||
RDI_PROC void rdi_parsed_from_source_line_map(RDI_Parsed *rdi, RDI_SourceLineMap *map, RDI_ParsedSourceLineMap *out);
|
||||
RDI_PROC RDI_U64 *rdi_line_voffs_from_num(RDI_ParsedSourceLineMap *map, RDI_U32 linenum, RDI_U32 *n_out);
|
||||
|
||||
//- vmap lookups
|
||||
RDI_PROC RDI_U64 rdi_vmap_idx_from_voff(RDI_VMapEntry *vmap, RDI_U64 vmap_count, RDI_U64 voff);
|
||||
|
||||
//- name maps
|
||||
RDI_PROC RDI_NameMap *rdi_name_map_from_kind(RDI_Parsed *p, RDI_NameMapKind kind);
|
||||
RDI_PROC void rdi_name_map_parse(RDI_Parsed* p, RDI_NameMap *mapptr, RDI_ParsedNameMap *out);
|
||||
RDI_PROC RDI_NameMapNode *rdi_name_map_lookup(RDI_Parsed *p, RDI_ParsedNameMap *map, RDI_U8 *str, RDI_U64 len);
|
||||
RDI_PROC RDI_U32 *rdi_matches_from_map_node(RDI_Parsed *p, RDI_NameMapNode *node, RDI_U32 *n_out);
|
||||
|
||||
////////////////////////////////
|
||||
//~ High-Level Composite Lookup Functions
|
||||
|
||||
//- procedures
|
||||
RDI_PROC RDI_Procedure *rdi_procedure_from_name(RDI_Parsed *rdi, RDI_U8 *name, RDI_U64 name_size);
|
||||
RDI_PROC RDI_Procedure *rdi_procedure_from_name_cstr(RDI_Parsed *rdi, char *cstr);
|
||||
RDI_PROC RDI_U8 *rdi_name_from_procedure(RDI_Parsed *rdi, RDI_Procedure *procedure, RDI_U64 *len_out);
|
||||
RDI_PROC RDI_Scope *rdi_root_scope_from_procedure(RDI_Parsed *rdi, RDI_Procedure *procedure);
|
||||
RDI_PROC RDI_UDT *rdi_container_udt_from_procedure(RDI_Parsed *rdi, RDI_Procedure *procedure);
|
||||
RDI_PROC RDI_Procedure *rdi_container_procedure_from_procedure(RDI_Parsed *rdi, RDI_Procedure *procedure);
|
||||
RDI_PROC RDI_U64 rdi_first_voff_from_procedure(RDI_Parsed *rdi, RDI_Procedure *procedure);
|
||||
RDI_PROC RDI_U64 rdi_opl_voff_from_procedure(RDI_Parsed *rdi, RDI_Procedure *procedure);
|
||||
RDI_PROC RDI_Procedure *rdi_procedure_from_voff(RDI_Parsed *rdi, RDI_U64 voff);
|
||||
|
||||
//- scopes
|
||||
RDI_PROC RDI_U64 rdi_first_voff_from_scope(RDI_Parsed *rdi, RDI_Scope *scope);
|
||||
RDI_PROC RDI_U64 rdi_opl_voff_from_scope(RDI_Parsed *rdi, RDI_Scope *scope);
|
||||
RDI_PROC RDI_Scope *rdi_scope_from_voff(RDI_Parsed *rdi, RDI_U64 voff);
|
||||
RDI_PROC RDI_Scope *rdi_parent_from_scope(RDI_Parsed *rdi, RDI_Scope *scope);
|
||||
RDI_PROC RDI_Procedure *rdi_procedure_from_scope(RDI_Parsed *rdi, RDI_Scope *scope);
|
||||
RDI_PROC RDI_InlineSite *rdi_inline_site_from_scope(RDI_Parsed *rdi, RDI_Scope *scope);
|
||||
|
||||
//- global variables
|
||||
RDI_PROC RDI_GlobalVariable *rdi_global_variable_from_voff(RDI_Parsed *rdi, RDI_U64 voff);
|
||||
|
||||
//- units
|
||||
RDI_PROC RDI_Unit *rdi_unit_from_voff(RDI_Parsed *rdi, RDI_U64 voff);
|
||||
RDI_PROC RDI_LineTable *rdi_line_table_from_unit(RDI_Parsed *rdi, RDI_Unit *unit);
|
||||
|
||||
//- line tables
|
||||
RDI_PROC RDI_Line rdi_line_from_voff(RDI_Parsed *rdi, RDI_U64 voff);
|
||||
RDI_PROC RDI_Line rdi_line_from_line_table_voff(RDI_Parsed *rdi, RDI_LineTable *line_table, RDI_U64 voff);
|
||||
RDI_PROC RDI_SourceFile *rdi_source_file_from_line(RDI_Parsed *rdi, RDI_Line *line);
|
||||
|
||||
//- source files
|
||||
RDI_PROC RDI_SourceFile *rdi_source_file_from_normal_path(RDI_Parsed *rdi, RDI_U8 *name, RDI_U64 name_size);
|
||||
RDI_PROC RDI_SourceFile *rdi_source_file_from_normal_path_cstr(RDI_Parsed *rdi, char *cstr);
|
||||
RDI_PROC RDI_U8 *rdi_normal_path_from_source_file(RDI_Parsed *rdi, RDI_SourceFile *src_file, RDI_U64 *len_out);
|
||||
RDI_PROC RDI_FilePathNode *rdi_file_path_node_from_source_file(RDI_Parsed *rdi, RDI_SourceFile *src_file);
|
||||
RDI_PROC RDI_SourceLineMap *rdi_source_line_map_from_source_file(RDI_Parsed *rdi, RDI_SourceFile *src_file);
|
||||
RDI_PROC RDI_U64 rdi_first_voff_from_source_file_line_num(RDI_Parsed *rdi, RDI_SourceFile *src_file, RDI_U32 line_num);
|
||||
|
||||
//- source line maps
|
||||
RDI_PROC RDI_U64 rdi_first_voff_from_source_line_map_num(RDI_Parsed *rdi, RDI_SourceLineMap *map, RDI_U32 line_num);
|
||||
|
||||
//- file path nodes
|
||||
RDI_PROC RDI_FilePathNode *rdi_parent_from_file_path_node(RDI_Parsed *rdi, RDI_FilePathNode *node);
|
||||
RDI_PROC RDI_U8 *rdi_name_from_file_path_node(RDI_Parsed *rdi, RDI_FilePathNode *node, RDI_U64 *len_out);
|
||||
|
||||
////////////////////////////////
|
||||
//~ Parser Helpers
|
||||
|
||||
#define rdi_parse__min(a,b) (((a)<(b))?(a):(b))
|
||||
RDI_PROC RDI_U64 rdi_cstring_length(char *cstr);
|
||||
RDI_PROC RDI_U64 rdi_size_from_bytecode_stream(RDI_U8 *ptr, RDI_U8 *opl);
|
||||
|
||||
#endif // RDI_FORMAT_PARSE_H
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
//~ (R)AD (D)ebug (I)nfo Format Parsing Library
|
||||
//
|
||||
// Defines helper types and functions for extracting data from
|
||||
// RDI files.
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
//~ Usage Samples
|
||||
//
|
||||
#if 0
|
||||
// Procedure Name -> Line
|
||||
{
|
||||
RDI_Parsed *rdi = ...;
|
||||
char *name = "mule_main";
|
||||
RDI_Procedure *procedure = rdi_procedure_from_name_cstr(rdi, name); // 1. name -> procedure
|
||||
RDI_U64 procedure_first_voff = rdi_first_voff_from_procedure(rdi, procedure); // 2. procedure -> virtual offset
|
||||
RDI_Line line = rdi_line_from_voff(rdi, procedure_first_voff); // 3. virtual offset -> line
|
||||
RDI_SourceFile *file = rdi_source_file_from_line(rdi, &line); // 4. line -> source file
|
||||
RDI_U64 file_path_size = 0; // 5. source file -> path
|
||||
RDI_U8 *file_path = rdi_normal_path_from_source_file(rdi, file, &file_path_size);
|
||||
printf("%s is at %.*s:%u\n", name, (int)file_path_size, file_path, line.line_num);
|
||||
}
|
||||
|
||||
// Line -> Procedure Name
|
||||
{
|
||||
RDI_Parsed *rdi = ...;
|
||||
char *path = "c:/devel/raddebugger/src/mule/mule_main.cpp";
|
||||
RDI_U32 line_num = 2557;
|
||||
RDI_SourceFile *file = rdi_source_file_from_normal_path_cstr(rdi, path); // 1. path -> source file
|
||||
RDI_U64 voff = rdi_first_voff_from_source_file_line_num(rdi, file, line_num); // 2. (source file, line) -> virtual offset
|
||||
RDI_Procedure *procedure = rdi_procedure_from_voff(rdi, voff); // 3. virtual offset -> procedure
|
||||
RDI_U64 name_size = 0; // 4. procedure -> name
|
||||
RDI_U8 *name = rdi_name_from_procedure(rdi, procedure, &name_size);
|
||||
printf("%s:%u is inside %.*s\n", path, line_num, (int)name_size, name);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef RDI_PARSE_H
|
||||
#define RDI_PARSE_H
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
//~ Parsed Information Types
|
||||
|
||||
typedef enum RDI_ParseStatus
|
||||
{
|
||||
RDI_ParseStatus_Good = 0,
|
||||
RDI_ParseStatus_HeaderDoesNotMatch = 1,
|
||||
RDI_ParseStatus_UnsupportedVersionNumber = 2,
|
||||
RDI_ParseStatus_InvalidDataSecionLayout = 3,
|
||||
RDI_ParseStatus_MissingRequiredSection = 4,
|
||||
}
|
||||
RDI_ParseStatus;
|
||||
|
||||
typedef struct RDI_Parsed RDI_Parsed;
|
||||
struct RDI_Parsed
|
||||
{
|
||||
RDI_U8 *raw_data;
|
||||
RDI_U64 raw_data_size;
|
||||
RDI_Section *sections;
|
||||
RDI_U64 sections_count;
|
||||
};
|
||||
|
||||
typedef struct RDI_ParsedLineTable RDI_ParsedLineTable;
|
||||
struct RDI_ParsedLineTable
|
||||
{
|
||||
// NOTE: Mapping VOFF -> LINE_INFO
|
||||
//
|
||||
// * [ voff[i], voff[i + 1] ) forms the voff range
|
||||
// * for the line info at lines[i] (and cols[i] if i < col_count)
|
||||
RDI_U64* voffs; // [count + 1] sorted
|
||||
RDI_Line* lines; // [count]
|
||||
RDI_Column* cols; // [col_count]
|
||||
RDI_U64 count;
|
||||
RDI_U64 col_count;
|
||||
};
|
||||
|
||||
typedef struct RDI_ParsedSourceLineMap RDI_ParsedSourceLineMap;
|
||||
struct RDI_ParsedSourceLineMap
|
||||
{
|
||||
// NOTE: Mapping LINE_NUMBER -> VOFFs
|
||||
//
|
||||
// * nums[i] gives a line number
|
||||
// * that line number has one or more associated voffs
|
||||
//
|
||||
// * to find all associated voffs for the line number nums[i] :
|
||||
// * let k span over the range [ ranges[i], ranges[i + 1] )
|
||||
// * voffs[k] gives the associated voffs
|
||||
RDI_U32* nums; // [count] sorted
|
||||
RDI_U32* ranges; // [count + 1]
|
||||
RDI_U64* voffs; // [voff_count]
|
||||
RDI_U64 count;
|
||||
RDI_U64 voff_count;
|
||||
};
|
||||
|
||||
typedef struct RDI_ParsedNameMap RDI_ParsedNameMap;
|
||||
struct RDI_ParsedNameMap
|
||||
{
|
||||
RDI_NameMapBucket *buckets;
|
||||
RDI_NameMapNode *nodes;
|
||||
RDI_U64 bucket_count;
|
||||
RDI_U64 node_count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ Global Nils
|
||||
|
||||
static union
|
||||
{
|
||||
RDI_TopLevelInfo top_level_info;
|
||||
RDI_BinarySection binary_section;
|
||||
RDI_FilePathNode file_path_node;
|
||||
RDI_SourceFile source_file;
|
||||
RDI_LineTable line_table;
|
||||
RDI_SourceLineMap source_line_map;
|
||||
RDI_Line line;
|
||||
RDI_Column column;
|
||||
RDI_Unit unit;
|
||||
RDI_VMapEntry vmap_entry;
|
||||
RDI_TypeNode type_node;
|
||||
RDI_UDT udt;
|
||||
RDI_Member member;
|
||||
RDI_EnumMember enum_member;
|
||||
RDI_GlobalVariable global_variable;
|
||||
RDI_ThreadVariable thread_variable;
|
||||
RDI_Procedure procedure;
|
||||
RDI_Scope scope;
|
||||
RDI_U64 voff;
|
||||
RDI_LocationBlock location_block;
|
||||
RDI_Local local;
|
||||
}
|
||||
rdi_nil_element_union = {0};
|
||||
static RDI_Parsed rdi_parsed_nil = {0};
|
||||
|
||||
////////////////////////////////
|
||||
//~ Top-Level Parsing API
|
||||
|
||||
RDI_PROC RDI_ParseStatus rdi_parse(RDI_U8 *data, RDI_U64 size, RDI_Parsed *out);
|
||||
|
||||
////////////////////////////////
|
||||
//~ Base Parsed Info Extraction Helpers
|
||||
|
||||
//- section table/element raw data extraction
|
||||
RDI_PROC void *rdi_section_raw_data_from_kind(RDI_Parsed *rdi, RDI_SectionKind kind, RDI_SectionEncoding *encoding_out, RDI_U64 *size_out);
|
||||
RDI_PROC void *rdi_section_raw_table_from_kind(RDI_Parsed *rdi, RDI_SectionKind kind, RDI_U64 *count_out);
|
||||
RDI_PROC void *rdi_section_raw_element_from_kind_idx(RDI_Parsed *rdi, RDI_SectionKind kind, RDI_U64 idx);
|
||||
#define rdi_table_from_name(rdi, name, count_out) ((RDI_SectionElementType_##name *)rdi_section_raw_table_from_kind((rdi), RDI_SectionKind_##name, (count_out)))
|
||||
#define rdi_element_from_name_idx(rdi, name, idx) ((RDI_SectionElementType_##name *)rdi_section_raw_element_from_kind_idx((rdi), RDI_SectionKind_##name, (idx)))
|
||||
|
||||
//- info about whole parse
|
||||
RDI_PROC RDI_U64 rdi_decompressed_size_from_parsed(RDI_Parsed *rdi);
|
||||
|
||||
//- decompression
|
||||
internal void rdi_decompress_parsed(U8 *decompressed_data, U64 decompressed_size, RDI_Parsed *og_rdi);
|
||||
|
||||
//- strings
|
||||
RDI_PROC RDI_U8 *rdi_string_from_idx(RDI_Parsed *rdi, RDI_U32 idx, RDI_U64 *len_out);
|
||||
|
||||
//- index runs
|
||||
RDI_PROC RDI_U32 *rdi_idx_run_from_first_count(RDI_Parsed *rdi, RDI_U32 raw_first, RDI_U32 raw_count, RDI_U32 *n_out);
|
||||
|
||||
//- line info
|
||||
RDI_PROC void rdi_parsed_from_line_table(RDI_Parsed *rdi, RDI_LineTable *line_table, RDI_ParsedLineTable *out);
|
||||
RDI_PROC RDI_U64 rdi_line_info_idx_range_from_voff(RDI_ParsedLineTable *line_info, RDI_U64 voff, RDI_U64 *n_out);
|
||||
RDI_PROC RDI_U64 rdi_line_info_idx_from_voff(RDI_ParsedLineTable *line_info, RDI_U64 voff);
|
||||
RDI_PROC void rdi_parsed_from_source_line_map(RDI_Parsed *rdi, RDI_SourceLineMap *map, RDI_ParsedSourceLineMap *out);
|
||||
RDI_PROC RDI_U64 *rdi_line_voffs_from_num(RDI_ParsedSourceLineMap *map, RDI_U32 linenum, RDI_U32 *n_out);
|
||||
|
||||
//- vmap lookups
|
||||
RDI_PROC RDI_U64 rdi_vmap_idx_from_voff(RDI_VMapEntry *vmap, RDI_U64 vmap_count, RDI_U64 voff);
|
||||
|
||||
//- name maps
|
||||
RDI_PROC RDI_NameMap *rdi_name_map_from_kind(RDI_Parsed *p, RDI_NameMapKind kind);
|
||||
RDI_PROC void rdi_name_map_parse(RDI_Parsed* p, RDI_NameMap *mapptr, RDI_ParsedNameMap *out);
|
||||
RDI_PROC RDI_NameMapNode *rdi_name_map_lookup(RDI_Parsed *p, RDI_ParsedNameMap *map, RDI_U8 *str, RDI_U64 len);
|
||||
RDI_PROC RDI_U32 *rdi_matches_from_map_node(RDI_Parsed *p, RDI_NameMapNode *node, RDI_U32 *n_out);
|
||||
|
||||
////////////////////////////////
|
||||
//~ High-Level Composite Lookup Functions
|
||||
|
||||
//- procedures
|
||||
RDI_PROC RDI_Procedure *rdi_procedure_from_name(RDI_Parsed *rdi, RDI_U8 *name, RDI_U64 name_size);
|
||||
RDI_PROC RDI_Procedure *rdi_procedure_from_name_cstr(RDI_Parsed *rdi, char *cstr);
|
||||
RDI_PROC RDI_U8 *rdi_name_from_procedure(RDI_Parsed *rdi, RDI_Procedure *procedure, RDI_U64 *len_out);
|
||||
RDI_PROC RDI_Scope *rdi_root_scope_from_procedure(RDI_Parsed *rdi, RDI_Procedure *procedure);
|
||||
RDI_PROC RDI_UDT *rdi_container_udt_from_procedure(RDI_Parsed *rdi, RDI_Procedure *procedure);
|
||||
RDI_PROC RDI_Procedure *rdi_container_procedure_from_procedure(RDI_Parsed *rdi, RDI_Procedure *procedure);
|
||||
RDI_PROC RDI_U64 rdi_first_voff_from_procedure(RDI_Parsed *rdi, RDI_Procedure *procedure);
|
||||
RDI_PROC RDI_U64 rdi_opl_voff_from_procedure(RDI_Parsed *rdi, RDI_Procedure *procedure);
|
||||
RDI_PROC RDI_Procedure *rdi_procedure_from_voff(RDI_Parsed *rdi, RDI_U64 voff);
|
||||
|
||||
//- scopes
|
||||
RDI_PROC RDI_U64 rdi_first_voff_from_scope(RDI_Parsed *rdi, RDI_Scope *scope);
|
||||
RDI_PROC RDI_U64 rdi_opl_voff_from_scope(RDI_Parsed *rdi, RDI_Scope *scope);
|
||||
RDI_PROC RDI_Scope *rdi_scope_from_voff(RDI_Parsed *rdi, RDI_U64 voff);
|
||||
RDI_PROC RDI_Scope *rdi_parent_from_scope(RDI_Parsed *rdi, RDI_Scope *scope);
|
||||
RDI_PROC RDI_Procedure *rdi_procedure_from_scope(RDI_Parsed *rdi, RDI_Scope *scope);
|
||||
RDI_PROC RDI_InlineSite *rdi_inline_site_from_scope(RDI_Parsed *rdi, RDI_Scope *scope);
|
||||
|
||||
//- global variables
|
||||
RDI_PROC RDI_GlobalVariable *rdi_global_variable_from_voff(RDI_Parsed *rdi, RDI_U64 voff);
|
||||
|
||||
//- units
|
||||
RDI_PROC RDI_Unit *rdi_unit_from_voff(RDI_Parsed *rdi, RDI_U64 voff);
|
||||
RDI_PROC RDI_LineTable *rdi_line_table_from_unit(RDI_Parsed *rdi, RDI_Unit *unit);
|
||||
|
||||
//- line tables
|
||||
RDI_PROC RDI_Line rdi_line_from_voff(RDI_Parsed *rdi, RDI_U64 voff);
|
||||
RDI_PROC RDI_Line rdi_line_from_line_table_voff(RDI_Parsed *rdi, RDI_LineTable *line_table, RDI_U64 voff);
|
||||
RDI_PROC RDI_SourceFile *rdi_source_file_from_line(RDI_Parsed *rdi, RDI_Line *line);
|
||||
|
||||
//- source files
|
||||
RDI_PROC RDI_SourceFile *rdi_source_file_from_normal_path(RDI_Parsed *rdi, RDI_U8 *name, RDI_U64 name_size);
|
||||
RDI_PROC RDI_SourceFile *rdi_source_file_from_normal_path_cstr(RDI_Parsed *rdi, char *cstr);
|
||||
RDI_PROC RDI_U8 *rdi_normal_path_from_source_file(RDI_Parsed *rdi, RDI_SourceFile *src_file, RDI_U64 *len_out);
|
||||
RDI_PROC RDI_FilePathNode *rdi_file_path_node_from_source_file(RDI_Parsed *rdi, RDI_SourceFile *src_file);
|
||||
RDI_PROC RDI_SourceLineMap *rdi_source_line_map_from_source_file(RDI_Parsed *rdi, RDI_SourceFile *src_file);
|
||||
RDI_PROC RDI_U64 rdi_first_voff_from_source_file_line_num(RDI_Parsed *rdi, RDI_SourceFile *src_file, RDI_U32 line_num);
|
||||
|
||||
//- source line maps
|
||||
RDI_PROC RDI_U64 rdi_first_voff_from_source_line_map_num(RDI_Parsed *rdi, RDI_SourceLineMap *map, RDI_U32 line_num);
|
||||
|
||||
//- file path nodes
|
||||
RDI_PROC RDI_FilePathNode *rdi_parent_from_file_path_node(RDI_Parsed *rdi, RDI_FilePathNode *node);
|
||||
RDI_PROC RDI_U8 *rdi_name_from_file_path_node(RDI_Parsed *rdi, RDI_FilePathNode *node, RDI_U64 *len_out);
|
||||
|
||||
////////////////////////////////
|
||||
//~ Parser Helpers
|
||||
|
||||
#define rdi_parse__min(a,b) (((a)<(b))?(a):(b))
|
||||
RDI_PROC RDI_U64 rdi_cstring_length(char *cstr);
|
||||
RDI_PROC RDI_U64 rdi_size_from_bytecode_stream(RDI_U8 *ptr, RDI_U8 *opl);
|
||||
|
||||
#endif // RDI_FORMAT_PARSE_H
|
||||
@@ -1,864 +0,0 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ Top-Level Parsing API
|
||||
|
||||
RDI_PROC RDI_ParseStatus
|
||||
rdi_parse(RDI_U8 *data, RDI_U64 size, RDI_Parsed *out)
|
||||
{
|
||||
RDI_ParseStatus result = RDI_ParseStatus_Good;
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: extract header
|
||||
//
|
||||
RDI_Header *hdr = 0;
|
||||
if(result == RDI_ParseStatus_Good)
|
||||
{
|
||||
if(sizeof(*hdr) <= size)
|
||||
{
|
||||
hdr = (RDI_Header*)data;
|
||||
}
|
||||
if(hdr == 0 || hdr->magic != RDI_MAGIC_CONSTANT)
|
||||
{
|
||||
hdr = 0;
|
||||
result = RDI_ParseStatus_HeaderDoesNotMatch;
|
||||
}
|
||||
if(hdr != 0 && hdr->encoding_version != RDI_ENCODING_VERSION)
|
||||
{
|
||||
hdr = 0;
|
||||
result = RDI_ParseStatus_UnsupportedVersionNumber;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: extract data sections
|
||||
//
|
||||
RDI_Section *dsecs = 0;
|
||||
RDI_U32 dsec_count = 0;
|
||||
if(result == RDI_ParseStatus_Good)
|
||||
{
|
||||
RDI_U64 opl = (RDI_U64)hdr->data_section_off + (RDI_U64)hdr->data_section_count*sizeof(*dsecs);
|
||||
if(opl <= size)
|
||||
{
|
||||
dsecs = (RDI_Section*)(data + hdr->data_section_off);
|
||||
dsec_count = hdr->data_section_count;
|
||||
}
|
||||
if(dsecs == 0)
|
||||
{
|
||||
result = RDI_ParseStatus_InvalidDataSecionLayout;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: fill result
|
||||
//
|
||||
if(result == RDI_ParseStatus_Good)
|
||||
{
|
||||
out->raw_data = data;
|
||||
out->raw_data_size = size;
|
||||
out->sections = dsecs;
|
||||
out->sections_count = dsec_count;
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: validate results
|
||||
//
|
||||
if(result == RDI_ParseStatus_Good)
|
||||
{
|
||||
for(RDI_SectionKind k = (RDI_SectionKind)(RDI_SectionKind_NULL+1); k < RDI_SectionKind_COUNT; k = (RDI_SectionKind)(k+1))
|
||||
{
|
||||
if(rdi_section_is_required_table[k])
|
||||
{
|
||||
RDI_U64 data_size = 0;
|
||||
RDI_SectionEncoding encoding = 0;
|
||||
void *data = rdi_section_raw_data_from_kind(out, k, &encoding, &data_size);
|
||||
if(data == 0 || data == &rdi_nil_element_union || data_size == 0)
|
||||
{
|
||||
result = RDI_ParseStatus_MissingRequiredSection;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ Base Parsed Info Extraction Helpers
|
||||
|
||||
//- section table/element raw data extraction
|
||||
|
||||
RDI_PROC void *
|
||||
rdi_section_raw_data_from_kind(RDI_Parsed *rdi, RDI_SectionKind kind, RDI_SectionEncoding *encoding_out, RDI_U64 *size_out)
|
||||
{
|
||||
void *result = 0;
|
||||
#if !defined(RDI_DISABLE_NILS)
|
||||
result = &rdi_nil_element_union;
|
||||
*size_out = rdi_section_element_size_table[kind];
|
||||
#endif
|
||||
if(0 <= kind && kind < rdi->sections_count &&
|
||||
rdi->sections[kind].off < rdi->raw_data_size)
|
||||
{
|
||||
result = rdi->raw_data+rdi->sections[kind].off;
|
||||
*size_out = rdi->sections[kind].encoded_size;
|
||||
*encoding_out = rdi->sections[kind].encoding;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
RDI_PROC void *
|
||||
rdi_section_raw_table_from_kind(RDI_Parsed *rdi, RDI_SectionKind kind, RDI_U64 *count_out)
|
||||
{
|
||||
void *result = 0;
|
||||
RDI_U64 all_elements_size = 0;
|
||||
RDI_SectionEncoding all_elements_encoding = 0;
|
||||
void *all_elements = rdi_section_raw_data_from_kind(rdi, kind, &all_elements_encoding, &all_elements_size);
|
||||
if(all_elements_encoding == RDI_SectionEncoding_Unpacked)
|
||||
{
|
||||
RDI_U64 element_size = (RDI_U64)rdi_section_element_size_table[kind];
|
||||
RDI_U64 all_elements_count = all_elements_size/element_size;
|
||||
result = all_elements;
|
||||
*count_out = all_elements_count;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
RDI_PROC void *
|
||||
rdi_section_raw_element_from_kind_idx(RDI_Parsed *rdi, RDI_SectionKind kind, RDI_U64 idx)
|
||||
{
|
||||
RDI_U64 count = 0;
|
||||
void *table = rdi_section_raw_table_from_kind(rdi, kind, &count);
|
||||
void *result = table;
|
||||
if(idx < count)
|
||||
{
|
||||
RDI_U64 element_size = (RDI_U64)rdi_section_element_size_table[kind];
|
||||
result = (RDI_U8 *)table + element_size*idx;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//- info about whole parse
|
||||
|
||||
RDI_PROC RDI_U64
|
||||
rdi_decompressed_size_from_parsed(RDI_Parsed *rdi)
|
||||
{
|
||||
RDI_U64 decompressed_size = rdi->raw_data_size;
|
||||
for(RDI_U64 section_idx = 0; section_idx < rdi->sections_count; section_idx += 1)
|
||||
{
|
||||
decompressed_size += (rdi->sections[section_idx].unpacked_size - rdi->sections[section_idx].encoded_size);
|
||||
}
|
||||
return decompressed_size;
|
||||
}
|
||||
|
||||
//- strings
|
||||
|
||||
RDI_PROC RDI_U8 *
|
||||
rdi_string_from_idx(RDI_Parsed *rdi, RDI_U32 idx, RDI_U64 *len_out)
|
||||
{
|
||||
RDI_U8 *result_base = 0;
|
||||
RDI_U64 result_size = 0;
|
||||
{
|
||||
RDI_U64 string_offs_count = 0;
|
||||
RDI_U32 *string_offs = rdi_table_from_name(rdi, StringTable, &string_offs_count);
|
||||
if(idx < string_offs_count)
|
||||
{
|
||||
RDI_U64 string_data_size = 0;
|
||||
RDI_U8 *string_data = rdi_table_from_name(rdi, StringData, &string_data_size);
|
||||
RDI_U32 off_raw = string_offs[idx];
|
||||
RDI_U32 opl_raw = string_offs[idx + 1];
|
||||
RDI_U32 opl = rdi_parse__min(opl_raw, string_data_size);
|
||||
RDI_U32 off = rdi_parse__min(off_raw, opl);
|
||||
result_base = string_data + off;
|
||||
result_size = opl - off;
|
||||
}
|
||||
}
|
||||
*len_out = result_size;
|
||||
return result_base;
|
||||
}
|
||||
|
||||
//- index runs
|
||||
|
||||
RDI_PROC RDI_U32*
|
||||
rdi_idx_run_from_first_count(RDI_Parsed *rdi, RDI_U32 raw_first, RDI_U32 raw_count, RDI_U32 *n_out)
|
||||
{
|
||||
RDI_U64 idx_run_count = 0;
|
||||
RDI_U32 *idx_run_data = rdi_table_from_name(rdi, IndexRuns, &idx_run_count);
|
||||
RDI_U32 raw_opl = raw_first + raw_count;
|
||||
RDI_U32 opl = rdi_parse__min(raw_opl, idx_run_count);
|
||||
RDI_U32 first = rdi_parse__min(raw_first, opl);
|
||||
RDI_U32 *result = 0;
|
||||
if(first < idx_run_count)
|
||||
{
|
||||
result = idx_run_data + first;
|
||||
}
|
||||
*n_out = opl - first;
|
||||
return result;
|
||||
}
|
||||
|
||||
//- line info
|
||||
|
||||
RDI_PROC void
|
||||
rdi_parsed_from_line_table(RDI_Parsed *rdi, RDI_LineTable *line_table, RDI_ParsedLineTable *out)
|
||||
{
|
||||
//- rjf: extract top-level line info tables
|
||||
RDI_U64 all_voffs_count = 0;
|
||||
RDI_U64 *all_voffs = rdi_table_from_name(rdi, LineInfoVOffs, &all_voffs_count);
|
||||
RDI_U64 *all_voffs_opl = all_voffs + all_voffs_count;
|
||||
RDI_U64 all_lines_count = 0;
|
||||
RDI_Line *all_lines = rdi_table_from_name(rdi, LineInfoLines, &all_lines_count);
|
||||
RDI_Line *all_lines_opl = all_lines + all_lines_count;
|
||||
RDI_U64 all_cols_count = 0;
|
||||
RDI_Column *all_cols = rdi_table_from_name(rdi, LineInfoColumns, &all_cols_count);
|
||||
RDI_Column *all_cols_opl = all_cols + all_cols_count;
|
||||
|
||||
//- rjf: extract ranges of top-level tables belonging to this line table
|
||||
RDI_U64 *lt_voffs = all_voffs + line_table->voffs_base_idx;
|
||||
RDI_Line *lt_lines = all_lines + line_table->lines_base_idx;
|
||||
RDI_Column *lt_cols = all_cols + line_table->cols_base_idx;
|
||||
RDI_U64 lines_count = line_table->lines_count;
|
||||
RDI_U64 cols_count = line_table->cols_count;
|
||||
if(lt_voffs >= all_voffs_opl) {lt_voffs = all_voffs; lines_count = 0;}
|
||||
if(lt_lines >= all_lines_opl) {lt_lines = all_lines; lines_count = 0;}
|
||||
if(lt_cols >= all_cols_opl) {lt_cols = all_cols; cols_count = 0;}
|
||||
|
||||
//- rjf: fill result
|
||||
out->voffs = lt_voffs;
|
||||
out->lines = lt_lines;
|
||||
out->cols = lt_cols;
|
||||
out->count = lines_count;
|
||||
out->col_count = cols_count;
|
||||
}
|
||||
|
||||
RDI_PROC RDI_U64
|
||||
rdi_line_info_idx_range_from_voff(RDI_ParsedLineTable *line_info, RDI_U64 voff, RDI_U64 *n_out)
|
||||
{
|
||||
RDI_U64 result = 0;
|
||||
RDI_U64 n = 0;
|
||||
if(line_info->count > 0 && line_info->voffs[0] <= voff && voff < line_info->voffs[line_info->count - 1])
|
||||
{
|
||||
//- rjf: find i such that: (vmap[i].voff <= voff) && (voff < vmap[i + 1].voff)
|
||||
// assuming: (i < j) -> (vmap[i].voff < vmap[j].voff)
|
||||
RDI_U32 first = 0;
|
||||
RDI_U32 opl = line_info->count;
|
||||
for(;;)
|
||||
{
|
||||
RDI_U32 mid = (first + opl)/2;
|
||||
if(line_info->voffs[mid] < voff)
|
||||
{
|
||||
first = mid;
|
||||
}
|
||||
else if(line_info->voffs[mid] > voff)
|
||||
{
|
||||
opl = mid;
|
||||
}
|
||||
else
|
||||
{
|
||||
first = mid;
|
||||
break;
|
||||
}
|
||||
if(opl - first <= 1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
result = (RDI_U64)first;
|
||||
|
||||
//- rjf: scan leftward, to find shallowest line info matching this voff
|
||||
for(;result != 0;)
|
||||
{
|
||||
if(line_info->voffs[result-1] == voff)
|
||||
{
|
||||
result -= 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: scan rightward, to count # of line info with this voff
|
||||
for(RDI_U64 idx = result; idx < line_info->count; idx += 1)
|
||||
{
|
||||
if(line_info->voffs[idx] == voff)
|
||||
{
|
||||
n += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(n_out)
|
||||
{
|
||||
*n_out = n;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
RDI_PROC RDI_U64
|
||||
rdi_line_info_idx_from_voff(RDI_ParsedLineTable *line_info, RDI_U64 voff)
|
||||
{
|
||||
RDI_U64 count = 0;
|
||||
RDI_U64 result = rdi_line_info_idx_range_from_voff(line_info, voff, &count);
|
||||
for(RDI_S64 idx = count-1; idx >= 0; idx -= 1)
|
||||
{
|
||||
if(result + idx < line_info->count && line_info->lines[result+idx].file_idx != 0)
|
||||
{
|
||||
result += idx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
RDI_PROC void
|
||||
rdi_parsed_from_source_line_map(RDI_Parsed *rdi, RDI_SourceLineMap *map, RDI_ParsedSourceLineMap *out)
|
||||
{
|
||||
//- rjf: extract top-level line info tables
|
||||
RDI_U64 all_nums_count = 0;
|
||||
RDI_U32 *all_nums = rdi_table_from_name(rdi, SourceLineMapNumbers, &all_nums_count);
|
||||
RDI_U32 *all_nums_opl = all_nums + all_nums_count;
|
||||
RDI_U64 all_rngs_count = 0;
|
||||
RDI_U32 *all_rngs = rdi_table_from_name(rdi, SourceLineMapRanges, &all_rngs_count);
|
||||
RDI_U32 *all_rngs_opl = all_rngs + all_rngs_count;
|
||||
RDI_U64 all_voffs_count = 0;
|
||||
RDI_U64 *all_voffs = rdi_table_from_name(rdi, SourceLineMapVOffs, &all_voffs_count);
|
||||
RDI_U64 *all_voffs_opl = all_voffs + all_voffs_count;
|
||||
|
||||
//- rjf: extract ranges of top-level tables belonging to this line map
|
||||
RDI_U32 *map_nums = all_nums + map->line_map_nums_base_idx;
|
||||
RDI_U32 *map_rngs = all_rngs + map->line_map_range_base_idx;
|
||||
RDI_U64 *map_voffs= all_voffs+ map->line_map_voff_base_idx;
|
||||
RDI_U64 lines_count = (RDI_U64)map->line_count;
|
||||
RDI_U64 voffs_count = (RDI_U64)map->voff_count;
|
||||
if(map_nums >= all_nums_opl) {map_nums = all_nums; lines_count = 0;}
|
||||
if(map_rngs >= all_rngs_opl) {map_rngs = all_rngs; lines_count = 0;}
|
||||
if(map_voffs>= all_voffs_opl){map_voffs= all_voffs;voffs_count = 0;}
|
||||
|
||||
//- rjf: fill result
|
||||
out->nums = map_nums;
|
||||
out->ranges = map_rngs;
|
||||
out->voffs = map_voffs;
|
||||
out->count = lines_count;
|
||||
out->voff_count = voffs_count;
|
||||
}
|
||||
|
||||
RDI_PROC RDI_U64 *
|
||||
rdi_line_voffs_from_num(RDI_ParsedSourceLineMap *map, RDI_U32 linenum, RDI_U32 *n_out)
|
||||
{
|
||||
RDI_U64 *result = 0;
|
||||
*n_out = 0;
|
||||
RDI_U32 closest_i = 0;
|
||||
if(map->count > 0 && map->nums[0] <= linenum)
|
||||
{
|
||||
// assuming: (i < j) -> (nums[i] < nums[j])
|
||||
// find i such that: (nums[i] <= linenum) && (linenum < nums[i + 1])
|
||||
RDI_U32 *nums = map->nums;
|
||||
RDI_U32 first = 0;
|
||||
RDI_U32 opl = map->count;
|
||||
for(;;)
|
||||
{
|
||||
RDI_U32 mid = (first + opl)/2;
|
||||
if(nums[mid] < linenum)
|
||||
{
|
||||
first = mid;
|
||||
}
|
||||
else if(nums[mid] > linenum)
|
||||
{
|
||||
opl = mid;
|
||||
}
|
||||
else
|
||||
{
|
||||
first = mid;
|
||||
break;
|
||||
}
|
||||
if(opl - first <= 1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
closest_i = first;
|
||||
}
|
||||
|
||||
// round up instead of down if possible
|
||||
if(closest_i + 1 < map->count && map->nums[closest_i] < linenum)
|
||||
{
|
||||
closest_i += 1;
|
||||
}
|
||||
|
||||
// set result if possible
|
||||
if(closest_i < map->count)
|
||||
{
|
||||
RDI_U32 first = map->ranges[closest_i];
|
||||
RDI_U32 opl = map->ranges[closest_i + 1];
|
||||
if(opl <= map->voff_count)
|
||||
{
|
||||
result = map->voffs + first;
|
||||
*n_out = opl - first;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//- vmap lookups
|
||||
|
||||
RDI_PROC RDI_U64
|
||||
rdi_vmap_idx_from_voff(RDI_VMapEntry *vmap, RDI_U64 vmap_count, RDI_U64 voff)
|
||||
{
|
||||
RDI_U64 result = 0;
|
||||
if(vmap_count > 0 && vmap[0].voff <= voff && voff < vmap[vmap_count - 1].voff)
|
||||
{
|
||||
// assuming: (i < j) -> (vmap[i].voff < vmap[j].voff)
|
||||
// find i such that: (vmap[i].voff <= voff) && (voff < vmap[i + 1].voff)
|
||||
RDI_U32 first = 0;
|
||||
RDI_U32 opl = vmap_count;
|
||||
for(;;)
|
||||
{
|
||||
RDI_U32 mid = (first + opl)/2;
|
||||
if(vmap[mid].voff < voff)
|
||||
{
|
||||
first = mid;
|
||||
}
|
||||
else if(vmap[mid].voff > voff)
|
||||
{
|
||||
opl = mid;
|
||||
}
|
||||
else
|
||||
{
|
||||
first = mid;
|
||||
break;
|
||||
}
|
||||
if(opl - first <= 1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
result = (RDI_U64)vmap[first].idx;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
RDI_PROC RDI_U64
|
||||
rdi_vmap_idx_from_section_kind_voff(RDI_Parsed *rdi, RDI_SectionKind kind, RDI_U64 voff)
|
||||
{
|
||||
RDI_U64 vmaps_count = 0;
|
||||
RDI_VMapEntry *vmaps = rdi_section_raw_table_from_kind(rdi, kind, &vmaps_count);
|
||||
RDI_U64 result = rdi_vmap_idx_from_voff(vmaps, vmaps_count, voff);
|
||||
return result;
|
||||
}
|
||||
|
||||
//- name maps
|
||||
|
||||
RDI_PROC void
|
||||
rdi_parsed_from_name_map(RDI_Parsed *rdi, RDI_NameMap *mapptr, RDI_ParsedNameMap *out)
|
||||
{
|
||||
out->buckets = 0;
|
||||
out->bucket_count = 0;
|
||||
if(mapptr != 0)
|
||||
{
|
||||
RDI_U64 all_buckets_count = 0;
|
||||
RDI_NameMapBucket *all_buckets = rdi_table_from_name(rdi, NameMapBuckets, &all_buckets_count);
|
||||
RDI_U64 all_nodes_count = 0;
|
||||
RDI_NameMapNode *all_nodes = rdi_table_from_name(rdi, NameMapNodes, &all_nodes_count);
|
||||
out->buckets = all_buckets+mapptr->bucket_base_idx;
|
||||
out->nodes = all_nodes+mapptr->node_base_idx;
|
||||
out->bucket_count = mapptr->bucket_count;
|
||||
out->node_count = mapptr->node_count;
|
||||
if(mapptr->bucket_base_idx > all_buckets_count)
|
||||
{
|
||||
out->buckets = 0;
|
||||
out->bucket_count = 0;
|
||||
}
|
||||
if(mapptr->node_base_idx > all_nodes_count)
|
||||
{
|
||||
out->nodes = 0;
|
||||
out->node_count = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RDI_PROC RDI_NameMapNode*
|
||||
rdi_name_map_lookup(RDI_Parsed *p, RDI_ParsedNameMap *map, RDI_U8 *str, RDI_U64 len)
|
||||
{
|
||||
RDI_NameMapNode *result = 0;
|
||||
if(map->bucket_count > 0)
|
||||
{
|
||||
RDI_NameMapBucket *buckets = map->buckets;
|
||||
RDI_U64 bucket_count = map->bucket_count;
|
||||
RDI_U64 hash = rdi_hash(str, len);
|
||||
RDI_U64 bucket_index = hash%bucket_count;
|
||||
RDI_NameMapBucket *bucket = map->buckets + bucket_index;
|
||||
RDI_NameMapNode *node = map->nodes + bucket->first_node;
|
||||
RDI_NameMapNode *node_opl = node + bucket->node_count;
|
||||
for(;node < node_opl; node += 1)
|
||||
{
|
||||
// extract a string from this node
|
||||
RDI_U64 nlen = 0;
|
||||
RDI_U8 *nstr = rdi_string_from_idx(p, node->string_idx, &nlen);
|
||||
|
||||
// compare this to the needle string
|
||||
RDI_S32 match = 0;
|
||||
if(nlen == len)
|
||||
{
|
||||
RDI_U8 *a = str;
|
||||
RDI_U8 *aopl = str + len;
|
||||
RDI_U8 *b = nstr;
|
||||
for (;a < aopl && *a == *b; a += 1, b += 1);
|
||||
match = (a == aopl);
|
||||
}
|
||||
|
||||
// stop with a matching node in result
|
||||
if(match)
|
||||
{
|
||||
result = node;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
RDI_PROC RDI_U32*
|
||||
rdi_matches_from_map_node(RDI_Parsed *p, RDI_NameMapNode *node, RDI_U32 *n_out)
|
||||
{
|
||||
RDI_U32 *result = 0;
|
||||
*n_out = 0;
|
||||
if(node != 0)
|
||||
{
|
||||
if(node->match_count == 1)
|
||||
{
|
||||
result = &node->match_idx_or_idx_run_first;
|
||||
*n_out = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = rdi_idx_run_from_first_count(p, node->match_idx_or_idx_run_first, node->match_count, n_out);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ High-Level Composite Lookup Functions
|
||||
|
||||
//- procedures
|
||||
|
||||
RDI_PROC RDI_Procedure *
|
||||
rdi_procedure_from_name(RDI_Parsed *rdi, RDI_U8 *name, RDI_U64 name_size)
|
||||
{
|
||||
RDI_NameMap *map = rdi_element_from_name_idx(rdi, NameMaps, RDI_NameMapKind_Procedures);
|
||||
RDI_ParsedNameMap map_parsed = {0};
|
||||
rdi_parsed_from_name_map(rdi, map, &map_parsed);
|
||||
RDI_NameMapNode *node = rdi_name_map_lookup(rdi, &map_parsed, name, name_size);
|
||||
RDI_U32 id_count = 0;
|
||||
RDI_U32 *ids = rdi_matches_from_map_node(rdi, node, &id_count);
|
||||
RDI_U32 procedure_idx = 0;
|
||||
if(id_count > 0)
|
||||
{
|
||||
procedure_idx = ids[0];
|
||||
}
|
||||
RDI_Procedure *procedure = rdi_element_from_name_idx(rdi, Procedures, procedure_idx);
|
||||
return procedure;
|
||||
}
|
||||
|
||||
RDI_PROC RDI_Procedure *
|
||||
rdi_procedure_from_name_cstr(RDI_Parsed *rdi, char *cstr)
|
||||
{
|
||||
RDI_Procedure *result = rdi_procedure_from_name(rdi, (RDI_U8 *)cstr, rdi_cstring_length(cstr));
|
||||
return result;
|
||||
}
|
||||
|
||||
RDI_PROC RDI_U8 *
|
||||
rdi_name_from_procedure(RDI_Parsed *rdi, RDI_Procedure *procedure, RDI_U64 *len_out)
|
||||
{
|
||||
return rdi_string_from_idx(rdi, procedure->name_string_idx, len_out);
|
||||
}
|
||||
|
||||
RDI_PROC RDI_Scope *
|
||||
rdi_root_scope_from_procedure(RDI_Parsed *rdi, RDI_Procedure *procedure)
|
||||
{
|
||||
RDI_Scope *scope = rdi_element_from_name_idx(rdi, Scopes, procedure->root_scope_idx);
|
||||
return scope;
|
||||
}
|
||||
|
||||
RDI_PROC RDI_UDT *
|
||||
rdi_container_udt_from_procedure(RDI_Parsed *rdi, RDI_Procedure *procedure)
|
||||
{
|
||||
RDI_U64 idx = 0;
|
||||
if(procedure->link_flags & RDI_LinkFlag_TypeScoped)
|
||||
{
|
||||
idx = procedure->container_idx;
|
||||
}
|
||||
RDI_UDT *udt = rdi_element_from_name_idx(rdi, UDTs, idx);
|
||||
return udt;
|
||||
}
|
||||
|
||||
RDI_PROC RDI_Procedure *
|
||||
rdi_container_procedure_from_procedure(RDI_Parsed *rdi, RDI_Procedure *procedure)
|
||||
{
|
||||
RDI_U64 idx = 0;
|
||||
if(procedure->link_flags & RDI_LinkFlag_ProcScoped)
|
||||
{
|
||||
idx = procedure->container_idx;
|
||||
}
|
||||
RDI_Procedure *container_procedure = rdi_element_from_name_idx(rdi, Procedures, idx);
|
||||
return container_procedure;
|
||||
}
|
||||
|
||||
RDI_PROC RDI_U64
|
||||
rdi_first_voff_from_procedure(RDI_Parsed *rdi, RDI_Procedure *procedure)
|
||||
{
|
||||
RDI_Scope *scope = rdi_root_scope_from_procedure(rdi, procedure);
|
||||
RDI_U64 result = rdi_first_voff_from_scope(rdi, scope);
|
||||
return result;
|
||||
}
|
||||
|
||||
RDI_PROC RDI_U64
|
||||
rdi_opl_voff_from_procedure(RDI_Parsed *rdi, RDI_Procedure *procedure)
|
||||
{
|
||||
RDI_Scope *scope = rdi_root_scope_from_procedure(rdi, procedure);
|
||||
RDI_U64 result = rdi_opl_voff_from_scope(rdi, scope);
|
||||
return result;
|
||||
}
|
||||
|
||||
RDI_PROC RDI_Procedure *
|
||||
rdi_procedure_from_voff(RDI_Parsed *rdi, RDI_U64 voff)
|
||||
{
|
||||
RDI_Scope *scope = rdi_scope_from_voff(rdi, voff);
|
||||
RDI_Procedure *procedure = rdi_procedure_from_scope(rdi, scope);
|
||||
return procedure;
|
||||
}
|
||||
|
||||
//- scopes
|
||||
|
||||
RDI_PROC RDI_U64
|
||||
rdi_first_voff_from_scope(RDI_Parsed *rdi, RDI_Scope *scope)
|
||||
{
|
||||
RDI_U64 *voffs = rdi_element_from_name_idx(rdi, ScopeVOffData, scope->voff_range_first);
|
||||
RDI_U64 result = *voffs;
|
||||
return result;
|
||||
}
|
||||
|
||||
RDI_PROC RDI_U64
|
||||
rdi_opl_voff_from_scope(RDI_Parsed *rdi, RDI_Scope *scope)
|
||||
{
|
||||
RDI_U64 result = 0;
|
||||
if(scope->voff_range_opl != 0)
|
||||
{
|
||||
RDI_U64 *voffs = rdi_element_from_name_idx(rdi, ScopeVOffData, scope->voff_range_opl-1);
|
||||
result = *voffs;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
RDI_PROC RDI_Scope *
|
||||
rdi_scope_from_voff(RDI_Parsed *rdi, RDI_U64 voff)
|
||||
{
|
||||
RDI_U32 idx = rdi_vmap_idx_from_section_kind_voff(rdi, RDI_SectionKind_ScopeVMap, voff);
|
||||
RDI_Scope *scope = rdi_element_from_name_idx(rdi, Scopes, idx);
|
||||
return scope;
|
||||
}
|
||||
|
||||
RDI_PROC RDI_Scope *
|
||||
rdi_parent_from_scope(RDI_Parsed *rdi, RDI_Scope *scope)
|
||||
{
|
||||
RDI_Scope *parent = rdi_element_from_name_idx(rdi, Scopes, scope->parent_scope_idx);
|
||||
return parent;
|
||||
}
|
||||
|
||||
RDI_PROC RDI_Procedure *
|
||||
rdi_procedure_from_scope(RDI_Parsed *rdi, RDI_Scope *scope)
|
||||
{
|
||||
RDI_Procedure *procedure = rdi_element_from_name_idx(rdi, Procedures, scope->proc_idx);
|
||||
return procedure;
|
||||
}
|
||||
|
||||
RDI_PROC RDI_InlineSite *
|
||||
rdi_inline_site_from_scope(RDI_Parsed *rdi, RDI_Scope *scope)
|
||||
{
|
||||
RDI_InlineSite *inline_site = rdi_element_from_name_idx(rdi, InlineSites, scope->inline_site_idx);
|
||||
return inline_site;
|
||||
}
|
||||
|
||||
//- global variables
|
||||
|
||||
RDI_PROC RDI_GlobalVariable *
|
||||
rdi_global_variable_from_voff(RDI_Parsed *rdi, RDI_U64 voff)
|
||||
{
|
||||
RDI_U32 idx = rdi_vmap_idx_from_section_kind_voff(rdi, RDI_SectionKind_GlobalVMap, voff);
|
||||
RDI_GlobalVariable *gvar = rdi_element_from_name_idx(rdi, GlobalVariables, idx);
|
||||
return gvar;
|
||||
}
|
||||
|
||||
//- units
|
||||
|
||||
RDI_PROC RDI_Unit *
|
||||
rdi_unit_from_voff(RDI_Parsed *rdi, RDI_U64 voff)
|
||||
{
|
||||
RDI_U32 unit_idx = rdi_vmap_idx_from_section_kind_voff(rdi, RDI_SectionKind_UnitVMap, voff);
|
||||
RDI_Unit *unit = rdi_element_from_name_idx(rdi, Units, unit_idx);
|
||||
return unit;
|
||||
}
|
||||
|
||||
RDI_PROC RDI_LineTable *
|
||||
rdi_line_table_from_unit(RDI_Parsed *rdi, RDI_Unit *unit)
|
||||
{
|
||||
RDI_LineTable *line_table = rdi_element_from_name_idx(rdi, LineTables, unit->line_table_idx);
|
||||
return line_table;
|
||||
}
|
||||
|
||||
//- line info
|
||||
|
||||
RDI_PROC RDI_Line
|
||||
rdi_line_from_voff(RDI_Parsed *rdi, RDI_U64 voff)
|
||||
{
|
||||
RDI_Unit *unit = rdi_unit_from_voff(rdi, voff);
|
||||
RDI_LineTable *line_table = rdi_line_table_from_unit(rdi, unit);
|
||||
RDI_Line line = rdi_line_from_line_table_voff(rdi, line_table, voff);
|
||||
return line;
|
||||
}
|
||||
|
||||
RDI_PROC RDI_Line
|
||||
rdi_line_from_line_table_voff(RDI_Parsed *rdi, RDI_LineTable *line_table, RDI_U64 voff)
|
||||
{
|
||||
RDI_ParsedLineTable parsed = {0};
|
||||
rdi_parsed_from_line_table(rdi, line_table, &parsed);
|
||||
RDI_U64 line_info_idx = rdi_line_info_idx_from_voff(&parsed, voff);
|
||||
RDI_Line result = {0};
|
||||
if(line_info_idx < parsed.count)
|
||||
{
|
||||
result = parsed.lines[line_info_idx];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
RDI_PROC RDI_SourceFile *
|
||||
rdi_source_file_from_line(RDI_Parsed *rdi, RDI_Line *line)
|
||||
{
|
||||
RDI_SourceFile *result = rdi_element_from_name_idx(rdi, SourceFiles, line->file_idx);
|
||||
return result;
|
||||
}
|
||||
|
||||
//- source files
|
||||
|
||||
RDI_PROC RDI_SourceFile *
|
||||
rdi_source_file_from_normal_path(RDI_Parsed *rdi, RDI_U8 *name, RDI_U64 name_size)
|
||||
{
|
||||
RDI_NameMap *map = rdi_element_from_name_idx(rdi, NameMaps, RDI_NameMapKind_NormalSourcePaths);
|
||||
RDI_ParsedNameMap map_parsed = {0};
|
||||
rdi_parsed_from_name_map(rdi, map, &map_parsed);
|
||||
RDI_NameMapNode *node = rdi_name_map_lookup(rdi, &map_parsed, name, name_size);
|
||||
RDI_U32 id_count = 0;
|
||||
RDI_U32 *ids = rdi_matches_from_map_node(rdi, node, &id_count);
|
||||
RDI_U32 file_idx = 0;
|
||||
if(id_count > 0)
|
||||
{
|
||||
file_idx = ids[0];
|
||||
}
|
||||
RDI_SourceFile *file = rdi_element_from_name_idx(rdi, SourceFiles, file_idx);
|
||||
return file;
|
||||
}
|
||||
|
||||
RDI_PROC RDI_SourceFile *
|
||||
rdi_source_file_from_normal_path_cstr(RDI_Parsed *rdi, char *cstr)
|
||||
{
|
||||
RDI_SourceFile *result = rdi_source_file_from_normal_path(rdi, (RDI_U8 *)cstr, rdi_cstring_length(cstr));
|
||||
return result;
|
||||
}
|
||||
|
||||
RDI_PROC RDI_U8 *
|
||||
rdi_normal_path_from_source_file(RDI_Parsed *rdi, RDI_SourceFile *src_file, RDI_U64 *len_out)
|
||||
{
|
||||
return rdi_string_from_idx(rdi, src_file->normal_full_path_string_idx, len_out);
|
||||
}
|
||||
|
||||
RDI_PROC RDI_FilePathNode *
|
||||
rdi_file_path_node_from_source_file(RDI_Parsed *rdi, RDI_SourceFile *src_file)
|
||||
{
|
||||
RDI_FilePathNode *result = rdi_element_from_name_idx(rdi, FilePathNodes, src_file->file_path_node_idx);
|
||||
return result;
|
||||
}
|
||||
|
||||
RDI_PROC RDI_SourceLineMap *
|
||||
rdi_source_line_map_from_source_file(RDI_Parsed *rdi, RDI_SourceFile *src_file)
|
||||
{
|
||||
RDI_SourceLineMap *result = rdi_element_from_name_idx(rdi, SourceLineMaps, src_file->source_line_map_idx);
|
||||
return result;
|
||||
}
|
||||
|
||||
RDI_PROC RDI_U64
|
||||
rdi_first_voff_from_source_file_line_num(RDI_Parsed *rdi, RDI_SourceFile *src_file, RDI_U32 line_num)
|
||||
{
|
||||
RDI_SourceLineMap *source_line_map = rdi_source_line_map_from_source_file(rdi, src_file);
|
||||
RDI_U64 voff = rdi_first_voff_from_source_line_map_num(rdi, source_line_map, line_num);
|
||||
return voff;
|
||||
}
|
||||
|
||||
//- source line maps
|
||||
|
||||
RDI_PROC RDI_U64
|
||||
rdi_first_voff_from_source_line_map_num(RDI_Parsed *rdi, RDI_SourceLineMap *map, RDI_U32 line_num)
|
||||
{
|
||||
RDI_ParsedSourceLineMap parsed = {0};
|
||||
rdi_parsed_from_source_line_map(rdi, map, &parsed);
|
||||
RDI_U32 all_voffs_count = 0;
|
||||
RDI_U64 *all_voffs = rdi_line_voffs_from_num(&parsed, line_num, &all_voffs_count);
|
||||
RDI_U64 voff = 0;
|
||||
if(all_voffs_count != 0)
|
||||
{
|
||||
voff = all_voffs[0];
|
||||
}
|
||||
return voff;
|
||||
}
|
||||
|
||||
//- file path nodes
|
||||
|
||||
RDI_PROC RDI_FilePathNode *
|
||||
rdi_parent_from_file_path_node(RDI_Parsed *rdi, RDI_FilePathNode *node)
|
||||
{
|
||||
RDI_FilePathNode *result = rdi_element_from_name_idx(rdi, FilePathNodes, node->parent_path_node);
|
||||
return result;
|
||||
}
|
||||
|
||||
RDI_PROC RDI_U8 *
|
||||
rdi_name_from_file_path_node(RDI_Parsed *rdi, RDI_FilePathNode *node, RDI_U64 *len_out)
|
||||
{
|
||||
return rdi_string_from_idx(rdi, node->name_string_idx, len_out);
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ Parser Helpers
|
||||
|
||||
RDI_PROC RDI_U64
|
||||
rdi_cstring_length(char *cstr)
|
||||
{
|
||||
RDI_U64 result = 0;
|
||||
for(;cstr[result] != 0; result += 1){}
|
||||
return result;
|
||||
}
|
||||
|
||||
RDI_PROC RDI_U64
|
||||
rdi_size_from_bytecode_stream(RDI_U8 *ptr, RDI_U8 *opl)
|
||||
{
|
||||
RDI_U64 bytecode_size = 0;
|
||||
RDI_U8 *off_first = ptr + sizeof(RDI_LocationKind);
|
||||
for(RDI_U8 *off = off_first, *next_off = opl; off < opl; off = next_off)
|
||||
{
|
||||
RDI_U8 op = *off;
|
||||
if(op == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
RDI_U16 ctrlbits = rdi_eval_op_ctrlbits_table[op];
|
||||
RDI_U32 p_size = RDI_DECODEN_FROM_CTRLBITS(ctrlbits);
|
||||
bytecode_size += (1 + p_size);
|
||||
next_off = (off + 1 + p_size);
|
||||
}
|
||||
return bytecode_size;
|
||||
}
|
||||
+34
-49
@@ -196,6 +196,21 @@ rdim_str8_match(RDIM_String8 a, RDIM_String8 b, RDIM_StringMatchFlags flags)
|
||||
return result;
|
||||
}
|
||||
|
||||
RDI_PROC RDIM_String8
|
||||
rdim_lower_from_str8(RDIM_Arena *arena, RDIM_String8 string)
|
||||
{
|
||||
RDIM_String8 result = rdim_str8_copy(arena, string);
|
||||
for(RDI_U64 idx = 0; idx < result.RDIM_String8_SizeMember; idx += 1)
|
||||
{
|
||||
RDI_U8 byte = result.RDIM_String8_BaseMember[idx];
|
||||
if('A' <= byte && byte <= 'Z')
|
||||
{
|
||||
result.RDIM_String8_BaseMember[idx] += ('a' - 'A');
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//- rjf: string lists
|
||||
|
||||
RDI_PROC void
|
||||
@@ -464,7 +479,7 @@ rdim_rng1u64_chunk_list_push(RDIM_Arena *arena, RDIM_Rng1U64ChunkList *list, RDI
|
||||
//~ Data Model
|
||||
|
||||
RDI_PROC RDI_TypeKind
|
||||
rdim_short_type_from_data_model(RDIM_DataModel data_model)
|
||||
rdim_short_type_kind_from_data_model(RDIM_DataModel data_model)
|
||||
{
|
||||
switch(data_model)
|
||||
{
|
||||
@@ -480,7 +495,7 @@ rdim_short_type_from_data_model(RDIM_DataModel data_model)
|
||||
}
|
||||
|
||||
RDI_PROC RDI_TypeKind
|
||||
rdim_unsigned_short_type_from_data_model(RDIM_DataModel data_model)
|
||||
rdim_unsigned_short_type_kind_from_data_model(RDIM_DataModel data_model)
|
||||
{
|
||||
switch(data_model)
|
||||
{
|
||||
@@ -528,7 +543,7 @@ rdim_unsigned_int_type_from_data_model(RDIM_DataModel data_model)
|
||||
}
|
||||
|
||||
RDI_PROC RDI_TypeKind
|
||||
rdim_long_type_from_data_model(RDIM_DataModel data_model)
|
||||
rdim_long_type_kind_from_data_model(RDIM_DataModel data_model)
|
||||
{
|
||||
switch(data_model)
|
||||
{
|
||||
@@ -544,7 +559,7 @@ rdim_long_type_from_data_model(RDIM_DataModel data_model)
|
||||
}
|
||||
|
||||
RDI_PROC RDI_TypeKind
|
||||
rdim_unsigned_long_type_from_data_model(RDIM_DataModel data_model)
|
||||
rdim_unsigned_long_type_kind_from_data_model(RDIM_DataModel data_model)
|
||||
{
|
||||
switch(data_model)
|
||||
{
|
||||
@@ -560,7 +575,7 @@ rdim_unsigned_long_type_from_data_model(RDIM_DataModel data_model)
|
||||
}
|
||||
|
||||
RDI_PROC RDI_TypeKind
|
||||
rdim_long_long_type_from_data_model(RDIM_DataModel data_model)
|
||||
rdim_long_long_type_kind_from_data_model(RDIM_DataModel data_model)
|
||||
{
|
||||
switch(data_model)
|
||||
{
|
||||
@@ -576,7 +591,7 @@ rdim_long_long_type_from_data_model(RDIM_DataModel data_model)
|
||||
}
|
||||
|
||||
RDI_PROC RDI_TypeKind
|
||||
rdim_unsigned_long_long_type_from_data_model(RDIM_DataModel data_model)
|
||||
rdim_unsigned_long_long_type_kind_from_data_model(RDIM_DataModel data_model)
|
||||
{
|
||||
switch(data_model)
|
||||
{
|
||||
@@ -592,7 +607,7 @@ rdim_unsigned_long_long_type_from_data_model(RDIM_DataModel data_model)
|
||||
}
|
||||
|
||||
RDI_PROC RDI_TypeKind
|
||||
rdim_pointer_size_t_type_from_data_model(RDIM_DataModel data_model)
|
||||
rdim_pointer_size_t_type_kind_from_data_model(RDIM_DataModel data_model)
|
||||
{
|
||||
switch(data_model)
|
||||
{
|
||||
@@ -1331,41 +1346,6 @@ rdim_count_from_location_block_chunk_list(RDIM_String8List *list)
|
||||
return count;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
RDI_PROC RDIM_Type *
|
||||
rdim_builtin_type_from_kind(RDIM_TypeChunkList list, RDI_TypeKind type_kind)
|
||||
{
|
||||
return &list.first->v[type_kind];
|
||||
}
|
||||
|
||||
RDI_PROC RDIM_TypeChunkList
|
||||
rdim_init_type_chunk_list(RDIM_Arena *arena, RDI_Arch arch)
|
||||
{
|
||||
RDIM_TypeChunkList list = {0};
|
||||
|
||||
RDI_U64 type_cap = (RDI_TypeKind_LastBuiltIn - RDI_TypeKind_FirstBuiltIn) + 2;
|
||||
|
||||
// RDI_TypeKind_NULL
|
||||
rdim_type_chunk_list_push(arena, &list, type_cap);
|
||||
|
||||
for(RDI_TypeKind type_kind = RDI_TypeKind_FirstBuiltIn; type_kind <= RDI_TypeKind_LastBuiltIn; type_kind += 1)
|
||||
{
|
||||
RDIM_Type *type = rdim_type_chunk_list_push(arena, &list, type_cap);
|
||||
type->name.str = rdi_string_from_type_kind(type_kind, &type->name.size);
|
||||
type->kind = type_kind;
|
||||
type->byte_size = rdi_size_from_basic_type_kind(type_kind);
|
||||
}
|
||||
|
||||
RDIM_Type *void_type = rdim_builtin_type_from_kind(list, RDI_TypeKind_Void);
|
||||
void_type->byte_size = rdi_addr_size_from_arch(arch);
|
||||
|
||||
RDIM_Type *handle_type = rdim_builtin_type_from_kind(list, RDI_TypeKind_Handle);
|
||||
handle_type->byte_size = rdi_addr_size_from_arch(arch);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: [Baking Helpers] Baked VMap Building
|
||||
|
||||
@@ -1949,7 +1929,7 @@ rdim_bake_path_node_from_string(RDIM_BakePathTree *tree, RDIM_String8 string)
|
||||
RDIM_BakePathNode *sub_dir_node = 0;
|
||||
for(RDIM_BakePathNode *child = node->first_child; child != 0; child = child->next_sibling)
|
||||
{
|
||||
if(rdim_str8_match(child->name, sub_dir, RDIM_StringMatchFlag_CaseInsensitive))
|
||||
if(rdim_str8_match(child->name, sub_dir, 0))
|
||||
{
|
||||
sub_dir_node = child;
|
||||
}
|
||||
@@ -2022,7 +2002,7 @@ rdim_bake_path_tree_insert(RDIM_Arena *arena, RDIM_BakePathTree *tree, RDIM_Stri
|
||||
RDIM_BakePathNode *sub_dir_node = 0;
|
||||
for(RDIM_BakePathNode *child = node->first_child; child != 0; child = child->next_sibling)
|
||||
{
|
||||
if(rdim_str8_match(child->name, sub_dir, RDIM_StringMatchFlag_CaseInsensitive))
|
||||
if(rdim_str8_match(child->name, sub_dir, 0))
|
||||
{
|
||||
sub_dir_node = child;
|
||||
}
|
||||
@@ -2210,7 +2190,8 @@ rdim_bake_string_map_loose_push_src_file_slice(RDIM_Arena *arena, RDIM_BakeStrin
|
||||
{
|
||||
for(RDI_U64 idx = 0; idx < count; idx += 1)
|
||||
{
|
||||
rdim_bake_string_map_loose_insert(arena, top, map, 1, v[idx].normal_full_path);
|
||||
RDIM_String8 normalized_path = rdim_lower_from_str8(arena, v[idx].path);
|
||||
rdim_bake_string_map_loose_insert(arena, top, map, 1, normalized_path);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2438,7 +2419,8 @@ rdim_bake_name_map_from_kind_params(RDIM_Arena *arena, RDI_NameMapKind kind, RDI
|
||||
for(RDI_U64 idx = 0; idx < n->count; idx += 1)
|
||||
{
|
||||
RDI_U64 src_file_idx = rdim_idx_from_src_file(&n->v[idx]);
|
||||
rdim_bake_name_map_push(arena, map, n->v[idx].normal_full_path, (RDI_U32)src_file_idx); // TODO(rjf): @u64_to_u32
|
||||
RDIM_String8 normalized_path = rdim_lower_from_str8(arena, n->v[idx].path);
|
||||
rdim_bake_name_map_push(arena, map, normalized_path, (RDI_U32)src_file_idx); // TODO(rjf): @u64_to_u32
|
||||
}
|
||||
}
|
||||
}break;
|
||||
@@ -2545,7 +2527,7 @@ rdim_bake_path_tree_from_params(RDIM_Arena *arena, RDIM_BakeParams *params)
|
||||
{
|
||||
for(RDI_U64 idx = 0; idx < n->count; idx += 1)
|
||||
{
|
||||
RDIM_BakePathNode *node = rdim_bake_path_tree_insert(arena, tree, n->v[idx].normal_full_path);
|
||||
RDIM_BakePathNode *node = rdim_bake_path_tree_insert(arena, tree, n->v[idx].path);
|
||||
node->src_file = &n->v[idx];
|
||||
}
|
||||
}
|
||||
@@ -3056,9 +3038,12 @@ rdim_bake_src_files(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_Ba
|
||||
////////////////////////
|
||||
//- rjf: fill file info
|
||||
//
|
||||
dst_file->file_path_node_idx = rdim_bake_path_node_idx_from_string(path_tree, src_file->normal_full_path);
|
||||
dst_file->normal_full_path_string_idx = rdim_bake_idx_from_string(strings, src_file->normal_full_path);
|
||||
RDI_U64 scratch_pos_restore = rdim_arena_pos(scratch.arena);
|
||||
RDIM_String8 normalized_path = rdim_lower_from_str8(scratch.arena, src_file->path);
|
||||
dst_file->file_path_node_idx = rdim_bake_path_node_idx_from_string(path_tree, src_file->path);
|
||||
dst_file->normal_full_path_string_idx = rdim_bake_idx_from_string(strings, normalized_path);
|
||||
dst_file->source_line_map_idx = (RDI_U32)(dst_map ? (dst_map - dst_maps) : 0);
|
||||
rdim_arena_pop_to(scratch.arena, scratch_pos_restore);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+10
-14
@@ -535,7 +535,7 @@ typedef struct RDIM_SrcFile RDIM_SrcFile;
|
||||
struct RDIM_SrcFile
|
||||
{
|
||||
struct RDIM_SrcFileChunkNode *chunk;
|
||||
RDIM_String8 normal_full_path;
|
||||
RDIM_String8 path;
|
||||
RDIM_SrcFileLineMapFragment *first_line_map_fragment;
|
||||
RDIM_SrcFileLineMapFragment *last_line_map_fragment;
|
||||
};
|
||||
@@ -1411,6 +1411,7 @@ RDI_PROC RDI_S32 rdim_str8_match(RDIM_String8 a, RDIM_String8 b, RDIM_StringMatc
|
||||
#define rdim_str8_lit(S) rdim_str8((RDI_U8*)(S), sizeof(S) - 1)
|
||||
#define rdim_str8_struct(S) rdim_str8((RDI_U8*)(S), sizeof(*(S)))
|
||||
#define rdim_str8_struct_array(S, C) rdim_str8((RDI_U8*)(S), sizeof(*(S)) * (C))
|
||||
RDI_PROC RDIM_String8 rdim_lower_from_str8(RDIM_Arena *arena, RDIM_String8 string);
|
||||
|
||||
//- rjf: string lists
|
||||
RDI_PROC void rdim_str8_list_push(RDIM_Arena *arena, RDIM_String8List *list, RDIM_String8 string);
|
||||
@@ -1428,15 +1429,15 @@ RDI_PROC void rdim_rng1u64_chunk_list_push(RDIM_Arena *arena, RDIM_Rng1U64ChunkL
|
||||
////////////////////////////////
|
||||
//~ Data Model
|
||||
|
||||
RDI_PROC RDI_TypeKind rdim_short_type_from_data_model(RDIM_DataModel data_model);
|
||||
RDI_PROC RDI_TypeKind rdim_unsigned_short_type_from_data_model(RDIM_DataModel data_model);
|
||||
RDI_PROC RDI_TypeKind rdim_short_type_kind_from_data_model(RDIM_DataModel data_model);
|
||||
RDI_PROC RDI_TypeKind rdim_unsigned_short_type_kind_from_data_model(RDIM_DataModel data_model);
|
||||
RDI_PROC RDI_TypeKind rdim_int_type_from_data_model(RDIM_DataModel data_model);
|
||||
RDI_PROC RDI_TypeKind rdim_unsigned_int_type_from_data_model(RDIM_DataModel data_model);
|
||||
RDI_PROC RDI_TypeKind rdim_long_type_from_data_model(RDIM_DataModel data_model);
|
||||
RDI_PROC RDI_TypeKind rdim_unsigned_long_type_from_data_model(RDIM_DataModel data_model);
|
||||
RDI_PROC RDI_TypeKind rdim_long_long_type_from_data_model(RDIM_DataModel data_model);
|
||||
RDI_PROC RDI_TypeKind rdim_unsigned_long_long_type_from_data_model(RDIM_DataModel data_model);
|
||||
RDI_PROC RDI_TypeKind rdim_pointer_size_t_type_from_data_model(RDIM_DataModel data_model);
|
||||
RDI_PROC RDI_TypeKind rdim_long_type_kind_from_data_model(RDIM_DataModel data_model);
|
||||
RDI_PROC RDI_TypeKind rdim_unsigned_long_type_kind_from_data_model(RDIM_DataModel data_model);
|
||||
RDI_PROC RDI_TypeKind rdim_long_long_type_kind_from_data_model(RDIM_DataModel data_model);
|
||||
RDI_PROC RDI_TypeKind rdim_unsigned_long_long_type_kind_from_data_model(RDIM_DataModel data_model);
|
||||
RDI_PROC RDI_TypeKind rdim_pointer_size_t_type_kind_from_data_model(RDIM_DataModel data_model);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: [Building] Binary Section Info Building
|
||||
@@ -1519,15 +1520,10 @@ RDI_PROC RDIM_Location *rdim_push_location_val_reg(RDIM_Arena *arena, RDI_U8 reg
|
||||
//- rjf: location sets
|
||||
RDI_PROC void rdim_location_set_push_case(RDIM_Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_LocationSet *locset, RDIM_Rng1U64 voff_range, RDIM_Location *location);
|
||||
|
||||
//- rjf:location block chunk list
|
||||
//- rjf: location block chunk list
|
||||
RDI_PROC RDI_LocationBlock *rdim_location_block_chunk_list_push_array(RDIM_Arena *arena, RDIM_String8List *list, RDI_U32 count);
|
||||
RDI_PROC RDI_U32 rdim_count_from_location_block_chunk_list(RDIM_String8List *list);
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
RDI_PROC RDIM_TypeChunkList rdim_init_type_chunk_list(RDIM_Arena *arena, RDI_Arch arch);
|
||||
RDI_PROC RDIM_Type * rdim_builtin_type_from_kind(RDIM_TypeChunkList list, RDI_TypeKind type_kind);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: [Baking Helpers] Baked VMap Building
|
||||
|
||||
|
||||
@@ -1,17 +1,6 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal String8
|
||||
push_cstr(Arena *arena, String8 str)
|
||||
{
|
||||
U64 buffer_size = str.size + 1;
|
||||
U8 *buffer = push_array_no_zero(arena, U8, buffer_size);
|
||||
MemoryCopy(buffer, str.str, str.size);
|
||||
buffer[str.size] = 0;
|
||||
String8 result = str8(buffer, buffer_size);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal U32 *
|
||||
push_u32(Arena *arena, U32 value)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal U64
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#pragma once
|
||||
|
||||
typedef struct U32Node
|
||||
{
|
||||
struct U32Node *next;
|
||||
U32 data;
|
||||
} U32Node;
|
||||
|
||||
typedef struct U64Node
|
||||
{
|
||||
struct U64Node *next;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal U32Array
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#if defined(__clang__)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#include "../third_party_ext/blake3/blake3_portable.c"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef BASE_BLAKE3_H
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal U16
|
||||
@@ -8,16 +8,12 @@ safe_cast_u16x(U64 x)
|
||||
return (U16)x;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal U64
|
||||
u128_mod64(U128 a, U64 b)
|
||||
{
|
||||
return a.u64[1] % b;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal Version
|
||||
make_version(U64 major, U64 minor)
|
||||
{
|
||||
@@ -45,8 +41,6 @@ version_compar(Version a, Version b)
|
||||
return cmp;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal ISectOff
|
||||
isect_off(U32 isect, U32 off)
|
||||
{
|
||||
@@ -54,8 +48,6 @@ isect_off(U32 isect, U32 off)
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal int
|
||||
u16_compar(const void *raw_a, const void *raw_b)
|
||||
{
|
||||
@@ -123,7 +115,6 @@ u64_compar_is_before(void *raw_a, void *raw_b)
|
||||
return is_before;
|
||||
}
|
||||
|
||||
|
||||
internal int
|
||||
u8_is_before(void *raw_a, void *raw_b)
|
||||
{
|
||||
@@ -212,8 +203,33 @@ pair_u64_compar_v1(const void *raw_a, const void *raw_b)
|
||||
return u64_compar(&a->v1, &b->v1);
|
||||
}
|
||||
|
||||
internal U64
|
||||
pair_u64_nearest_v0(PairU64 *arr, U64 count, U64 v)
|
||||
{
|
||||
U64 result = max_U64;
|
||||
|
||||
////////////////////////////////
|
||||
if (count > 1 && arr[0].v0 <= v && v < arr[count-1].v0) {
|
||||
U64 l = 0;
|
||||
U64 r = count - 1;
|
||||
for (; l <= r; ) {
|
||||
U64 m = l + (r - l) / 2;
|
||||
if (arr[m].v0 == v) {
|
||||
return m;
|
||||
} else if (arr[m].v0 < v) {
|
||||
l = m + 1;
|
||||
} else {
|
||||
r = m - 1;
|
||||
}
|
||||
}
|
||||
result = l;
|
||||
} else if (count == 1 && arr[0].v0 == v) {
|
||||
result = 0;
|
||||
} else if (count > 0 && v >= arr[count-1].v0) {
|
||||
result = count-1;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
internal void
|
||||
str8_list_concat_in_place_array(String8List *list, String8List *arr, U64 count)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal U32
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#pragma once
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user