mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-09-22 17:20:05 +00:00
Compare commits
157
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b99e10224f | ||
|
|
435f6c4ef6 | ||
|
|
b631d431fa | ||
|
|
2562d04fbf | ||
|
|
b52a008748 | ||
|
|
b16d930d13 | ||
|
|
26be351354 | ||
|
|
77b2172a85 | ||
|
|
f1c5c97a1b | ||
|
|
6be2792659 | ||
|
|
c42e7837ac | ||
|
|
fe657987d6 | ||
|
|
48c7bb788e | ||
|
|
080a001183 | ||
|
|
81c7c7a7c4 | ||
|
|
95fe497056 | ||
|
|
8994cb04bc | ||
|
|
ce90b63079 | ||
|
|
6cf9b82857 | ||
|
|
cefbd40e2c | ||
|
|
420f089fda | ||
|
|
ff45952f07 | ||
|
|
fa4f9621b0 | ||
|
|
4c0ebc851c | ||
|
|
5a79518dcb | ||
|
|
713cc2c693 | ||
|
|
dcec3c07d9 | ||
|
|
b03c1766c6 | ||
|
|
4278f7db1e | ||
|
|
ff90a90744 | ||
|
|
626665911d | ||
|
|
f09f059af2 | ||
|
|
e95afcd5aa | ||
|
|
a8b1805749 | ||
|
|
a8b2266fc0 | ||
|
|
bc446d8520 | ||
|
|
9808157f45 | ||
|
|
0ec6b8e8a8 | ||
|
|
3e0c150ccb | ||
|
|
fd1906b034 | ||
|
|
2bbf3ff987 | ||
|
|
880d7a4139 | ||
|
|
c6caec657d | ||
|
|
3d7fc6fce5 | ||
|
|
0d0951bf08 | ||
|
|
3a190ae2c3 | ||
|
|
420c2ec208 | ||
|
|
f9abd3efb9 | ||
|
|
5893ab94cb | ||
|
|
ff2e9df705 | ||
|
|
5aeee47f98 | ||
|
|
31f25d0fe7 | ||
|
|
bd4f82c8e8 | ||
|
|
680ea2ffdc | ||
|
|
f7d7f6633f | ||
|
|
04c1488cd4 | ||
|
|
5232ba298d | ||
|
|
65ada18d1d | ||
|
|
8e6a0ae4db | ||
|
|
e297460697 | ||
|
|
cf8c0e7442 | ||
|
|
776c8daa27 | ||
|
|
69b43c76d4 | ||
|
|
d114a0e961 | ||
|
|
d177e39a54 | ||
|
|
158dd742ad | ||
|
|
0773b6d282 | ||
|
|
15d43d7c99 | ||
|
|
7650a83d1e | ||
|
|
daeb08e79f | ||
|
|
ef5287d2a9 | ||
|
|
db04792073 | ||
|
|
4091373517 | ||
|
|
214be8c433 | ||
|
|
f807dc4785 | ||
|
|
0dd05169ee | ||
|
|
ce9d43a92e | ||
|
|
0886963d93 | ||
|
|
27cd7a21a3 | ||
|
|
7bb88f480e | ||
|
|
fad817fb9e | ||
|
|
1d42f1bd66 | ||
|
|
a5dd35b874 | ||
|
|
a89af7f6fd | ||
|
|
5a19ab9c31 | ||
|
|
e204fe28c1 | ||
|
|
d036eb9fc5 | ||
|
|
1621e504ce | ||
|
|
44b8c9e87c | ||
|
|
4a0e21d447 | ||
|
|
3cd32fa235 | ||
|
|
c3a672cd02 | ||
|
|
9ce0bc5dbf | ||
|
|
ffb21277e9 | ||
|
|
a40edbba51 | ||
|
|
c2855a9a46 | ||
|
|
61e7aaadeb | ||
|
|
5a0efe1261 | ||
|
|
6d55d21643 | ||
|
|
4164b30aac | ||
|
|
aded54c97f | ||
|
|
79bcbe4b39 | ||
|
|
86d9b792d8 | ||
|
|
f3a36ece13 | ||
|
|
c5d198e3e9 | ||
|
|
eba7500f73 | ||
|
|
339f43919c | ||
|
|
f3fbf10754 | ||
|
|
4a2e1dd8d0 | ||
|
|
ee65ea3692 | ||
|
|
baead67a99 | ||
|
|
e085dae636 | ||
|
|
eba6765541 | ||
|
|
002e479a2d | ||
|
|
8848080729 | ||
|
|
e1166abc63 | ||
|
|
6ffc065712 | ||
|
|
15b1ebcd21 | ||
|
|
37b27a9cff | ||
|
|
327fec3155 | ||
|
|
d0b97a3010 | ||
|
|
1b5321ad8e | ||
|
|
4769d0a8d4 | ||
|
|
41cddf96b8 | ||
|
|
100d3523d3 | ||
|
|
f0b1b46840 | ||
|
|
e9666e2edd | ||
|
|
8f932bdbf7 | ||
|
|
c3c9539f9b | ||
|
|
13341a458a | ||
|
|
62659c5161 | ||
|
|
1ecabff7b6 | ||
|
|
45f5a2d18f | ||
|
|
bcd16a4f29 | ||
|
|
6d7858d445 | ||
|
|
c67f1a8b4a | ||
|
|
340396f9f7 | ||
|
|
eb6aabe2d1 | ||
|
|
9ec7fb61ed | ||
|
|
dcffefd0c6 | ||
|
|
5be2b5dfd9 | ||
|
|
7260baea85 | ||
|
|
a802f2186b | ||
|
|
a43678e311 | ||
|
|
edee84dd03 | ||
|
|
4a211de2b3 | ||
|
|
d0915ec9a7 | ||
|
|
52245a8e5a | ||
|
|
dbcecd99af | ||
|
|
68c0906570 | ||
|
|
26611c5454 | ||
|
|
05d4faeb49 | ||
|
|
d5c2e50e9a | ||
|
|
800a2349e5 | ||
|
|
46390ba0b8 | ||
|
|
f1a0e7233d | ||
|
|
9d60dcc099 |
@@ -0,0 +1 @@
|
||||
*.sh text=auto eol=lf
|
||||
@@ -193,7 +193,7 @@ If build was successful linker executable is placed in `build` folder under `rad
|
||||
|
||||
## Benchmarks
|
||||
|
||||

|
||||

|
||||
|
||||
---
|
||||
|
||||
@@ -241,6 +241,8 @@ not depend on any other layers in the codebase. The folders which contain these
|
||||
layers are prefixed with `lib_`, like `lib_rdi_format`.
|
||||
|
||||
A list of the layers in the codebase and their associated namespaces is below:
|
||||
- `async` (`ASYNC_`): Implements a system for asynchronous work to be queued
|
||||
and executed on a thread pool.
|
||||
- `base` (no namespace): Universal, codebase-wide constructs. Strings, math,
|
||||
memory allocators, helper macros, command-line parsing, and so on. Depends
|
||||
on no other codebase layers.
|
||||
@@ -375,8 +377,6 @@ A list of the layers in the codebase and their associated namespaces is below:
|
||||
as-needed basis. Higher level drawing features are implemented in the `draw`
|
||||
layer.
|
||||
- `scratch` (no namespace): Scratch space for small and transient test programs.
|
||||
- `task_system` (`TS_`): Implements a system for kicking off asynchronous tasks
|
||||
and obtaining artifacts from those tasks once they've completed.
|
||||
- `texture_cache` (`TEX_`): Implements an asynchronously-filled cache for GPU
|
||||
texture data, filled by data sourced in the `hash_store` layer's cache. Used
|
||||
for asynchronously preparing data for visualization.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
@echo off
|
||||
setlocal
|
||||
setlocal enabledelayedexpansion
|
||||
cd /D "%~dp0"
|
||||
|
||||
:: --- Usage Notes (2024/1/10) ------------------------------------------------
|
||||
@@ -48,11 +48,21 @@ set cl_debug= call cl /Od /Ob1 /DBUILD_DEBUG=1 %cl_common% %auto_compile_fl
|
||||
set cl_release= call cl /O2 /DBUILD_DEBUG=0 %cl_common% %auto_compile_flags%
|
||||
set clang_debug= call clang -g -O0 -DBUILD_DEBUG=1 %clang_common% %auto_compile_flags%
|
||||
set clang_release= call clang -g -O2 -DBUILD_DEBUG=0 %clang_common% %auto_compile_flags%
|
||||
set cl_link= /link /MANIFEST:EMBED /INCREMENTAL:NO /natvis:"%~dp0\src\natvis\base.natvis" /pdbaltpath:%%%%_PDB%%%%
|
||||
set clang_link= -fuse-ld=lld -Xlinker /MANIFEST:EMBED -Xlinker /natvis:"%~dp0\src\natvis\base.natvis" -Xlinker /pdbaltpath:%%%%_PDB%%%%
|
||||
set cl_link= /link /MANIFEST:EMBED /INCREMENTAL:NO /pdbaltpath:%%%%_PDB%%%%
|
||||
set clang_link= -fuse-ld=lld -Xlinker /MANIFEST:EMBED -Xlinker /pdbaltpath:%%%%_PDB%%%%
|
||||
set cl_out= /out:
|
||||
set clang_out= -o
|
||||
|
||||
:: --- NATVIS -----------------------------------------------------------------
|
||||
set natvis= /NATVIS:"%~dp0\src\natvis\base.natvis"
|
||||
if "%radlink%"=="1" set natvis= %natvis% /NATVIS:"%~dp0\src\linker\linker.natvis"
|
||||
|
||||
if "%clang%"=="1" (
|
||||
set result=
|
||||
for %%n in (%natvis%) do set result= !result! -Xlinker %%n
|
||||
set natvis= !result!
|
||||
)
|
||||
|
||||
:: --- Per-Build Settings -----------------------------------------------------
|
||||
set link_dll=-DLL
|
||||
set link_icon=logo.res
|
||||
@@ -77,6 +87,9 @@ if "%clang%"=="1" set out=%clang_out%
|
||||
if "%debug%"=="1" set compile=%compile_debug%
|
||||
if "%release%"=="1" set compile=%compile_release%
|
||||
|
||||
:: --- Append NATVIS to link line ---------------------------------------------
|
||||
set compile_link= %compile_link% %natvis%
|
||||
|
||||
:: --- Prep Directories -------------------------------------------------------
|
||||
if not exist build mkdir build
|
||||
if not exist local mkdir local
|
||||
@@ -87,7 +100,8 @@ pushd build
|
||||
popd
|
||||
|
||||
:: --- Get Current Git Commit Id ----------------------------------------------
|
||||
for /f %%i in ('call git describe --always --dirty') do set compile=%compile% -DBUILD_GIT_HASH=\"%%i\"
|
||||
for /f %%i in ('call git describe --always --dirty') do set compile=%compile% -DBUILD_GIT_HASH=\"%%i\"
|
||||
for /f %%i in ('call git rev-parse HEAD') do set compile=%compile% -DBUILD_GIT_HASH_FULL=\"%%i\"
|
||||
|
||||
:: --- Build & Run Metaprogram ------------------------------------------------
|
||||
if "%no_meta%"=="1" echo [skipping metagen]
|
||||
@@ -108,6 +122,7 @@ if "%rdi_dump%"=="1" set didbuild=1 && %compile% ..\src\rdi_du
|
||||
if "%rdi_breakpad_from_pdb%"=="1" set didbuild=1 && %compile% ..\src\rdi_breakpad_from_pdb\rdi_breakpad_from_pdb_main.c %compile_link% %out%rdi_breakpad_from_pdb.exe || exit /b 1
|
||||
if "%tester%"=="1" set didbuild=1 && %compile% ..\src\tester\tester_main.c %compile_link% %out%tester.exe || exit /b 1
|
||||
if "%ryan_scratch%"=="1" set didbuild=1 && %compile% ..\src\scratch\ryan_scratch.c %compile_link% %out%ryan_scratch.exe || exit /b 1
|
||||
if "%textperf%"=="1" set didbuild=1 && %compile% ..\src\scratch\textperf.c %compile_link% %out%textperf.exe || exit /b 1
|
||||
if "%parse_inline_sites%"=="1" set didbuild=1 && %compile% ..\src\scratch\parse_inline_sites.c %compile_link% %out%parse_inline_sites.exe || exit /b 1
|
||||
if "%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
|
||||
@@ -122,16 +137,6 @@ if "%mule_peb_trample%"=="1" (
|
||||
)
|
||||
popd
|
||||
|
||||
:: --- Unset ------------------------------------------------------------------
|
||||
for %%a in (%*) do set "%%a=0"
|
||||
set raddbg=
|
||||
set compile=
|
||||
set compile_link=
|
||||
set out=
|
||||
set msvc=
|
||||
set debug=
|
||||
set release=
|
||||
|
||||
:: --- Warn On No Builds ------------------------------------------------------
|
||||
if "%didbuild%"=="" (
|
||||
echo [WARNING] no valid build target specified; must use build target names as arguments to this script, like `build raddbg` or `build rdi_from_pdb`.
|
||||
|
||||
@@ -14,13 +14,17 @@ if [ -v gcc ]; then compiler="${CC:-gcc}"; echo "[gcc compile]"; fi
|
||||
# --- Unpack Command Line Build Arguments -------------------------------------
|
||||
auto_compile_flags=''
|
||||
|
||||
# --- Get Current Git Commit Id -----------------------------------------------
|
||||
git_hash=$(git rev-parse HEAD)
|
||||
git_hash_full=$(git rev-parse HEAD)
|
||||
|
||||
# --- Compile/Link Line Definitions -------------------------------------------
|
||||
clang_common='-I../src/ -I../local/ -g -Wno-unknown-warning-option -fdiagnostics-absolute-paths -Wall -Wno-missing-braces -Wno-unused-function -Wno-writable-strings -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-register -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-single-bit-bitfield-constant-conversion -Wno-compare-distinct-pointer-types -Wno-initializer-overrides -Wno-incompatible-pointer-types-discards-qualifiers -Wno-for-loop-analysis -Xclang -flto-visibility-public-std -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf'
|
||||
clang_common="-I../src/ -I../local/ -g -DBUILD_GIT_HASH=\"$git_hash\" -DBUILD_GIT_HASH_FULL=\"$git_hash_full\" -Wno-unknown-warning-option -fdiagnostics-absolute-paths -Wall -Wno-missing-braces -Wno-unused-function -Wno-writable-strings -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-register -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-single-bit-bitfield-constant-conversion -Wno-compare-distinct-pointer-types -Wno-initializer-overrides -Wno-incompatible-pointer-types-discards-qualifiers -Wno-for-loop-analysis -Xclang -flto-visibility-public-std -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf"
|
||||
clang_debug="$compiler -g -O0 -DBUILD_DEBUG=1 ${clang_common} ${auto_compile_flags}"
|
||||
clang_release="$compiler -g -O2 -DBUILD_DEBUG=0 ${clang_common} ${auto_compile_flags}"
|
||||
clang_link="-lpthread -lm -lrt -ldl"
|
||||
clang_out="-o"
|
||||
gcc_common='-I../src/ -I../local/ -g -Wno-unknown-warning-option -Wall -Wno-missing-braces -Wno-unused-function -Wno-attributes -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-compare-distinct-pointer-types -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf'
|
||||
gcc_common="-I../src/ -I../local/ -g -DBUILD_GIT_HASH=\"$git_hash\" -DBUILD_GIT_HASH_FULL=\"$git_hash_full\" -Wno-unknown-warning-option -Wall -Wno-missing-braces -Wno-unused-function -Wno-attributes -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-compare-distinct-pointer-types -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf"
|
||||
gcc_debug="$compiler -g -O0 -DBUILD_DEBUG=1 ${gcc_common} ${auto_compile_flags}"
|
||||
gcc_release="$compiler -g -O2 -DBUILD_DEBUG=0 ${gcc_common} ${auto_compile_flags}"
|
||||
gcc_link="-lpthread -lm -lrt -ldl"
|
||||
@@ -59,6 +63,7 @@ fi
|
||||
# --- Build Everything (@build_targets) ---------------------------------------
|
||||
cd build
|
||||
if [ -v raddbg ]; then didbuild=1 && $compile ../src/raddbg/raddbg_main.c $compile_link $link_os_gfx $out raddbg; fi
|
||||
if [ -v radlink ]; then didbuild=1 && $compile ../src/linker/lnk.c $compile_link $out radlink; fi
|
||||
if [ -v rdi_from_pdb ]; then didbuild=1 && $compile ../src/rdi_from_pdb/rdi_from_pdb_main.c $compile_link $out rdi_from_pdb; fi
|
||||
if [ -v rdi_from_dwarf ]; then didbuild=1 && $compile ../src/rdi_from_dwarf/rdi_from_dwarf.c $compile_link $out rdi_from_dwarf; fi
|
||||
if [ -v rdi_dump ]; then didbuild=1 && $compile ../src/rdi_dump/rdi_dump_main.c $compile_link $out rdi_dump; fi
|
||||
|
||||
@@ -49,6 +49,8 @@ commands =
|
||||
.f1 = { .win = "build raddbg telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
||||
.f2 = { .win = "build rdi_from_pdb", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
||||
.f3 = { .win = "pushd build && raddbg.exe --user:local_dev.raddbg_user --project:local_dev.raddbg_project --xuto_run && popd",.linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
||||
// .f1 = { .win = "build textperf release telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
||||
// .f3 = { .win = "pushd build && textperf.exe --capture && popd",.linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
||||
|
||||
//- rjf: local target builds
|
||||
.build_raddbg = { .win = "build raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
@echo off
|
||||
setlocal
|
||||
cd /D "%~dp0"
|
||||
|
||||
echo --- getting test data folder path ---------------------------------------------
|
||||
if not exist .\local\test_data_path.txt (
|
||||
echo error: You must first store the full path of your test data folder inside of `local/test_data_path.txt`.
|
||||
goto :EOF
|
||||
)
|
||||
set /p test_data_folder=<.\local\test_data_path.txt
|
||||
echo test data path: %test_data_folder%
|
||||
echo:
|
||||
|
||||
echo --- building all testing executables ------------------------------------------
|
||||
call build rdi_from_pdb rdi_dump raddbg radlink tester
|
||||
echo:
|
||||
|
||||
echo --- running tests -------------------------------------------------------------
|
||||
pushd build
|
||||
call tester.exe --test_data:%test_data_folder%
|
||||
popd
|
||||
@@ -0,0 +1,240 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Top-Level Layer Initialization
|
||||
|
||||
internal void
|
||||
async_init(void)
|
||||
{
|
||||
Arena *arena = arena_alloc();
|
||||
async_shared = push_array(arena, ASYNC_Shared, 1);
|
||||
async_shared->arena = arena;
|
||||
for EachEnumVal(ASYNC_Priority, p)
|
||||
{
|
||||
ASYNC_Ring *ring = &async_shared->rings[p];
|
||||
ring->ring_size = MB(8);
|
||||
ring->ring_base = push_array_no_zero(arena, U8, ring->ring_size);
|
||||
ring->ring_mutex = os_mutex_alloc();
|
||||
ring->ring_cv = os_condition_variable_alloc();
|
||||
}
|
||||
async_shared->ring_mutex = os_mutex_alloc();
|
||||
async_shared->ring_cv = os_condition_variable_alloc();
|
||||
async_shared->work_threads_count = Max(1, os_get_system_info()->logical_processor_count-1);
|
||||
async_shared->work_threads = push_array(arena, OS_Handle, async_shared->work_threads_count);
|
||||
for EachIndex(idx, async_shared->work_threads_count)
|
||||
{
|
||||
async_shared->work_threads[idx] = os_thread_launch(async_work_thread__entry_point, (void *)idx, 0);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Top-Level Accessors
|
||||
|
||||
internal U64
|
||||
async_thread_count(void)
|
||||
{
|
||||
return async_shared->work_threads_count;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Work Kickoffs
|
||||
|
||||
internal B32
|
||||
async_push_work_(ASYNC_WorkFunctionType *work_function, ASYNC_WorkParams *params)
|
||||
{
|
||||
// rjf: choose ring
|
||||
ASYNC_Ring *ring = &async_shared->rings[params->priority];
|
||||
|
||||
// rjf: build work package
|
||||
ASYNC_Work work = {0};
|
||||
work.work_function = work_function;
|
||||
work.input = params->input;
|
||||
work.output = params->output;
|
||||
work.semaphore = params->semaphore;
|
||||
work.completion_counter = params->completion_counter;
|
||||
|
||||
// rjf: loop; try to write into user -> writer ring buffer. if we're on a
|
||||
// worker thread, determine if we need to execute this task locally on this
|
||||
// thread, and skip ring buffer if so.
|
||||
B32 queued_in_ring_buffer = 0;
|
||||
B32 need_to_execute_on_this_thread = 0;
|
||||
OS_MutexScope(ring->ring_mutex) for(;;)
|
||||
{
|
||||
U64 num_available_work_threads = (async_shared->work_threads_count - ins_atomic_u64_eval(&async_shared->work_threads_live_count));
|
||||
if(num_available_work_threads == 0 && async_work_thread_depth > 0)
|
||||
{
|
||||
need_to_execute_on_this_thread = 1;
|
||||
break;
|
||||
}
|
||||
U64 unconsumed_size = ring->ring_write_pos - ring->ring_read_pos;
|
||||
U64 available_size = ring->ring_size - unconsumed_size;
|
||||
if(available_size >= sizeof(work))
|
||||
{
|
||||
queued_in_ring_buffer = 1;
|
||||
if(!os_handle_match(params->semaphore, os_handle_zero()))
|
||||
{
|
||||
os_semaphore_take(params->semaphore, max_U64);
|
||||
}
|
||||
ring->ring_write_pos += ring_write_struct(ring->ring_base, ring->ring_size, ring->ring_write_pos, &work);
|
||||
break;
|
||||
}
|
||||
if(os_now_microseconds() >= params->endt_us)
|
||||
{
|
||||
break;
|
||||
}
|
||||
os_condition_variable_wait(ring->ring_cv, ring->ring_mutex, params->endt_us);
|
||||
}
|
||||
|
||||
// rjf: broadcast ring buffer cv if we wrote successfully
|
||||
if(queued_in_ring_buffer)
|
||||
{
|
||||
os_condition_variable_broadcast(ring->ring_cv);
|
||||
os_condition_variable_broadcast(async_shared->ring_cv);
|
||||
}
|
||||
|
||||
// rjf: if we did not queue successfully, and we have determined that
|
||||
// we need to execute this work on the current thread, then execute the
|
||||
// work before returning
|
||||
if(need_to_execute_on_this_thread)
|
||||
{
|
||||
async_execute_work(work);
|
||||
}
|
||||
|
||||
// rjf: return success signal
|
||||
B32 result = (queued_in_ring_buffer || need_to_execute_on_this_thread);
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Task-Based Work Helper
|
||||
|
||||
internal void
|
||||
async_task_list_push(Arena *arena, ASYNC_TaskList *list, ASYNC_Task *t)
|
||||
{
|
||||
ASYNC_TaskNode *n = push_array(arena, ASYNC_TaskNode, 1);
|
||||
SLLQueuePush(list->first, list->last, n);
|
||||
n->v = t;
|
||||
list->count += 1;
|
||||
}
|
||||
|
||||
internal ASYNC_Task *
|
||||
async_task_launch_(Arena *arena, ASYNC_WorkFunctionType *work_function, ASYNC_WorkParams *params)
|
||||
{
|
||||
ASYNC_Task *task = push_array(arena, ASYNC_Task, 1);
|
||||
task->semaphore = os_semaphore_alloc(1, 1, str8_zero());
|
||||
ASYNC_WorkParams params_refined = {0};
|
||||
MemoryCopyStruct(¶ms_refined, params);
|
||||
params_refined.endt_us = max_U64;
|
||||
params_refined.semaphore = task->semaphore;
|
||||
if(params_refined.output == 0)
|
||||
{
|
||||
params_refined.output = &task->output;
|
||||
}
|
||||
async_push_work_(work_function, ¶ms_refined);
|
||||
return task;
|
||||
}
|
||||
|
||||
internal void *
|
||||
async_task_join(ASYNC_Task *task)
|
||||
{
|
||||
void *result = 0;
|
||||
if(task != 0 && !os_handle_match(task->semaphore, os_handle_zero()))
|
||||
{
|
||||
os_semaphore_take(task->semaphore, max_U64);
|
||||
os_semaphore_release(task->semaphore);
|
||||
MemoryZeroStruct(&task->semaphore);
|
||||
result = (void *)ins_atomic_u64_eval(&task->output);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Work Execution
|
||||
|
||||
internal ASYNC_Work
|
||||
async_pop_work(void)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
ASYNC_Work work = {0};
|
||||
B32 done = 0;
|
||||
ASYNC_Priority taken_priority = ASYNC_Priority_Low;
|
||||
OS_MutexScope(async_shared->ring_mutex) for(;!done;)
|
||||
{
|
||||
for(ASYNC_Priority priority = ASYNC_Priority_High;; priority = (ASYNC_Priority)(priority - 1))
|
||||
{
|
||||
ASYNC_Ring *ring = &async_shared->rings[priority];
|
||||
OS_MutexScope(ring->ring_mutex)
|
||||
{
|
||||
U64 unconsumed_size = ring->ring_write_pos - ring->ring_read_pos;
|
||||
if(unconsumed_size >= sizeof(work))
|
||||
{
|
||||
ring->ring_read_pos += ring_read_struct(ring->ring_base, ring->ring_size, ring->ring_read_pos, &work);
|
||||
done = 1;
|
||||
taken_priority = priority;
|
||||
}
|
||||
}
|
||||
if(done)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if(priority == ASYNC_Priority_Low)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!done)
|
||||
{
|
||||
os_condition_variable_wait(async_shared->ring_cv, async_shared->ring_mutex, max_U64);
|
||||
}
|
||||
}
|
||||
os_condition_variable_broadcast(async_shared->ring_cv);
|
||||
os_condition_variable_broadcast(async_shared->rings[taken_priority].ring_cv);
|
||||
ProfEnd();
|
||||
return work;
|
||||
}
|
||||
|
||||
internal void
|
||||
async_execute_work(ASYNC_Work work)
|
||||
{
|
||||
//- rjf: run work
|
||||
async_work_thread_depth += 1;
|
||||
void *work_out = work.work_function(async_work_thread_idx, work.input);
|
||||
async_work_thread_depth -= 1;
|
||||
|
||||
//- rjf: store output
|
||||
if(work.output != 0)
|
||||
{
|
||||
ins_atomic_u64_eval_assign((U64 *)work.output, (U64)work_out);
|
||||
}
|
||||
|
||||
//- rjf: release semaphore
|
||||
if(!os_handle_match(work.semaphore, os_handle_zero()))
|
||||
{
|
||||
os_semaphore_drop(work.semaphore);
|
||||
}
|
||||
|
||||
//- rjf: increment completion counter
|
||||
if(work.completion_counter != 0)
|
||||
{
|
||||
ins_atomic_u64_inc_eval(work.completion_counter);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Work Thread Entry Point
|
||||
|
||||
internal void
|
||||
async_work_thread__entry_point(void *p)
|
||||
{
|
||||
U64 thread_idx = (U64)p;
|
||||
ThreadNameF("[async] work thread #%I64u", thread_idx);
|
||||
async_work_thread_idx = thread_idx;
|
||||
for(;;)
|
||||
{
|
||||
ASYNC_Work work = async_pop_work();
|
||||
ins_atomic_u64_inc_eval(&async_shared->work_threads_live_count);
|
||||
async_execute_work(work);
|
||||
ins_atomic_u64_dec_eval(&async_shared->work_threads_live_count);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef ASYNC_H
|
||||
#define ASYNC_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Work Function Type
|
||||
|
||||
#define ASYNC_WORK_SIG(name) void *name(U64 thread_idx, void *input)
|
||||
#define ASYNC_WORK_DEF(name) internal ASYNC_WORK_SIG(name)
|
||||
typedef ASYNC_WORK_SIG(ASYNC_WorkFunctionType);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Work Types
|
||||
|
||||
typedef enum ASYNC_Priority
|
||||
{
|
||||
ASYNC_Priority_Low,
|
||||
ASYNC_Priority_High,
|
||||
ASYNC_Priority_COUNT
|
||||
}
|
||||
ASYNC_Priority;
|
||||
|
||||
typedef struct ASYNC_WorkParams ASYNC_WorkParams;
|
||||
struct ASYNC_WorkParams
|
||||
{
|
||||
void *input;
|
||||
void **output;
|
||||
OS_Handle semaphore;
|
||||
U64 *completion_counter;
|
||||
U64 endt_us;
|
||||
ASYNC_Priority priority;
|
||||
};
|
||||
|
||||
typedef struct ASYNC_Work ASYNC_Work;
|
||||
struct ASYNC_Work
|
||||
{
|
||||
ASYNC_WorkFunctionType *work_function;
|
||||
void *input;
|
||||
void **output;
|
||||
OS_Handle semaphore;
|
||||
U64 *completion_counter;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Task-Based Work Types
|
||||
|
||||
typedef struct ASYNC_Task ASYNC_Task;
|
||||
struct ASYNC_Task
|
||||
{
|
||||
OS_Handle semaphore;
|
||||
void *output;
|
||||
};
|
||||
|
||||
typedef struct ASYNC_TaskNode ASYNC_TaskNode;
|
||||
struct ASYNC_TaskNode
|
||||
{
|
||||
ASYNC_TaskNode *next;
|
||||
ASYNC_Task *v;
|
||||
};
|
||||
|
||||
typedef struct ASYNC_TaskList ASYNC_TaskList;
|
||||
struct ASYNC_TaskList
|
||||
{
|
||||
ASYNC_TaskNode *first;
|
||||
ASYNC_TaskNode *last;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Shared State Bundle
|
||||
|
||||
typedef struct ASYNC_Ring ASYNC_Ring;
|
||||
struct ASYNC_Ring
|
||||
{
|
||||
U64 ring_size;
|
||||
U8 *ring_base;
|
||||
U64 ring_write_pos;
|
||||
U64 ring_read_pos;
|
||||
OS_Handle ring_mutex;
|
||||
OS_Handle ring_cv;
|
||||
};
|
||||
|
||||
typedef struct ASYNC_Shared ASYNC_Shared;
|
||||
struct ASYNC_Shared
|
||||
{
|
||||
Arena *arena;
|
||||
|
||||
// rjf: user -> work thread ring buffers
|
||||
ASYNC_Ring rings[ASYNC_Priority_COUNT];
|
||||
OS_Handle ring_mutex;
|
||||
OS_Handle ring_cv;
|
||||
|
||||
// rjf: work threads
|
||||
OS_Handle *work_threads;
|
||||
U64 work_threads_count;
|
||||
U64 work_threads_live_count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
thread_static B32 async_work_thread_depth = 0;
|
||||
thread_static U64 async_work_thread_idx = 0;
|
||||
global ASYNC_Shared *async_shared = 0;
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Top-Level Layer Initialization
|
||||
|
||||
internal void async_init(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Top-Level Accessors
|
||||
|
||||
internal U64 async_thread_count(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Work Kickoffs
|
||||
|
||||
internal B32 async_push_work_(ASYNC_WorkFunctionType *work_function, ASYNC_WorkParams *params);
|
||||
#define async_push_work(function, ...) async_push_work_((function), &(ASYNC_WorkParams){.endt_us = max_U64, .priority = ASYNC_Priority_High, __VA_ARGS__})
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Task-Based Work Helper
|
||||
|
||||
internal void async_task_list_push(Arena *arena, ASYNC_TaskList *list, ASYNC_Task *t);
|
||||
internal ASYNC_Task *async_task_launch_(Arena *arena, ASYNC_WorkFunctionType *work_function, ASYNC_WorkParams *params);
|
||||
#define async_task_launch(arena, work_function, ...) async_task_launch_((arena), (work_function), &(ASYNC_WorkParams){.endt_us = max_U64, __VA_ARGS__})
|
||||
internal void *async_task_join(ASYNC_Task *task);
|
||||
#define async_task_join_struct(task, T) (T *)async_task_join(task)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Work Execution
|
||||
|
||||
internal ASYNC_Work async_pop_work(void);
|
||||
internal void async_execute_work(ASYNC_Work work);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Work Thread Entry Point
|
||||
|
||||
internal void async_work_thread__entry_point(void *p);
|
||||
|
||||
#endif // ASYNC_H
|
||||
@@ -52,7 +52,7 @@ arena_alloc_(ArenaParams *params)
|
||||
Arena *arena = (Arena *)base;
|
||||
arena->current = arena;
|
||||
arena->flags = params->flags;
|
||||
arena->cmt_size = (U32)params->commit_size;
|
||||
arena->cmt_size = params->commit_size;
|
||||
arena->res_size = params->reserve_size;
|
||||
arena->base_pos = 0;
|
||||
arena->pos = ARENA_HEADER_SIZE;
|
||||
@@ -90,7 +90,7 @@ arena_push(Arena *arena, U64 size, U64 align)
|
||||
if(current->res < pos_pst && !(arena->flags & ArenaFlag_NoChain))
|
||||
{
|
||||
Arena *new_block = 0;
|
||||
|
||||
|
||||
#if ARENA_FREE_LIST
|
||||
Arena *prev_block;
|
||||
for(new_block = arena->free_last, prev_block = 0; new_block != 0; prev_block = new_block, new_block = new_block->prev)
|
||||
@@ -106,12 +106,12 @@ arena_push(Arena *arena, U64 size, U64 align)
|
||||
arena->free_last = new_block->prev;
|
||||
}
|
||||
arena->free_size -= new_block->res_size;
|
||||
AsanUnpoisonMemoryRegion((U8*)new_block + ARENA_HEADER_SIZE, new_block->res_size - ARENA_HEADER_SIZE);
|
||||
AsanUnpoisonMemoryRegion((U8*)new_block + ARENA_HEADER_SIZE, new_block->res_size - ARENA_HEADER_SIZE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
if(new_block == 0)
|
||||
{
|
||||
U64 res_size = current->res_size;
|
||||
@@ -124,10 +124,11 @@ arena_push(Arena *arena, U64 size, U64 align)
|
||||
new_block = arena_alloc(.reserve_size = res_size,
|
||||
.commit_size = cmt_size,
|
||||
.flags = current->flags);
|
||||
new_block->base_pos = current->base_pos + current->res;
|
||||
SLLStackPush_N(arena->current, new_block, prev);
|
||||
}
|
||||
|
||||
|
||||
new_block->base_pos = current->base_pos + current->res;
|
||||
SLLStackPush_N(arena->current, new_block, prev);
|
||||
|
||||
current = new_block;
|
||||
pos_pre = AlignPow2(current->pos, align);
|
||||
pos_pst = pos_pre + size;
|
||||
@@ -186,7 +187,7 @@ arena_pop_to(Arena *arena, U64 pos)
|
||||
{
|
||||
U64 big_pos = ClampBot(ARENA_HEADER_SIZE, pos);
|
||||
Arena *current = arena->current;
|
||||
|
||||
|
||||
#if ARENA_FREE_LIST
|
||||
for(Arena *prev = 0; current->base_pos >= big_pos; current = prev)
|
||||
{
|
||||
|
||||
@@ -7,16 +7,12 @@
|
||||
////////////////////////////////
|
||||
//~ rjf: Constants
|
||||
|
||||
#if ARENA_FREE_LIST
|
||||
# define ARENA_HEADER_SIZE 128
|
||||
#else
|
||||
# define ARENA_HEADER_SIZE 64
|
||||
#endif
|
||||
#define ARENA_HEADER_SIZE 128
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Types
|
||||
|
||||
typedef U32 ArenaFlags;
|
||||
typedef U64 ArenaFlags;
|
||||
enum
|
||||
{
|
||||
ArenaFlag_NoChain = (1<<0),
|
||||
@@ -38,7 +34,7 @@ struct Arena
|
||||
Arena *prev; // previous arena in chain
|
||||
Arena *current; // current arena in chain
|
||||
ArenaFlags flags;
|
||||
U32 cmt_size;
|
||||
U64 cmt_size;
|
||||
U64 res_size;
|
||||
U64 base_pos;
|
||||
U64 pos;
|
||||
|
||||
@@ -98,9 +98,10 @@ cmd_line_from_string_list(Arena *arena, String8List command_line)
|
||||
next = node->next;
|
||||
String8 option_name = node->string;
|
||||
|
||||
// NOTE(rjf): Look at -- or - at the start of an argument to determine if it's
|
||||
// a flag option. All arguments after a single "--" (with no trailing string
|
||||
// on the command line will be considered as input files.
|
||||
// NOTE(rjf): Look at --, -, or / (only on Windows) at the start of an
|
||||
// argument to determine if it's a flag option. All arguments after a
|
||||
// single "--" (with no trailing string on the command line will be
|
||||
// considered as input files.
|
||||
B32 is_option = 1;
|
||||
if(after_passthrough_option == 0)
|
||||
{
|
||||
@@ -117,6 +118,11 @@ cmd_line_from_string_list(Arena *arena, String8List command_line)
|
||||
{
|
||||
option_name = str8_skip(option_name, 1);
|
||||
}
|
||||
else if(operating_system_from_context() == OperatingSystem_Windows &&
|
||||
str8_match(str8_prefix(node->string, 1), str8_lit("/"), 0))
|
||||
{
|
||||
option_name = str8_skip(option_name, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
is_option = 0;
|
||||
@@ -184,6 +190,18 @@ cmd_line_from_string_list(Arena *arena, String8List command_line)
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: fill argc/argv
|
||||
parsed.argc = command_line.node_count;
|
||||
parsed.argv = push_array(arena, char *, parsed.argc);
|
||||
{
|
||||
U64 idx = 0;
|
||||
for(String8Node *n = command_line.first; n != 0; n = n->next)
|
||||
{
|
||||
parsed.argv[idx] = (char *)push_str8_copy(arena, n->string).str;
|
||||
idx += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return parsed;
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,8 @@ struct CmdLine
|
||||
String8List inputs;
|
||||
U64 option_table_size;
|
||||
CmdLineOpt **option_table;
|
||||
U64 argc;
|
||||
char **argv;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
@@ -155,11 +155,11 @@
|
||||
#endif
|
||||
|
||||
#if !defined(BUILD_VERSION_MINOR)
|
||||
# define BUILD_VERSION_MINOR 0
|
||||
# define BUILD_VERSION_MINOR 9
|
||||
#endif
|
||||
|
||||
#if !defined(BUILD_VERSION_PATCH)
|
||||
# define BUILD_VERSION_PATCH 0
|
||||
# define BUILD_VERSION_PATCH 14
|
||||
#endif
|
||||
|
||||
#define BUILD_VERSION_STRING_LITERAL Stringify(BUILD_VERSION_MAJOR) "." Stringify(BUILD_VERSION_MINOR) "." Stringify(BUILD_VERSION_PATCH)
|
||||
|
||||
+11
-23
@@ -143,12 +143,6 @@ bswap_u64(U64 x)
|
||||
|
||||
#if COMPILER_MSVC || (COMPILER_CLANG && OS_WINDOWS)
|
||||
|
||||
internal U64
|
||||
count_bits_set16(U16 val)
|
||||
{
|
||||
return __popcnt16(val);
|
||||
}
|
||||
|
||||
internal U64
|
||||
count_bits_set32(U32 val)
|
||||
{
|
||||
@@ -195,46 +189,40 @@ clz64(U64 mask)
|
||||
|
||||
#elif COMPILER_CLANG || COMPILER_GCC
|
||||
|
||||
internal U64
|
||||
count_bits_set16(U16 val)
|
||||
{
|
||||
NotImplemented;
|
||||
return 0;
|
||||
}
|
||||
|
||||
internal U64
|
||||
count_bits_set32(U32 val)
|
||||
{
|
||||
NotImplemented;
|
||||
return 0;
|
||||
return __builtin_popcount(val);
|
||||
}
|
||||
|
||||
internal U64
|
||||
count_bits_set64(U64 val)
|
||||
{
|
||||
NotImplemented;
|
||||
return 0;
|
||||
return __builtin_popcountll(val);
|
||||
}
|
||||
|
||||
internal U64
|
||||
ctz32(U32 val)
|
||||
{
|
||||
NotImplemented;
|
||||
return 0;
|
||||
return __builtin_ctz(val);
|
||||
}
|
||||
|
||||
internal U64
|
||||
clz32(U32 val)
|
||||
{
|
||||
NotImplemented;
|
||||
return 0;
|
||||
return __builtin_clz(val);
|
||||
}
|
||||
|
||||
internal U64
|
||||
ctz64(U64 val)
|
||||
{
|
||||
return __builtin_ctzll(val);
|
||||
}
|
||||
|
||||
internal U64
|
||||
clz64(U64 val)
|
||||
{
|
||||
NotImplemented;
|
||||
return 0;
|
||||
return __builtin_clzll(val);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
+59
-30
@@ -40,6 +40,12 @@
|
||||
# define thread_static __thread
|
||||
#endif
|
||||
|
||||
#if COMPILER_MSVC
|
||||
# define force_inline __forceinline
|
||||
#elif COMPILER_CLANG || COMPILER_GCC
|
||||
# define force_inline __attribute__((always_inline))
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Linkage Keyword Macros
|
||||
|
||||
@@ -172,42 +178,49 @@
|
||||
////////////////////////////////
|
||||
//~ rjf: Atomic Operations
|
||||
|
||||
#if OS_WINDOWS
|
||||
# include <windows.h>
|
||||
# include <tmmintrin.h>
|
||||
# include <wmmintrin.h>
|
||||
#if COMPILER_MSVC
|
||||
# include <intrin.h>
|
||||
# if ARCH_X64
|
||||
# define ins_atomic_u64_eval(x) InterlockedAdd64((volatile __int64 *)(x), 0)
|
||||
# define ins_atomic_u64_inc_eval(x) InterlockedIncrement64((volatile __int64 *)(x))
|
||||
# define ins_atomic_u64_dec_eval(x) InterlockedDecrement64((volatile __int64 *)(x))
|
||||
# define ins_atomic_u64_eval_assign(x,c) InterlockedExchange64((volatile __int64 *)(x),(c))
|
||||
# define ins_atomic_u64_add_eval(x,c) InterlockedAdd64((volatile __int64 *)(x), c)
|
||||
# define ins_atomic_u64_eval(x) *((volatile U64 *)(x))
|
||||
# define ins_atomic_u64_inc_eval(x) InterlockedIncrement64((volatile __int64 *)(x))
|
||||
# define ins_atomic_u64_dec_eval(x) InterlockedDecrement64((volatile __int64 *)(x))
|
||||
# define ins_atomic_u64_eval_assign(x,c) InterlockedExchange64((volatile __int64 *)(x),(c))
|
||||
# define ins_atomic_u64_add_eval(x,c) InterlockedAdd64((volatile __int64 *)(x), c)
|
||||
# define ins_atomic_u64_eval_cond_assign(x,k,c) InterlockedCompareExchange64((volatile __int64 *)(x),(k),(c))
|
||||
# define ins_atomic_u32_eval(x,c) InterlockedAdd((volatile LONG *)(x), 0)
|
||||
# define ins_atomic_u32_eval_assign(x,c) InterlockedExchange((volatile LONG *)(x),(c))
|
||||
# define ins_atomic_u32_eval(x) *((volatile U32 *)(x))
|
||||
# define ins_atomic_u32_inc_eval(x) InterlockedIncrement((volatile LONG *)x)
|
||||
# define ins_atomic_u32_eval_assign(x,c) InterlockedExchange((volatile LONG *)(x),(c))
|
||||
# define ins_atomic_u32_eval_cond_assign(x,k,c) InterlockedCompareExchange((volatile LONG *)(x),(k),(c))
|
||||
# define ins_atomic_ptr_eval_assign(x,c) (void*)ins_atomic_u64_eval_assign((volatile __int64 *)(x), (__int64)(c))
|
||||
# define ins_atomic_u32_add_eval(x,c) InterlockedAdd((volatile LONG *)(x), c)
|
||||
# else
|
||||
# error Atomic intrinsics not defined for this operating system / architecture combination.
|
||||
# endif
|
||||
#elif OS_LINUX
|
||||
# if ARCH_X64
|
||||
# define ins_atomic_u64_eval(x) __sync_fetch_and_add((volatile U64 *)(x), 0)
|
||||
# define ins_atomic_u64_inc_eval(x) __sync_fetch_and_add((volatile U64 *)(x), 1)
|
||||
# define ins_atomic_u64_dec_eval(x) __sync_fetch_and_sub((volatile U64 *)(x), 1)
|
||||
# define ins_atomic_u64_eval_assign(x,c) __sync_lock_test_and_set((volatile U64 *)(x),(c))
|
||||
# define ins_atomic_u64_add_eval(x,c) __sync_fetch_and_add((volatile U64 *)(x), c)
|
||||
# define ins_atomic_u64_eval_cond_assign(x,k,c) __sync_val_compare_and_swap((volatile U64 *)(x),(c),(k))
|
||||
# define ins_atomic_u32_eval(x,c) __sync_fetch_and_add((volatile U32 *)(x), 0)
|
||||
# define ins_atomic_u32_eval_assign(x,c) __sync_lock_test_and_set((volatile U32 *)(x),(c))
|
||||
# define ins_atomic_u32_eval_cond_assign(x,k,c) __sync_val_compare_and_swap((volatile U32 *)(x),(c),(k))
|
||||
# define ins_atomic_ptr_eval_assign(x,c) (void*)ins_atomic_u64_eval_assign((volatile U64 *)(x), (U64)(c))
|
||||
# else
|
||||
# error Atomic intrinsics not defined for this operating system / architecture combination.
|
||||
# error Atomic intrinsics not defined for this compiler / architecture combination.
|
||||
# endif
|
||||
#elif COMPILER_CLANG || COMPILER_GCC
|
||||
# define ins_atomic_u64_eval(x) __atomic_load_n(x, __ATOMIC_SEQ_CST)
|
||||
# define ins_atomic_u64_inc_eval(x) (__atomic_fetch_add((volatile U64 *)(x), 1, __ATOMIC_SEQ_CST) + 1)
|
||||
# define ins_atomic_u64_dec_eval(x) (__atomic_fetch_sub((volatile U64 *)(x), 1, __ATOMIC_SEQ_CST) - 1)
|
||||
# define ins_atomic_u64_eval_assign(x,c) __atomic_exchange_n(x, c, __ATOMIC_SEQ_CST)
|
||||
# define ins_atomic_u64_add_eval(x,c) (__atomic_fetch_add((volatile U64 *)(x), c, __ATOMIC_SEQ_CST) + (c))
|
||||
# define ins_atomic_u64_eval_cond_assign(x,k,c) ({ U64 _new = (c); __atomic_compare_exchange_n((volatile U64 *)(x),&_new,(k),0,__ATOMIC_SEQ_CST,__ATOMIC_SEQ_CST); _new; })
|
||||
# define ins_atomic_u32_eval(x) __atomic_load_n(x, __ATOMIC_SEQ_CST)
|
||||
# define ins_atomic_u32_inc_eval(x) (__atomic_fetch_add((volatile U32 *)(x), 1, __ATOMIC_SEQ_CST) + 1)
|
||||
# define ins_atomic_u32_add_eval(x,c) (__atomic_fetch_add((volatile U32 *)(x), c, __ATOMIC_SEQ_CST) + (c))
|
||||
# define ins_atomic_u32_eval_assign(x,c) __atomic_exchange_n(x, c, __ATOMIC_SEQ_CST)
|
||||
# define ins_atomic_u32_eval_cond_assign(x,k,c) ({ U32 _new = (c); __atomic_compare_exchange_n((volatile U32 *)(x),&_new,(k),0,__ATOMIC_SEQ_CST,__ATOMIC_SEQ_CST); _new; })
|
||||
#else
|
||||
# error Atomic intrinsics not defined for this operating system.
|
||||
# error Atomic intrinsics not defined for this compiler / architecture.
|
||||
#endif
|
||||
|
||||
#if ARCH_64BIT
|
||||
# define ins_atomic_ptr_eval_cond_assign(x,k,c) (void*)ins_atomic_u64_eval_cond_assign((volatile U64 *)(x), (U64)(k), (U64)(c))
|
||||
# define ins_atomic_ptr_eval_assign(x,c) (void*)ins_atomic_u64_eval_assign((volatile U64 *)(x), (U64)(c))
|
||||
# define ins_atomic_ptr_eval(x) (void*)ins_atomic_u64_eval((volatile U64 *)x)
|
||||
#elif ARCH_32BIT
|
||||
# define ins_atomic_ptr_eval_cond_assign(x,k,c) (void*)ins_atomic_u32_eval_cond_assign((volatile U32 *)(x), (U32)(k), (U32)(c))
|
||||
# define ins_atomic_ptr_eval_assign(x,c) (void*)ins_atomic_u32_eval_assign((volatile U32 *)(x), (U32)(c))
|
||||
# define ins_atomic_ptr_eval(x) (void*)ins_atomic_u32_eval((volatile U32 *)x)
|
||||
#else
|
||||
# error Atomic intrinsics for pointers not defined for this architecture.
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
@@ -479,6 +492,23 @@ struct TxtRng
|
||||
TxtPt max;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ Globally Unique Ids
|
||||
|
||||
typedef union Guid Guid;
|
||||
union Guid
|
||||
{
|
||||
struct
|
||||
{
|
||||
U32 data1;
|
||||
U16 data2;
|
||||
U16 data3;
|
||||
U8 data4[8];
|
||||
};
|
||||
U8 v[16];
|
||||
};
|
||||
StaticAssert(sizeof(Guid) == 16, g_guid_size_check);
|
||||
|
||||
////////////////////////////////
|
||||
//~ NOTE(allen): Constants
|
||||
|
||||
@@ -745,7 +775,6 @@ internal U16 bswap_u16(U16 x);
|
||||
internal U32 bswap_u32(U32 x);
|
||||
internal U64 bswap_u64(U64 x);
|
||||
|
||||
internal U64 count_bits_set16(U16 val);
|
||||
internal U64 count_bits_set32(U32 val);
|
||||
internal U64 count_bits_set64(U64 val);
|
||||
|
||||
|
||||
+25
-22
@@ -1,22 +1,24 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
global U64 global_update_tick_idx = 0;
|
||||
|
||||
internal void
|
||||
main_thread_base_entry_point(void (*entry_point)(CmdLine *cmdline), char **arguments, U64 arguments_count)
|
||||
main_thread_base_entry_point(int arguments_count, char **arguments)
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
ThreadNameF("[main thread]");
|
||||
|
||||
//- rjf: set up telemetry
|
||||
#if PROFILE_TELEMETRY
|
||||
local_persist U8 tm_data[MB(64)];
|
||||
local_persist char tm_data[MB(64)];
|
||||
tmLoadLibrary(TM_RELEASE);
|
||||
tmSetMaxThreadCount(256);
|
||||
tmInitialize(sizeof(tm_data), (char *)tm_data);
|
||||
tmInitialize(sizeof(tm_data), tm_data);
|
||||
#endif
|
||||
|
||||
//- rjf: parse command line
|
||||
String8List command_line_argument_strings = os_string_list_from_argcv(scratch.arena, (int)arguments_count, arguments);
|
||||
String8List command_line_argument_strings = os_string_list_from_argcv(scratch.arena, arguments_count, arguments);
|
||||
CmdLine cmdline = cmd_line_from_string_list(scratch.arena, command_line_argument_strings);
|
||||
|
||||
//- rjf: begin captures
|
||||
@@ -26,9 +28,16 @@ main_thread_base_entry_point(void (*entry_point)(CmdLine *cmdline), char **argum
|
||||
ProfBeginCapture(arguments[0]);
|
||||
}
|
||||
|
||||
#if PROFILE_TELEMETRY
|
||||
tmMessage(0, TMMF_ICON_NOTE, BUILD_TITLE);
|
||||
#endif
|
||||
|
||||
//- rjf: initialize all included layers
|
||||
#if defined(TASK_SYSTEM_H) && !defined(TS_INIT_MANUAL)
|
||||
ts_init();
|
||||
#if defined(ASYNC_H) && !defined(ASYNC_INIT_MANUAL)
|
||||
async_init();
|
||||
#endif
|
||||
#if defined(RDI_FROM_PDB_H) && !defined(P2R_INIT_MANUAL)
|
||||
p2r_init();
|
||||
#endif
|
||||
#if defined(HASH_STORE_H) && !defined(HS_INIT_MANUAL)
|
||||
hs_init();
|
||||
@@ -45,12 +54,9 @@ main_thread_base_entry_point(void (*entry_point)(CmdLine *cmdline), char **argum
|
||||
#if defined(DASM_CACHE_H) && !defined(DASM_INIT_MANUAL)
|
||||
dasm_init();
|
||||
#endif
|
||||
#if defined(DBGI_H) && !defined(DBGI_INIT_MANUAL)
|
||||
#if defined(DBGI_H) && !defined(DI_INIT_MANUAL)
|
||||
di_init();
|
||||
#endif
|
||||
#if defined(FUZZY_SEARCH_H) && !defined(FZY_INIT_MANUAL)
|
||||
fzy_init();
|
||||
#endif
|
||||
#if defined(DEMON_CORE_H) && !defined(DMN_INIT_MANUAL)
|
||||
dmn_init();
|
||||
#endif
|
||||
@@ -90,6 +96,7 @@ main_thread_base_entry_point(void (*entry_point)(CmdLine *cmdline), char **argum
|
||||
{
|
||||
ProfEndCapture();
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
}
|
||||
|
||||
@@ -102,22 +109,18 @@ supplement_thread_base_entry_point(void (*entry_point)(void *params), void *para
|
||||
tctx_release();
|
||||
}
|
||||
|
||||
internal U64
|
||||
update_tick_idx(void)
|
||||
{
|
||||
U64 result = ins_atomic_u64_eval(&global_update_tick_idx);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal B32
|
||||
update(void)
|
||||
{
|
||||
ProfTick(0);
|
||||
#if defined(TEXT_CACHE_H)
|
||||
txt_user_clock_tick();
|
||||
#endif
|
||||
#if defined(DASM_CACHE_H)
|
||||
dasm_user_clock_tick();
|
||||
#endif
|
||||
#if defined(GEO_CACHE_H)
|
||||
geo_user_clock_tick();
|
||||
#endif
|
||||
#if defined(TEXTURE_CACHE_H)
|
||||
tex_user_clock_tick();
|
||||
#endif
|
||||
ins_atomic_u64_inc_eval(&global_update_tick_idx);
|
||||
#if OS_FEATURE_GRAPHICAL
|
||||
B32 result = frame();
|
||||
#else
|
||||
|
||||
@@ -4,8 +4,9 @@
|
||||
#ifndef BASE_ENTRY_POINT_H
|
||||
#define BASE_ENTRY_POINT_H
|
||||
|
||||
internal void main_thread_base_entry_point(void (*entry_point)(CmdLine *cmdline), char **arguments, U64 arguments_count);
|
||||
internal void main_thread_base_entry_point(int argc, char **argv);
|
||||
internal void supplement_thread_base_entry_point(void (*entry_point)(void *params), void *params);
|
||||
internal U64 update_tick_idx(void);
|
||||
internal B32 update(void);
|
||||
|
||||
#endif // BASE_ENTRY_POINT_H
|
||||
|
||||
@@ -195,6 +195,30 @@ read_only global Type B32__type = {TypeKind_B32, 0, sizeof(B32), &type_nil, st
|
||||
read_only global Type B64__type = {TypeKind_B64, 0, sizeof(B64), &type_nil, str8_lit_comp("B64")};
|
||||
read_only global Type F32__type = {TypeKind_F32, 0, sizeof(F32), &type_nil, str8_lit_comp("F32")};
|
||||
read_only global Type F64__type = {TypeKind_F64, 0, sizeof(F64), &type_nil, str8_lit_comp("F64")};
|
||||
read_only global Type *type_kind_type_table[] =
|
||||
{
|
||||
&type_nil,
|
||||
type(void),
|
||||
type(U8),
|
||||
type(U16),
|
||||
type(U32),
|
||||
type(U64),
|
||||
type(S8),
|
||||
type(S16),
|
||||
type(S32),
|
||||
type(S64),
|
||||
type(B8),
|
||||
type(B16),
|
||||
type(B32),
|
||||
type(B64),
|
||||
type(F32),
|
||||
type(F64),
|
||||
&type_nil,
|
||||
&type_nil,
|
||||
&type_nil,
|
||||
&type_nil,
|
||||
&type_nil,
|
||||
};
|
||||
|
||||
//- rjf: Rng1U64
|
||||
struct_members(Rng1U64)
|
||||
|
||||
+36
-14
@@ -43,26 +43,48 @@
|
||||
# define ProfLockTake(...) tmAcquiredLock(0, 0, __VA_ARGS__)
|
||||
# define ProfLockDrop(...) tmReleasedLock(0, __VA_ARGS__)
|
||||
# define ProfColor(color) tmZoneColorSticky(color)
|
||||
# define ProfBeginV(...) \
|
||||
if (TM_API_PTR) { \
|
||||
static tm_uint64 file_id = 0; TM_API_PTR->_tmStaticString(&file_id, __FILE__); \
|
||||
Temp scratch = scratch_begin(0,0); \
|
||||
String8 string = push_str8f(scratch.arena, __VA_ARGS__); \
|
||||
tm_uint64 hash = TM_API_PTR->_tmHash((char*)string.str, string.size); \
|
||||
hash = TM_API_PTR->_tmSendDynamicString(hash, (char*)string.str); \
|
||||
TM_API_PTR->_tmEnterZoneFast_Core(0, 0, file_id, __LINE__, hash); \
|
||||
scratch_end(scratch); \
|
||||
}
|
||||
# define ProfNoteV(...) \
|
||||
if (TM_API_PTR) { \
|
||||
static tm_uint64 file_id = 0; TM_API_PTR->_tmStaticString(&file_id, __FILE__); \
|
||||
Temp scratch = scratch_begin(0,0); \
|
||||
String8 string = push_str8f(scratch.arena, __VA_ARGS__); \
|
||||
tm_uint64 hash = TM_API_PTR->_tmHash((char*)string.str, string.size); \
|
||||
hash = TM_API_PTR->_tmSendDynamicString(hash, (char*)string.str); \
|
||||
TM_API_PTR->_tmMessageFast_Core(0, TMMF_ICON_NOTE, file_id, __LINE__, hash); \
|
||||
scratch_end(scratch); \
|
||||
}
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Zeroify Undefined Defines
|
||||
|
||||
#if !defined(ProfBegin)
|
||||
# define ProfBegin(...) (0)
|
||||
# define ProfBeginDynamic(...) (0)
|
||||
# define ProfEnd(...) (0)
|
||||
# define ProfTick(...) (0)
|
||||
# define ProfIsCapturing(...) (0)
|
||||
# define ProfBeginCapture(...) (0)
|
||||
# define ProfEndCapture(...) (0)
|
||||
# define ProfThreadName(...) (0)
|
||||
# define ProfMsg(...) (0)
|
||||
# define ProfBeginLockWait(...) (0)
|
||||
# define ProfEndLockWait(...) (0)
|
||||
# define ProfLockTake(...) (0)
|
||||
# define ProfLockDrop(...) (0)
|
||||
# define ProfColor(...) (0)
|
||||
# define ProfBegin(...) (0)
|
||||
# define ProfBeginDynamic(...) (0)
|
||||
# define ProfEnd(...) (0)
|
||||
# define ProfTick(...) (0)
|
||||
# define ProfIsCapturing(...) (0)
|
||||
# define ProfBeginCapture(...) (0)
|
||||
# define ProfEndCapture(...) (0)
|
||||
# define ProfThreadName(...) (0)
|
||||
# define ProfMsg(...) (0)
|
||||
# define ProfBeginLockWait(...) (0)
|
||||
# define ProfEndLockWait(...) (0)
|
||||
# define ProfLockTake(...) (0)
|
||||
# define ProfLockDrop(...) (0)
|
||||
# define ProfColor(...) (0)
|
||||
# define ProfBeginV(...) (0)
|
||||
# define ProfNoteV(...) (0)
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
+297
-42
@@ -215,12 +215,42 @@ str32_cstring(U32 *c){
|
||||
internal String8
|
||||
str8_cstring_capped(void *cstr, void *cap)
|
||||
{
|
||||
char *ptr = (char*)cstr;
|
||||
char *opl = (char*)cap;
|
||||
char *ptr = (char *)cstr;
|
||||
char *opl = (char *)cap;
|
||||
for (;ptr < opl && *ptr != 0; ptr += 1);
|
||||
U64 size = (U64)(ptr - (char *)cstr);
|
||||
String8 result = {(U8*)cstr, size};
|
||||
return(result);
|
||||
String8 result = str8((U8*)cstr, size);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String16
|
||||
str16_cstring_capped(void *cstr, void *cap)
|
||||
{
|
||||
U16 *ptr = (U16 *)cstr;
|
||||
U16 *opl = (U16 *)cap;
|
||||
for (;ptr < opl && *ptr != 0; ptr += 1);
|
||||
U64 size = (U64)(ptr - (U16 *)cstr);
|
||||
String16 result = str16(cstr, size);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String8
|
||||
str8_cstring_capped_reverse(void *raw_start, void *raw_cap)
|
||||
{
|
||||
U8 *start = raw_start;
|
||||
U8 *ptr = raw_cap;
|
||||
for(; ptr > start; )
|
||||
{
|
||||
ptr -= 1;
|
||||
|
||||
if (*ptr == '\0')
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
U64 size = (U64)(ptr - start);
|
||||
String8 result = str8(start, size);
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
@@ -263,31 +293,41 @@ backslashed_from_str8(Arena *arena, String8 string)
|
||||
//~ rjf: String Matching
|
||||
|
||||
internal B32
|
||||
str8_match(String8 a, String8 b, StringMatchFlags flags){
|
||||
str8_match(String8 a, String8 b, StringMatchFlags flags)
|
||||
{
|
||||
B32 result = 0;
|
||||
if (a.size == b.size || (flags & StringMatchFlag_RightSideSloppy)){
|
||||
B32 case_insensitive = (flags & StringMatchFlag_CaseInsensitive);
|
||||
if(a.size == b.size && flags == 0)
|
||||
{
|
||||
result = MemoryMatch(a.str, b.str, b.size);
|
||||
}
|
||||
else if(a.size == b.size || (flags & StringMatchFlag_RightSideSloppy))
|
||||
{
|
||||
B32 case_insensitive = (flags & StringMatchFlag_CaseInsensitive);
|
||||
B32 slash_insensitive = (flags & StringMatchFlag_SlashInsensitive);
|
||||
U64 size = Min(a.size, b.size);
|
||||
U64 size = Min(a.size, b.size);
|
||||
result = 1;
|
||||
for (U64 i = 0; i < size; i += 1){
|
||||
for(U64 i = 0; i < size; i += 1)
|
||||
{
|
||||
U8 at = a.str[i];
|
||||
U8 bt = b.str[i];
|
||||
if (case_insensitive){
|
||||
if(case_insensitive)
|
||||
{
|
||||
at = char_to_upper(at);
|
||||
bt = char_to_upper(bt);
|
||||
}
|
||||
if (slash_insensitive){
|
||||
if(slash_insensitive)
|
||||
{
|
||||
at = char_to_correct_slash(at);
|
||||
bt = char_to_correct_slash(bt);
|
||||
}
|
||||
if (at != bt){
|
||||
if(at != bt)
|
||||
{
|
||||
result = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal U64
|
||||
@@ -322,6 +362,22 @@ str8_find_needle(String8 string, U64 start_pos, String8 needle, StringMatchFlags
|
||||
return(result);
|
||||
}
|
||||
|
||||
internal U64
|
||||
str8_find_needle_reverse(String8 string, U64 start_pos, String8 needle, StringMatchFlags flags)
|
||||
{
|
||||
U64 result = 0;
|
||||
for(S64 i = string.size - start_pos - needle.size; i >= 0; --i)
|
||||
{
|
||||
String8 haystack = str8_substr(string, rng_1u64(i, i + needle.size));
|
||||
if(str8_match(haystack, needle, flags))
|
||||
{
|
||||
result = (U64)i + needle.size;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal B32
|
||||
str8_ends_with(String8 string, String8 end, StringMatchFlags flags){
|
||||
String8 postfix = str8_postfix(string, end.size);
|
||||
@@ -544,21 +600,121 @@ try_s64_from_str8_c_rules(String8 string, S64 *x){
|
||||
//- rjf: integer -> string
|
||||
|
||||
internal String8
|
||||
str8_from_memory_size(Arena *arena, U64 z){
|
||||
String8 result = {0};
|
||||
if (z < KB(1)){
|
||||
result = push_str8f(arena, "%llu b", z);
|
||||
str8_from_memory_size(Arena *arena, U64 size)
|
||||
{
|
||||
String8 result;
|
||||
|
||||
if(size < KB(1))
|
||||
{
|
||||
result = push_str8f(arena, "%llu Bytes", size);
|
||||
}
|
||||
else if (z < MB(1)){
|
||||
result = push_str8f(arena, "%llu.%02llu Kb", z/KB(1), ((100*z)/KB(1))%100);
|
||||
else if(size < MB(1))
|
||||
{
|
||||
result = push_str8f(arena, "%llu.%02llu KiB", size / KB(1), ((size * 100) / KB(1)) % 100);
|
||||
}
|
||||
else if (z < GB(1)){
|
||||
result = push_str8f(arena, "%llu.%02llu Mb", z/MB(1), ((100*z)/MB(1))%100);
|
||||
else if(size < GB(1))
|
||||
{
|
||||
result = push_str8f(arena, "%llu.%02llu MiB", size / MB(1), ((size * 100) / MB(1)) % 100);
|
||||
}
|
||||
else{
|
||||
result = push_str8f(arena, "%llu.%02llu Gb", z/GB(1), ((100*z)/GB(1))%100);
|
||||
else if(size < TB(1))
|
||||
{
|
||||
result = push_str8f(arena, "%llu.%02llu GiB", size / GB(1), ((size * 100) / GB(1)) % 100);
|
||||
}
|
||||
return(result);
|
||||
else
|
||||
{
|
||||
result = push_str8f(arena, "%llu.%02llu TiB", size / TB(1), ((size * 100) / TB(1)) % 100);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String8
|
||||
str8_from_count(Arena *arena, U64 count)
|
||||
{
|
||||
String8 result;
|
||||
|
||||
if(count < 1 * 1000)
|
||||
{
|
||||
result = push_str8f(arena, "%llu", count);
|
||||
}
|
||||
else if(count < 1000000)
|
||||
{
|
||||
U64 frac = ((count * 100) / 1000) % 100;
|
||||
if(frac > 0)
|
||||
{
|
||||
result = push_str8f(arena, "%llu.%02lluK", count / 1000, frac);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = push_str8f(arena, "%lluK", count / 1000);
|
||||
}
|
||||
}
|
||||
else if(count < 1000000000)
|
||||
{
|
||||
U64 frac = ((count * 100) / 1000000) % 100;
|
||||
if(frac > 0)
|
||||
{
|
||||
result = push_str8f(arena, "%llu.%02lluM", count / 1000000, frac);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = push_str8f(arena, "%lluM", count / 1000000);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
U64 frac = ((count * 100) * 1000000000) % 100;
|
||||
if(frac > 0)
|
||||
{
|
||||
result = push_str8f(arena, "%llu.%02lluB", count / 1000000000, frac);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = push_str8f(arena, "%lluB", count / 1000000000, frac);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String8
|
||||
str8_from_bits_u32(Arena *arena, U32 x)
|
||||
{
|
||||
U8 c0 = 'a' + ((x >> 28) & 0xf);
|
||||
U8 c1 = 'a' + ((x >> 24) & 0xf);
|
||||
U8 c2 = 'a' + ((x >> 20) & 0xf);
|
||||
U8 c3 = 'a' + ((x >> 16) & 0xf);
|
||||
U8 c4 = 'a' + ((x >> 12) & 0xf);
|
||||
U8 c5 = 'a' + ((x >> 8) & 0xf);
|
||||
U8 c6 = 'a' + ((x >> 4) & 0xf);
|
||||
U8 c7 = 'a' + ((x >> 0) & 0xf);
|
||||
String8 result = push_str8f(arena, "%c%c%c%c%c%c%c%c", c0, c1, c2, c3, c4, c5, c6, c7);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String8
|
||||
str8_from_bits_u64(Arena *arena, U64 x)
|
||||
{
|
||||
U8 c0 = 'a' + ((x >> 60) & 0xf);
|
||||
U8 c1 = 'a' + ((x >> 56) & 0xf);
|
||||
U8 c2 = 'a' + ((x >> 52) & 0xf);
|
||||
U8 c3 = 'a' + ((x >> 48) & 0xf);
|
||||
U8 c4 = 'a' + ((x >> 44) & 0xf);
|
||||
U8 c5 = 'a' + ((x >> 40) & 0xf);
|
||||
U8 c6 = 'a' + ((x >> 36) & 0xf);
|
||||
U8 c7 = 'a' + ((x >> 32) & 0xf);
|
||||
U8 c8 = 'a' + ((x >> 28) & 0xf);
|
||||
U8 c9 = 'a' + ((x >> 24) & 0xf);
|
||||
U8 ca = 'a' + ((x >> 20) & 0xf);
|
||||
U8 cb = 'a' + ((x >> 16) & 0xf);
|
||||
U8 cc = 'a' + ((x >> 12) & 0xf);
|
||||
U8 cd = 'a' + ((x >> 8) & 0xf);
|
||||
U8 ce = 'a' + ((x >> 4) & 0xf);
|
||||
U8 cf = 'a' + ((x >> 0) & 0xf);
|
||||
String8 result = push_str8f(arena,
|
||||
"%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c",
|
||||
c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, ca, cb, cc, cd, ce, cf);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String8
|
||||
@@ -685,27 +841,28 @@ f64_from_str8(String8 string)
|
||||
{
|
||||
// rjf: find starting pos of numeric string, as well as sign
|
||||
F64 sign = +1.0;
|
||||
//U64 first_numeric = 0;
|
||||
if(string.str[0] == '-')
|
||||
{
|
||||
//first_numeric = 1;
|
||||
sign = -1.0;
|
||||
}
|
||||
else if(string.str[0] == '+')
|
||||
{
|
||||
//first_numeric = 1;
|
||||
sign = 1.0;
|
||||
}
|
||||
|
||||
// rjf: gather numerics
|
||||
U64 num_valid_chars = 0;
|
||||
char buffer[64];
|
||||
B32 exp = 0;
|
||||
for(U64 idx = 0; idx < string.size && num_valid_chars < sizeof(buffer)-1; idx += 1)
|
||||
{
|
||||
if(char_is_digit(string.str[idx], 10) || string.str[idx] == '.')
|
||||
if(char_is_digit(string.str[idx], 10) || string.str[idx] == '.' || string.str[idx] == 'e' ||
|
||||
(exp && (string.str[idx] == '+' || string.str[idx] == '-')))
|
||||
{
|
||||
buffer[num_valid_chars] = string.str[idx];
|
||||
num_valid_chars += 1;
|
||||
exp = 0;
|
||||
exp = (string.str[idx] == 'e');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1138,7 +1295,9 @@ 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){
|
||||
StringJoin params = {0};
|
||||
switch (style){
|
||||
switch(style)
|
||||
{
|
||||
case PathStyle_Null:{}break;
|
||||
case PathStyle_Relative:
|
||||
case PathStyle_WindowsAbsolute:
|
||||
{
|
||||
@@ -1151,9 +1310,8 @@ str8_path_list_join_by_style(Arena *arena, String8List *path, PathStyle style){
|
||||
params.sep = str8_lit("/");
|
||||
}break;
|
||||
}
|
||||
|
||||
String8 result = str8_list_join(arena, path, ¶ms);
|
||||
return(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String8TxtPtPair
|
||||
@@ -1412,6 +1570,35 @@ str32_from_8(Arena *arena, String8 in){
|
||||
return(str32(str, size));
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ String -> Enum Conversions
|
||||
|
||||
read_only global struct
|
||||
{
|
||||
String8 string;
|
||||
OperatingSystem os;
|
||||
} g_os_enum_map[] =
|
||||
{
|
||||
{ str8_lit_comp(""), OperatingSystem_Null },
|
||||
{ str8_lit_comp("Windows"), OperatingSystem_Windows, },
|
||||
{ str8_lit_comp("Linux"), OperatingSystem_Linux, },
|
||||
{ str8_lit_comp("Mac"), OperatingSystem_Mac, },
|
||||
};
|
||||
StaticAssert(ArrayCount(g_os_enum_map) == OperatingSystem_COUNT, g_os_enum_map_count_check);
|
||||
|
||||
internal OperatingSystem
|
||||
operating_system_from_string(String8 string)
|
||||
{
|
||||
for(U64 i = 0; i < ArrayCount(g_os_enum_map); ++i)
|
||||
{
|
||||
if(str8_match(g_os_enum_map[i].string, string, StringMatchFlag_CaseInsensitive))
|
||||
{
|
||||
return g_os_enum_map[i].os;
|
||||
}
|
||||
}
|
||||
return OperatingSystem_Null;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Types & Space Enum -> String Conversions
|
||||
|
||||
@@ -1444,18 +1631,14 @@ string_from_side(Side side){
|
||||
}
|
||||
|
||||
internal String8
|
||||
string_from_operating_system(OperatingSystem os){
|
||||
local_persist String8 strings[] = {
|
||||
str8_lit_comp("Null"),
|
||||
str8_lit_comp("Windows"),
|
||||
str8_lit_comp("Linux"),
|
||||
str8_lit_comp("Mac"),
|
||||
};
|
||||
String8 result = str8_lit("error");
|
||||
if (os < OperatingSystem_COUNT){
|
||||
result = strings[os];
|
||||
string_from_operating_system(OperatingSystem os)
|
||||
{
|
||||
String8 result = g_os_enum_map[OperatingSystem_Null].string;
|
||||
if(os < ArrayCount(g_os_enum_map))
|
||||
{
|
||||
result = g_os_enum_map[os].string;
|
||||
}
|
||||
return(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String8
|
||||
@@ -1565,6 +1748,78 @@ string_from_elapsed_time(Arena *arena, DateTime dt){
|
||||
return(result);
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ Globally UNique Ids
|
||||
|
||||
internal String8
|
||||
string_from_guid(Arena *arena, Guid guid)
|
||||
{
|
||||
String8 result = push_str8f(arena, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
|
||||
guid.data1,
|
||||
guid.data2,
|
||||
guid.data3,
|
||||
guid.data4[0],
|
||||
guid.data4[1],
|
||||
guid.data4[2],
|
||||
guid.data4[3],
|
||||
guid.data4[4],
|
||||
guid.data4[5],
|
||||
guid.data4[6],
|
||||
guid.data4[7]);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal B32
|
||||
try_guid_from_string(String8 string, Guid *guid_out)
|
||||
{
|
||||
Temp scratch = scratch_begin(0,0);
|
||||
B32 is_parsed = 0;
|
||||
String8List list = str8_split_by_string_chars(scratch.arena, string, str8_lit("-"), StringSplitFlag_KeepEmpties);
|
||||
if(list.node_count == 5)
|
||||
{
|
||||
String8 data1_str = list.first->string;
|
||||
String8 data2_str = list.first->next->string;
|
||||
String8 data3_str = list.first->next->next->string;
|
||||
String8 data4_hi_str = list.first->next->next->next->string;
|
||||
String8 data4_lo_str = list.first->next->next->next->next->string;
|
||||
if(str8_is_integer(data1_str, 16) &&
|
||||
str8_is_integer(data2_str, 16) &&
|
||||
str8_is_integer(data3_str, 16) &&
|
||||
str8_is_integer(data4_hi_str, 16) &&
|
||||
str8_is_integer(data4_lo_str, 16))
|
||||
{
|
||||
U64 data1 = u64_from_str8(data1_str, 16);
|
||||
U64 data2 = u64_from_str8(data2_str, 16);
|
||||
U64 data3 = u64_from_str8(data3_str, 16);
|
||||
U64 data4_hi = u64_from_str8(data4_hi_str, 16);
|
||||
U64 data4_lo = u64_from_str8(data4_lo_str, 16);
|
||||
if(data1 <= max_U32 &&
|
||||
data2 <= max_U16 &&
|
||||
data3 <= max_U16 &&
|
||||
data4_hi <= max_U16 &&
|
||||
data4_lo <= 0xffffffffffff)
|
||||
{
|
||||
guid_out->data1 = (U32)data1;
|
||||
guid_out->data2 = (U16)data2;
|
||||
guid_out->data3 = (U16)data3;
|
||||
U64 data4 = (data4_hi << 48) | data4_lo;
|
||||
MemoryCopy(&guid_out->data4[0], &data4, sizeof(data4));
|
||||
is_parsed = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
scratch_end(scratch);
|
||||
return is_parsed;
|
||||
}
|
||||
|
||||
internal Guid
|
||||
guid_from_string(String8 string)
|
||||
{
|
||||
Guid guid = {0};
|
||||
try_guid_from_string(string, &guid);
|
||||
return guid;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Text Indentation
|
||||
|
||||
|
||||
+19
-1
@@ -193,6 +193,8 @@ internal String8 str8_cstring(char *c);
|
||||
internal String16 str16_cstring(U16 *c);
|
||||
internal String32 str32_cstring(U32 *c);
|
||||
internal String8 str8_cstring_capped(void *cstr, void *cap);
|
||||
internal String16 str16_cstring_capped(void *cstr, void *cap);
|
||||
internal String8 str8_cstring_capped_reverse(void *raw_start, void *raw_cap);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Stylization
|
||||
@@ -206,6 +208,7 @@ internal String8 backslashed_from_str8(Arena *arena, String8 string);
|
||||
|
||||
internal B32 str8_match(String8 a, String8 b, StringMatchFlags flags);
|
||||
internal U64 str8_find_needle(String8 string, U64 start_pos, String8 needle, StringMatchFlags flags);
|
||||
internal U64 str8_find_needle_reverse(String8 string, U64 start_pos, String8 needle, StringMatchFlags flags);
|
||||
internal B32 str8_ends_with(String8 string, String8 end, StringMatchFlags flags);
|
||||
|
||||
////////////////////////////////
|
||||
@@ -238,7 +241,10 @@ internal B32 try_u64_from_str8_c_rules(String8 string, U64 *x);
|
||||
internal B32 try_s64_from_str8_c_rules(String8 string, S64 *x);
|
||||
|
||||
//- rjf: integer -> string
|
||||
internal String8 str8_from_memory_size(Arena *arena, U64 z);
|
||||
internal String8 str8_from_memory_size(Arena *arena, U64 size);
|
||||
internal String8 str8_from_count(Arena *arena, U64 count);
|
||||
internal String8 str8_from_bits_u32(Arena *arena, U32 x);
|
||||
internal String8 str8_from_bits_u64(Arena *arena, U64 x);
|
||||
internal String8 str8_from_u64(Arena *arena, U64 u64, U32 radix, U8 min_digits, U8 digit_group_separator);
|
||||
internal String8 str8_from_s64(Arena *arena, S64 s64, U32 radix, U8 min_digits, U8 digit_group_separator);
|
||||
|
||||
@@ -310,6 +316,11 @@ internal String16 str16_from_8(Arena *arena, String8 in);
|
||||
internal String8 str8_from_32(Arena *arena, String32 in);
|
||||
internal String32 str32_from_8(Arena *arena, String8 in);
|
||||
|
||||
////////////////////////////////
|
||||
//~ String -> Enum Conversions
|
||||
|
||||
internal OperatingSystem operating_system_from_string(String8 string);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Types & Space Enum -> String Conversions
|
||||
|
||||
@@ -327,6 +338,13 @@ internal String8 push_date_time_string(Arena *arena, DateTime *date_time);
|
||||
internal String8 push_file_name_date_time_string(Arena *arena, DateTime *date_time);
|
||||
internal String8 string_from_elapsed_time(Arena *arena, DateTime dt);
|
||||
|
||||
////////////////////////////////
|
||||
//~ Globally Unique Ids
|
||||
|
||||
internal String8 string_from_guid(Arena *arena, Guid guid);
|
||||
internal B32 try_guid_from_string(String8 string, Guid *guid_out);
|
||||
internal Guid guid_from_string(String8 string);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Text Indentation
|
||||
|
||||
|
||||
+10
-8
@@ -490,12 +490,8 @@ cv_c13_parsed_from_data(Arena *arena, String8 c13_data, String8 strtbl, COFF_Sec
|
||||
CV_C13SubSecLinesHeader *hdr = (CV_C13SubSecLinesHeader*)(first + read_off);
|
||||
read_off += sizeof(*hdr);
|
||||
|
||||
// extract top level info
|
||||
// rjf: extract section index
|
||||
U32 sec_idx = hdr->sec;
|
||||
B32 has_cols = !!(hdr->flags & CV_C13SubSecLinesFlag_HasColumns);
|
||||
U64 secrel_off = hdr->sec_off;
|
||||
U64 secrel_opl = secrel_off + hdr->len;
|
||||
U64 sec_base_off = sections.v[sec_idx - 1].voff;
|
||||
|
||||
// rjf: bad section index -> skip
|
||||
if(sec_idx < 1 || sections.count < sec_idx)
|
||||
@@ -503,6 +499,12 @@ cv_c13_parsed_from_data(Arena *arena, String8 c13_data, String8 strtbl, COFF_Sec
|
||||
continue;
|
||||
}
|
||||
|
||||
// extract top level info
|
||||
B32 has_cols = !!(hdr->flags & CV_C13SubSecLinesFlag_HasColumns);
|
||||
U64 secrel_off = hdr->sec_off;
|
||||
U64 secrel_opl = secrel_off + hdr->len;
|
||||
U64 sec_base_off = sections.v[sec_idx - 1].voff;
|
||||
|
||||
// read files
|
||||
for(;read_off+sizeof(CV_C13File) <= read_off_opl;)
|
||||
{
|
||||
@@ -519,7 +521,7 @@ cv_c13_parsed_from_data(Arena *arena, String8 c13_data, String8 strtbl, COFF_Sec
|
||||
CV_C13Checksum *checksum = (CV_C13Checksum*)(c13_data.str + file_chksms->off + file_off);
|
||||
U32 name_off = checksum->name_off;
|
||||
file_name = str8_cstring_capped((char*)(strtbl.str + name_off),
|
||||
(char*)(strtbl.str + strtbl.size));
|
||||
(char*)(strtbl.str + strtbl.size));
|
||||
}
|
||||
|
||||
// array layouts
|
||||
@@ -596,7 +598,7 @@ cv_c13_parsed_from_data(Arena *arena, String8 c13_data, String8 strtbl, COFF_Sec
|
||||
CV_C13Checksum *checksum = (CV_C13Checksum*)(c13_data.str + file_chksms->off + hdr->file_off);
|
||||
U32 name_off = checksum->name_off;
|
||||
file_name = str8_cstring_capped((char*)(strtbl.str + name_off),
|
||||
(char*)(strtbl.str + strtbl.size));
|
||||
(char*)(strtbl.str + strtbl.size));
|
||||
}
|
||||
|
||||
// rjf: parse extra files
|
||||
@@ -617,7 +619,7 @@ cv_c13_parsed_from_data(Arena *arena, String8 c13_data, String8 strtbl, COFF_Sec
|
||||
SLLQueuePush(node->inlinee_lines_first, node->inlinee_lines_last, n);
|
||||
n->v.inlinee = hdr->inlinee;
|
||||
n->v.file_name = file_name;
|
||||
n->v.file_off = hdr->file_off;
|
||||
n->v.file_off = hdr->file_off;
|
||||
n->v.first_source_ln = hdr->first_source_ln;
|
||||
n->v.extra_file_count = extra_file_count;
|
||||
n->v.extra_files = extra_files;
|
||||
|
||||
+160
-142
@@ -97,15 +97,17 @@ coff_header_info_from_data(String8 data)
|
||||
COFF_HeaderInfo info = {0};
|
||||
if (coff_is_big_obj(data)) {
|
||||
COFF_HeaderBigObj *big_header = (COFF_HeaderBigObj*)data.str;
|
||||
info.machine = big_header->machine;
|
||||
info.section_array_off = sizeof(COFF_HeaderBigObj);
|
||||
info.section_count_no_null = big_header->section_count;
|
||||
info.string_table_off = big_header->pointer_to_symbol_table + sizeof(COFF_Symbol32) * big_header->number_of_symbols;
|
||||
info.symbol_size = sizeof(COFF_Symbol32);
|
||||
info.symbol_off = big_header->pointer_to_symbol_table;
|
||||
info.symbol_count = big_header->number_of_symbols;
|
||||
info.type = COFF_DataType_BIG_OBJ;
|
||||
info.machine = big_header->machine;
|
||||
info.section_array_off = sizeof(COFF_HeaderBigObj);
|
||||
info.section_count_no_null = big_header->section_count;
|
||||
info.string_table_off = big_header->pointer_to_symbol_table + sizeof(COFF_Symbol32) * big_header->number_of_symbols;
|
||||
info.symbol_size = sizeof(COFF_Symbol32);
|
||||
info.symbol_off = big_header->pointer_to_symbol_table;
|
||||
info.symbol_count = big_header->number_of_symbols;
|
||||
} else if (coff_is_obj(data)) {
|
||||
COFF_Header *header = (COFF_Header*)data.str;
|
||||
COFF_Header *header = (COFF_Header*)data.str;
|
||||
info.type = COFF_DataType_OBJ;
|
||||
info.machine = header->machine;
|
||||
info.section_array_off = sizeof(COFF_Header);
|
||||
info.section_count_no_null = header->section_count;
|
||||
@@ -143,6 +145,30 @@ coff_align_size_from_section_flags(COFF_SectionFlags flags)
|
||||
return align;
|
||||
}
|
||||
|
||||
internal COFF_SectionFlags
|
||||
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;
|
||||
}
|
||||
flags <<= COFF_SectionFlag_ALIGN_SHIFT;
|
||||
return flags;
|
||||
}
|
||||
|
||||
internal COFF_SymbolValueInterpType
|
||||
coff_interp_symbol(COFF_Symbol32 *symbol)
|
||||
{
|
||||
@@ -550,6 +576,39 @@ coff_make_import_header_by_ordinal(Arena *arena,
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ Resources
|
||||
|
||||
internal String8
|
||||
coff_resource_string_from_str16(Arena *arena, String16 string)
|
||||
{
|
||||
AssertAlways(string.size <= max_U16);
|
||||
U16 size16 = (U16)string.size;
|
||||
|
||||
U16 *buffer = push_array_no_zero(arena, U16, size16 + 1);
|
||||
MemoryCopy(buffer + 0, &size16, sizeof(size16));
|
||||
MemoryCopy(buffer + 1, string.str, size16 * sizeof(string.str[0]));
|
||||
|
||||
return str8_array(buffer, size16 + 1);
|
||||
}
|
||||
|
||||
internal String8
|
||||
coff_resource_string_from_str8(Arena *arena, String8 string)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
String16 string16 = str16_from_8(scratch.arena, string);
|
||||
String8 result = coff_resource_string_from_str16(arena, string16);
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String8
|
||||
coff_resource_number_from_u16(Arena *arena, U16 number)
|
||||
{
|
||||
U16 *buffer = push_array_no_zero(arena, U16, 2);
|
||||
buffer[0] = max_U16;
|
||||
buffer[1] = number;
|
||||
return str8_array(buffer, 2);
|
||||
}
|
||||
|
||||
internal B32
|
||||
coff_resource_id_is_equal(COFF_ResourceID a, COFF_ResourceID b)
|
||||
@@ -567,47 +626,9 @@ coff_resource_id_is_equal(COFF_ResourceID a, COFF_ResourceID b)
|
||||
}
|
||||
|
||||
internal COFF_ResourceID
|
||||
coff_resource_id_copy(Arena *arena, COFF_ResourceID id)
|
||||
coff_utf8_resource_id_from_utf16(Arena *arena, COFF_ResourceID_16 *id_16)
|
||||
{
|
||||
COFF_ResourceID result = zero_struct;
|
||||
switch (id.type) {
|
||||
case COFF_ResourceIDType_NULL: break;
|
||||
case COFF_ResourceIDType_NUMBER: {
|
||||
result.type = COFF_ResourceIDType_NUMBER;
|
||||
result.u.number = id.u.number;
|
||||
} break;
|
||||
case COFF_ResourceIDType_STRING: {
|
||||
result.type = COFF_ResourceIDType_STRING;
|
||||
result.u.string = id.u.string;
|
||||
} break;
|
||||
default: Assert(!"invalid resource id type");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal U64
|
||||
coff_sizeof_resource_id(COFF_ResourceID id)
|
||||
{
|
||||
U64 size = 0;
|
||||
switch (id.type) {
|
||||
case COFF_ResourceIDType_NULL: break;
|
||||
case COFF_ResourceIDType_NUMBER: {
|
||||
size += sizeof(U16);
|
||||
size += sizeof(U16);
|
||||
} break;
|
||||
case COFF_ResourceIDType_STRING: {
|
||||
size += sizeof(U16);
|
||||
size += (id.u.string.size + /* null: */1) * sizeof(U16);
|
||||
} break;
|
||||
default: InvalidPath;
|
||||
}
|
||||
return AlignPow2(size, COFF_RES_ALIGN);
|
||||
}
|
||||
|
||||
internal COFF_ResourceID
|
||||
coff_convert_resource_id(Arena *arena, COFF_ResourceID_16 *id_16)
|
||||
{
|
||||
COFF_ResourceID id;
|
||||
COFF_ResourceID id = {0};
|
||||
id.type = id_16->type;
|
||||
switch (id_16->type) {
|
||||
case COFF_ResourceIDType_NULL: break;
|
||||
@@ -617,23 +638,22 @@ coff_convert_resource_id(Arena *arena, COFF_ResourceID_16 *id_16)
|
||||
case COFF_ResourceIDType_STRING: {
|
||||
id.u.string = str8_from_16(arena, id_16->u.string);
|
||||
} break;
|
||||
default: Assert(!"invalid resource id type");
|
||||
default: InvalidPath;
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
internal U64
|
||||
coff_read_resource_id(String8 data, U64 off, COFF_ResourceID_16 *id_out)
|
||||
coff_read_resource_id_utf16(String8 data, U64 off, COFF_ResourceID_16 *id_out)
|
||||
{
|
||||
U64 cursor = off;
|
||||
|
||||
U16 flag = 0;
|
||||
str8_deserial_read_struct(data, cursor, &flag);
|
||||
|
||||
B32 is_number = flag == max_U16;
|
||||
if (is_number) {
|
||||
cursor += sizeof(flag);
|
||||
if (flag == max_U16) {
|
||||
id_out->type = COFF_ResourceIDType_NUMBER;
|
||||
cursor += sizeof(flag);
|
||||
cursor += str8_deserial_read_struct(data, cursor, &id_out->u.number);
|
||||
} else {
|
||||
id_out->type = COFF_ResourceIDType_STRING;
|
||||
@@ -641,93 +661,81 @@ coff_read_resource_id(String8 data, U64 off, COFF_ResourceID_16 *id_out)
|
||||
}
|
||||
|
||||
U64 read_size = cursor - off;
|
||||
read_size = AlignPow2(read_size, COFF_RES_ALIGN);
|
||||
return read_size;
|
||||
}
|
||||
|
||||
internal U64
|
||||
coff_read_resource(String8 raw_res, U64 off, Arena *arena, COFF_Resource *res_out)
|
||||
{
|
||||
// parse header
|
||||
COFF_ResourceHeaderPrefix prefix; MemoryZeroStruct(&prefix);
|
||||
U64 cursor = str8_deserial_read_struct(raw_res, off, &prefix);
|
||||
String8 header_data = str8_substr(raw_res, rng_1u64(off, off + prefix.header_size));
|
||||
String8 raw_header = str8_skip(raw_res, off);
|
||||
U64 header_cursor = 0;
|
||||
|
||||
// prefix
|
||||
COFF_ResourceHeaderPrefix prefix = {0};
|
||||
header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &prefix);
|
||||
|
||||
Assert(prefix.header_size >= sizeof(COFF_ResourceHeaderPrefix));
|
||||
raw_header = str8_prefix(raw_header, prefix.header_size);
|
||||
|
||||
// header
|
||||
COFF_ResourceID_16 type_16 = {0};
|
||||
COFF_ResourceID_16 name_16 = {0};
|
||||
header_cursor += coff_read_resource_id_utf16(raw_header, header_cursor, &type_16);
|
||||
header_cursor += coff_read_resource_id_utf16(raw_header, header_cursor, &name_16);
|
||||
header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &res_out->data_version);
|
||||
header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &res_out->memory_flags);
|
||||
header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &res_out->language_id);
|
||||
header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &res_out->version);
|
||||
header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &res_out->characteristics);
|
||||
Assert(prefix.header_size == header_cursor);
|
||||
|
||||
// convert utf-16 resource ids to utf-8
|
||||
res_out->type = coff_utf8_resource_id_from_utf16(arena, &type_16);
|
||||
res_out->name = coff_utf8_resource_id_from_utf16(arena, &name_16);
|
||||
|
||||
// read data
|
||||
U64 data_read_size = str8_deserial_read_block(raw_res, off + prefix.header_size, prefix.data_size, &res_out->data);
|
||||
Assert(prefix.data_size == data_read_size);
|
||||
|
||||
COFF_ResourceID_16 type_16; MemoryZeroStruct(&type_16);
|
||||
cursor += coff_read_resource_id(header_data, cursor, &type_16);
|
||||
cursor = AlignPow2(cursor, COFF_RES_ALIGN);
|
||||
|
||||
COFF_ResourceID_16 name_16; MemoryZeroStruct(&name_16);
|
||||
cursor += coff_read_resource_id(header_data, cursor, &name_16);
|
||||
cursor = AlignPow2(cursor, COFF_RES_ALIGN);
|
||||
|
||||
U32 data_version = 0;
|
||||
cursor += str8_deserial_read_struct(header_data, cursor, &data_version);
|
||||
|
||||
COFF_ResourceMemoryFlags memory_flags = 0;
|
||||
cursor += str8_deserial_read_struct(header_data, cursor, &memory_flags);
|
||||
|
||||
U16 language_id = 0;
|
||||
cursor += str8_deserial_read_struct(header_data, cursor, &language_id);
|
||||
|
||||
U32 version = 0;
|
||||
cursor += str8_deserial_read_struct(header_data, cursor, &version);
|
||||
|
||||
U32 characteristics = 0;
|
||||
cursor += str8_deserial_read_struct(header_data, cursor, &characteristics);
|
||||
|
||||
String8 data;
|
||||
cursor += str8_deserial_read_block(raw_res, off + prefix.header_size, prefix.data_size, &data);
|
||||
|
||||
// was resource parsed?
|
||||
Assert(cursor >= prefix.data_size + prefix.header_size);
|
||||
|
||||
// fill out result
|
||||
res_out->type = coff_convert_resource_id(arena, &type_16);
|
||||
res_out->name = coff_convert_resource_id(arena, &name_16);
|
||||
res_out->language_id = language_id;
|
||||
res_out->data_version = data_version;
|
||||
res_out->version = version;
|
||||
res_out->memory_flags = memory_flags;
|
||||
res_out->data = data;
|
||||
|
||||
U64 resource_size = AlignPow2(prefix.data_size + prefix.header_size, COFF_RES_ALIGN);
|
||||
return resource_size;
|
||||
// compute read size
|
||||
U64 read_size = Max(prefix.header_size, sizeof(prefix)) + AlignPow2(prefix.data_size, COFF_RES_ALIGN);
|
||||
return read_size;
|
||||
}
|
||||
|
||||
internal COFF_ResourceList
|
||||
coff_resource_list_from_data(Arena *arena, String8 data)
|
||||
{
|
||||
COFF_ResourceList list; MemoryZeroStruct(&list);
|
||||
for (U64 cursor = 0, stride; cursor < data.size; cursor += stride) {
|
||||
COFF_ResourceList list = {0};
|
||||
U64 cursor;
|
||||
for (cursor = 0 ; cursor < data.size; ) {
|
||||
COFF_ResourceNode *node = push_array(arena, COFF_ResourceNode, 1);
|
||||
stride = coff_read_resource(data, cursor, arena, &node->data);
|
||||
list.count += 1;
|
||||
cursor += coff_read_resource(data, cursor, arena, &node->data);
|
||||
SLLQueuePush(list.first, list.last, node);
|
||||
++list.count;
|
||||
}
|
||||
Assert(cursor == data.size);
|
||||
return list;
|
||||
}
|
||||
|
||||
internal void
|
||||
coff_write_resource_id(Arena *arena, String8List *srl, COFF_ResourceID id)
|
||||
internal String8
|
||||
coff_write_resource_id(Arena *arena, COFF_ResourceID id)
|
||||
{
|
||||
String8 result = str8_zero();
|
||||
switch (id.type) {
|
||||
case COFF_ResourceIDType_NULL: break;
|
||||
case COFF_ResourceIDType_NUMBER: {
|
||||
str8_serial_push_u16(arena, srl, max_U16);
|
||||
str8_serial_push_u16(arena, srl, id.u.number);
|
||||
result = coff_resource_number_from_u16(arena, id.u.number);
|
||||
} break;
|
||||
case COFF_ResourceIDType_STRING: {
|
||||
String16 str16 = str16_from_8(arena, id.u.string);
|
||||
Assert(str16.size <= max_U16);
|
||||
str8_serial_push_u16(arena, srl, str16.size);
|
||||
str8_serial_push_data(arena, srl, str16.str, str16.size);
|
||||
result = coff_resource_string_from_str8(arena, id.u.string);
|
||||
} break;
|
||||
default: InvalidPath;
|
||||
}
|
||||
str8_serial_push_align(arena, srl, COFF_RES_ALIGN);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String8List
|
||||
internal String8
|
||||
coff_write_resource(Arena *arena,
|
||||
COFF_ResourceID type,
|
||||
COFF_ResourceID name,
|
||||
@@ -738,34 +746,43 @@ coff_write_resource(Arena *arena,
|
||||
U32 characteristics,
|
||||
String8 data)
|
||||
{
|
||||
U64 header_size = sizeof(COFF_ResourceHeaderPrefix) +
|
||||
coff_sizeof_resource_id(type) +
|
||||
coff_sizeof_resource_id(name) +
|
||||
sizeof(data_version) +
|
||||
sizeof(memory_flags) +
|
||||
sizeof(language_id) +
|
||||
sizeof(version) +
|
||||
sizeof(characteristics);
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
|
||||
COFF_ResourceHeaderPrefix *header = push_array(arena, COFF_ResourceHeaderPrefix, 1);
|
||||
header->data_size = safe_cast_u32(data.size);
|
||||
header->header_size = safe_cast_u32(header_size);
|
||||
String8List list = {0};
|
||||
|
||||
String8List srl = {0};
|
||||
str8_serial_begin(arena, &srl);
|
||||
str8_serial_push_data(arena, &srl, &g_coff_res_magic[0], sizeof(g_coff_res_magic));
|
||||
str8_serial_push_data(arena, &srl, header, sizeof(*header));
|
||||
coff_write_resource_id(arena, &srl, type);
|
||||
coff_write_resource_id(arena, &srl, name);
|
||||
str8_serial_push_u32(arena, &srl, data_version);
|
||||
str8_serial_push_u16(arena, &srl, memory_flags);
|
||||
str8_serial_push_u16(arena, &srl, language_id);
|
||||
str8_serial_push_u32(arena, &srl, version);
|
||||
str8_serial_push_u32(arena, &srl, characteristics);
|
||||
str8_serial_push_string(arena, &srl, data);
|
||||
str8_serial_push_align(arena, &srl, COFF_RES_ALIGN);
|
||||
COFF_ResourceHeaderPrefix *prefix = push_array(scratch.arena, COFF_ResourceHeaderPrefix, 1);
|
||||
String8 packed_type = coff_write_resource_id(scratch.arena, type);
|
||||
String8 packed_name = coff_write_resource_id(scratch.arena, name);
|
||||
|
||||
return srl;
|
||||
// prefix + header
|
||||
str8_list_push(scratch.arena, &list, str8_struct(prefix));
|
||||
str8_list_push(scratch.arena, &list, packed_type);
|
||||
str8_list_push(scratch.arena, &list, packed_name);
|
||||
str8_list_push(scratch.arena, &list, str8_struct(&data_version));
|
||||
str8_list_push(scratch.arena, &list, str8_struct(&memory_flags));
|
||||
str8_list_push(scratch.arena, &list, str8_struct(&language_id));
|
||||
str8_list_push(scratch.arena, &list, str8_struct(&version));
|
||||
str8_list_push(scratch.arena, &list, str8_struct(&characteristics));
|
||||
|
||||
prefix->data_size = safe_cast_u32(data.size);
|
||||
prefix->header_size = safe_cast_u32(list.total_size);
|
||||
|
||||
// data
|
||||
str8_list_push(scratch.arena, &list, data);
|
||||
|
||||
// magic
|
||||
str8_list_push_front(scratch.arena, &list, str8_array_fixed(g_coff_res_magic));
|
||||
|
||||
// align
|
||||
U64 align_size = AlignPow2(list.total_size, COFF_RES_ALIGN) - list.total_size;
|
||||
U8 *align = push_array(scratch.arena, U8, align_size);
|
||||
str8_list_push(scratch.arena, &list, str8(align, align_size));
|
||||
|
||||
// join
|
||||
String8 res = str8_list_join(arena, &list, 0);
|
||||
|
||||
scratch_end(scratch);
|
||||
return res;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
@@ -777,12 +794,10 @@ coff_data_type_from_data(String8 data)
|
||||
if (is_big_obj) {
|
||||
return COFF_DataType_BIG_OBJ;
|
||||
}
|
||||
|
||||
B32 is_import = coff_is_import(data);
|
||||
if (is_import) {
|
||||
return COFF_DataType_IMPORT;
|
||||
}
|
||||
|
||||
return COFF_DataType_OBJ;
|
||||
}
|
||||
|
||||
@@ -1207,6 +1222,7 @@ read_only struct
|
||||
} 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 },
|
||||
@@ -1259,10 +1275,12 @@ coff_string_from_comdat_select_type(COFF_ComdatSelectType select)
|
||||
internal String8
|
||||
coff_string_from_machine_type(COFF_MachineType machine)
|
||||
{
|
||||
Assert(machine < ArrayCount(g_coff_machine_map));
|
||||
Assert(machine == g_coff_machine_map[machine].machine);
|
||||
String8 string = g_coff_machine_map[machine].string;
|
||||
return string;
|
||||
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
|
||||
|
||||
+272
-298
@@ -77,12 +77,12 @@ typedef struct COFF_Header COFF_Header;
|
||||
struct COFF_Header
|
||||
{
|
||||
COFF_MachineType machine;
|
||||
U16 section_count;
|
||||
COFF_TimeStamp time_stamp;
|
||||
U32 symbol_table_foff;
|
||||
U32 symbol_count;
|
||||
U16 optional_header_size;
|
||||
COFF_Flags flags;
|
||||
U16 section_count;
|
||||
COFF_TimeStamp time_stamp;
|
||||
U32 symbol_table_foff;
|
||||
U32 symbol_count;
|
||||
U16 optional_header_size;
|
||||
COFF_Flags flags;
|
||||
};
|
||||
|
||||
typedef U32 COFF_SectionAlign;
|
||||
@@ -108,35 +108,36 @@ enum
|
||||
typedef U32 COFF_SectionFlags;
|
||||
enum
|
||||
{
|
||||
COFF_SectionFlag_TYPE_NO_PAD = (1 << 3),
|
||||
COFF_SectionFlag_CNT_CODE = (1 << 5),
|
||||
COFF_SectionFlag_CNT_INITIALIZED_DATA = (1 << 6),
|
||||
COFF_SectionFlag_CNT_UNINITIALIZED_DATA = (1 << 7),
|
||||
COFF_SectionFlag_LNK_OTHER = (1 << 8),
|
||||
COFF_SectionFlag_LNK_INFO = (1 << 9),
|
||||
COFF_SectionFlag_LNK_REMOVE = (1 << 11),
|
||||
COFF_SectionFlag_LNK_COMDAT = (1 << 12),
|
||||
COFF_SectionFlag_GPREL = (1 << 15),
|
||||
COFF_SectionFlag_MEM_16BIT = (1 << 17),
|
||||
COFF_SectionFlag_MEM_LOCKED = (1 << 18),
|
||||
COFF_SectionFlag_MEM_PRELOAD = (1 << 19),
|
||||
COFF_SectionFlag_ALIGN_SHIFT = 20, COFF_SectionFlag_ALIGN_MASK = 0xf,
|
||||
COFF_SectionFlag_LNK_NRELOC_OVFL = (1 << 24),
|
||||
COFF_SectionFlag_MEM_DISCARDABLE = (1 << 25),
|
||||
COFF_SectionFlag_MEM_NOT_CACHED = (1 << 26),
|
||||
COFF_SectionFlag_MEM_NOT_PAGED = (1 << 27),
|
||||
COFF_SectionFlag_MEM_SHARED = (1 << 28),
|
||||
COFF_SectionFlag_MEM_EXECUTE = (1 << 29),
|
||||
COFF_SectionFlag_MEM_READ = (1 << 30),
|
||||
COFF_SectionFlag_MEM_WRITE = (1 << 31),
|
||||
COFF_SectionFlag_TYPE_NO_PAD = (1 << 3),
|
||||
COFF_SectionFlag_CNT_CODE = (1 << 5),
|
||||
COFF_SectionFlag_CNT_INITIALIZED_DATA = (1 << 6),
|
||||
COFF_SectionFlag_CNT_UNINITIALIZED_DATA = (1 << 7),
|
||||
COFF_SectionFlag_LNK_OTHER = (1 << 8),
|
||||
COFF_SectionFlag_LNK_INFO = (1 << 9),
|
||||
COFF_SectionFlag_LNK_REMOVE = (1 << 11),
|
||||
COFF_SectionFlag_LNK_COMDAT = (1 << 12),
|
||||
COFF_SectionFlag_GPREL = (1 << 15),
|
||||
COFF_SectionFlag_MEM_16BIT = (1 << 17),
|
||||
COFF_SectionFlag_MEM_LOCKED = (1 << 18),
|
||||
COFF_SectionFlag_MEM_PRELOAD = (1 << 19),
|
||||
COFF_SectionFlag_ALIGN_SHIFT = 20,
|
||||
COFF_SectionFlag_ALIGN_MASK = 0xf,
|
||||
COFF_SectionFlag_LNK_NRELOC_OVFL = (1 << 24),
|
||||
COFF_SectionFlag_MEM_DISCARDABLE = (1 << 25),
|
||||
COFF_SectionFlag_MEM_NOT_CACHED = (1 << 26),
|
||||
COFF_SectionFlag_MEM_NOT_PAGED = (1 << 27),
|
||||
COFF_SectionFlag_MEM_SHARED = (1 << 28),
|
||||
COFF_SectionFlag_MEM_EXECUTE = (1 << 29),
|
||||
COFF_SectionFlag_MEM_READ = (1 << 30),
|
||||
COFF_SectionFlag_MEM_WRITE = (1 << 31),
|
||||
};
|
||||
#define COFF_SectionFlags_Extract_ALIGN(f) (COFF_SectionAlign)(((f) >> COFF_SectionFlag_ALIGN_SHIFT) & COFF_SectionFlag_ALIGN_MASK)
|
||||
#define COFF_SectionFlags_LNK_FLAGS ((COFF_SectionFlag_ALIGN_MASK << COFF_SectionFlag_ALIGN_SHIFT) | COFF_SectionFlag_LNK_COMDAT | COFF_SectionFlag_LNK_INFO | COFF_SectionFlag_LNK_OTHER | COFF_SectionFlag_LNK_REMOVE | COFF_SectionFlag_LNK_NRELOC_OVFL)
|
||||
#define COFF_SectionFlags_LNK_FLAGS ((COFF_SectionFlag_ALIGN_MASK << COFF_SectionFlag_ALIGN_SHIFT) | COFF_SectionFlag_LNK_COMDAT | COFF_SectionFlag_LNK_INFO | COFF_SectionFlag_LNK_OTHER | COFF_SectionFlag_LNK_REMOVE | COFF_SectionFlag_LNK_NRELOC_OVFL)
|
||||
|
||||
typedef struct COFF_SectionHeader COFF_SectionHeader;
|
||||
struct COFF_SectionHeader
|
||||
{
|
||||
U8 name[8];
|
||||
U8 name[8];
|
||||
U32 vsize;
|
||||
U32 voff;
|
||||
U32 fsize;
|
||||
@@ -151,112 +152,99 @@ struct COFF_SectionHeader
|
||||
typedef U16 COFF_RelocTypeX64;
|
||||
enum
|
||||
{
|
||||
COFF_RelocTypeX64_ABS = 0x0,
|
||||
COFF_RelocTypeX64_ADDR64 = 0x1,
|
||||
COFF_RelocTypeX64_ADDR32 = 0x2,
|
||||
COFF_RelocTypeX64_ADDR32NB = 0x3,
|
||||
// NB => No Base
|
||||
COFF_RelocTypeX64_REL32 = 0x4,
|
||||
COFF_RelocTypeX64_REL32_1 = 0x5,
|
||||
COFF_RelocTypeX64_REL32_2 = 0x6,
|
||||
COFF_RelocTypeX64_REL32_3 = 0x7,
|
||||
COFF_RelocTypeX64_REL32_4 = 0x8,
|
||||
COFF_RelocTypeX64_REL32_5 = 0x9,
|
||||
COFF_RelocTypeX64_SECTION = 0xA,
|
||||
COFF_RelocTypeX64_SECREL = 0xB,
|
||||
COFF_RelocTypeX64_SECREL7 = 0xC,
|
||||
// TODO(nick): MSDN doesn't specify size for CLR token
|
||||
COFF_RelocTypeX64_TOKEN = 0xD,
|
||||
COFF_RelocTypeX64_SREL32 = 0xE,
|
||||
// TODO(nick): MSDN doesn't specify size for PAIR
|
||||
COFF_RelocTypeX64_PAIR = 0xF,
|
||||
COFF_RelocTypeX64_SSPAN32 = 0x10,
|
||||
COFF_RelocTypeX64_COUNT = 17
|
||||
COFF_RelocTypeX64_ABS = 0x0,
|
||||
COFF_RelocTypeX64_ADDR64 = 0x1,
|
||||
COFF_RelocTypeX64_ADDR32 = 0x2,
|
||||
COFF_RelocTypeX64_ADDR32NB = 0x3, // NB => No Base
|
||||
COFF_RelocTypeX64_REL32 = 0x4,
|
||||
COFF_RelocTypeX64_REL32_1 = 0x5,
|
||||
COFF_RelocTypeX64_REL32_2 = 0x6,
|
||||
COFF_RelocTypeX64_REL32_3 = 0x7,
|
||||
COFF_RelocTypeX64_REL32_4 = 0x8,
|
||||
COFF_RelocTypeX64_REL32_5 = 0x9,
|
||||
COFF_RelocTypeX64_SECTION = 0xA,
|
||||
COFF_RelocTypeX64_SECREL = 0xB,
|
||||
COFF_RelocTypeX64_SECREL7 = 0xC, // TODO(nick): MSDN doesn't specify size for CLR token
|
||||
COFF_RelocTypeX64_TOKEN = 0xD,
|
||||
COFF_RelocTypeX64_SREL32 = 0xE, // TODO(nick): MSDN doesn't specify size for PAIR
|
||||
COFF_RelocTypeX64_PAIR = 0xF,
|
||||
COFF_RelocTypeX64_SSPAN32 = 0x10,
|
||||
COFF_RelocTypeX64_COUNT = 17
|
||||
};
|
||||
|
||||
typedef U16 COFF_RelocTypeX86;
|
||||
enum
|
||||
{
|
||||
COFF_RelocTypeX86_ABS = 0x0,
|
||||
// relocation is ignored
|
||||
COFF_RelocTypeX86_DIR16 = 0x1,
|
||||
// no support
|
||||
COFF_RelocTypeX86_REL16 = 0x2,
|
||||
// no support
|
||||
COFF_RelocTypeX86_UNKNOWN0 = 0x3,
|
||||
COFF_RelocTypeX86_UNKNOWN2 = 0x4,
|
||||
COFF_RelocTypeX86_UNKNOWN3 = 0x5,
|
||||
COFF_RelocTypeX86_DIR32 = 0x6,
|
||||
// 32-bit virtual address
|
||||
COFF_RelocTypeX86_DIR32NB = 0x7,
|
||||
// 32-bit virtual offset
|
||||
COFF_RelocTypeX86_SEG12 = 0x9,
|
||||
// no support
|
||||
COFF_RelocTypeX86_SECTION = 0xA,
|
||||
// 16-bit section index, used for debug info purposes
|
||||
COFF_RelocTypeX86_SECREL = 0xB,
|
||||
// 32-bit offset from start of a section
|
||||
COFF_RelocTypeX86_TOKEN = 0xC,
|
||||
// CLR token? (for managed languages)
|
||||
COFF_RelocTypeX86_SECREL7 = 0xD,
|
||||
// 7-bit offset from the base of the section that contains the target.
|
||||
COFF_RelocTypeX86_UNKNOWN4 = 0xE,
|
||||
COFF_RelocTypeX86_UNKNOWN5 = 0xF,
|
||||
COFF_RelocTypeX86_UNKNOWN6 = 0x10,
|
||||
COFF_RelocTypeX86_UNKNOWN7 = 0x11,
|
||||
COFF_RelocTypeX86_UNKNOWN8 = 0x12,
|
||||
COFF_RelocTypeX86_UNKNOWN9 = 0x13,
|
||||
COFF_RelocTypeX86_REL32 = 0x14,
|
||||
COFF_RelocTypeX86_COUNT = 20
|
||||
COFF_RelocTypeX86_ABS = 0x0, // relocation is ignored
|
||||
COFF_RelocTypeX86_DIR16 = 0x1, // no support
|
||||
COFF_RelocTypeX86_REL16 = 0x2, // no support
|
||||
COFF_RelocTypeX86_UNKNOWN0 = 0x3,
|
||||
COFF_RelocTypeX86_UNKNOWN2 = 0x4,
|
||||
COFF_RelocTypeX86_UNKNOWN3 = 0x5,
|
||||
COFF_RelocTypeX86_DIR32 = 0x6, // 32-bit virtual address
|
||||
COFF_RelocTypeX86_DIR32NB = 0x7, // 32-bit virtual offset
|
||||
COFF_RelocTypeX86_SEG12 = 0x9, // no support
|
||||
COFF_RelocTypeX86_SECTION = 0xA, // 16-bit section index, used for debug info purposes
|
||||
COFF_RelocTypeX86_SECREL = 0xB, // 32-bit offset from start of a section
|
||||
COFF_RelocTypeX86_TOKEN = 0xC, // CLR token? (for managed languages)
|
||||
COFF_RelocTypeX86_SECREL7 = 0xD, // 7-bit offset from the base of the section that contains the target.
|
||||
COFF_RelocTypeX86_UNKNOWN4 = 0xE,
|
||||
COFF_RelocTypeX86_UNKNOWN5 = 0xF,
|
||||
COFF_RelocTypeX86_UNKNOWN6 = 0x10,
|
||||
COFF_RelocTypeX86_UNKNOWN7 = 0x11,
|
||||
COFF_RelocTypeX86_UNKNOWN8 = 0x12,
|
||||
COFF_RelocTypeX86_UNKNOWN9 = 0x13,
|
||||
COFF_RelocTypeX86_REL32 = 0x14,
|
||||
COFF_RelocTypeX86_COUNT = 20
|
||||
};
|
||||
|
||||
typedef U16 COFF_RelocTypeARM;
|
||||
enum
|
||||
{
|
||||
COFF_RelocTypeARM_ABS = 0x0,
|
||||
COFF_RelocTypeARM_ADDR32 = 0x1,
|
||||
COFF_RelocTypeARM_ADDR32NB = 0x2,
|
||||
COFF_RelocTypeARM_BRANCH24 = 0x3,
|
||||
COFF_RelocTypeARM_BRANCH11 = 0x4,
|
||||
COFF_RelocTypeARM_UNKNOWN1 = 0x5,
|
||||
COFF_RelocTypeARM_UNKNOWN2 = 0x6,
|
||||
COFF_RelocTypeARM_UNKNOWN3 = 0x7,
|
||||
COFF_RelocTypeARM_UNKNOWN4 = 0x8,
|
||||
COFF_RelocTypeARM_UNKNOWN5 = 0x9,
|
||||
COFF_RelocTypeARM_REL32 = 0xA,
|
||||
COFF_RelocTypeARM_SECTION = 0xE,
|
||||
COFF_RelocTypeARM_SECREL = 0xF,
|
||||
COFF_RelocTypeARM_MOV32 = 0x10,
|
||||
COFF_RelocTypeARM_THUMB_MOV32 = 0x11,
|
||||
COFF_RelocTypeARM_THUMB_BRANCH20 = 0x12,
|
||||
COFF_RelocTypeARM_UNUSED = 0x13,
|
||||
COFF_RelocTypeARM_THUMB_BRANCH24 = 0x14,
|
||||
COFF_RelocTypeARM_THUMB_BLX23 = 0x15,
|
||||
COFF_RelocTypeARM_PAIR = 0x16,
|
||||
COFF_RelocTypeARM_COUNT = 20
|
||||
COFF_RelocTypeARM_ABS = 0x0,
|
||||
COFF_RelocTypeARM_ADDR32 = 0x1,
|
||||
COFF_RelocTypeARM_ADDR32NB = 0x2,
|
||||
COFF_RelocTypeARM_BRANCH24 = 0x3,
|
||||
COFF_RelocTypeARM_BRANCH11 = 0x4,
|
||||
COFF_RelocTypeARM_UNKNOWN1 = 0x5,
|
||||
COFF_RelocTypeARM_UNKNOWN2 = 0x6,
|
||||
COFF_RelocTypeARM_UNKNOWN3 = 0x7,
|
||||
COFF_RelocTypeARM_UNKNOWN4 = 0x8,
|
||||
COFF_RelocTypeARM_UNKNOWN5 = 0x9,
|
||||
COFF_RelocTypeARM_REL32 = 0xA,
|
||||
COFF_RelocTypeARM_SECTION = 0xE,
|
||||
COFF_RelocTypeARM_SECREL = 0xF,
|
||||
COFF_RelocTypeARM_MOV32 = 0x10,
|
||||
COFF_RelocTypeARM_THUMB_MOV32 = 0x11,
|
||||
COFF_RelocTypeARM_THUMB_BRANCH20 = 0x12,
|
||||
COFF_RelocTypeARM_UNUSED = 0x13,
|
||||
COFF_RelocTypeARM_THUMB_BRANCH24 = 0x14,
|
||||
COFF_RelocTypeARM_THUMB_BLX23 = 0x15,
|
||||
COFF_RelocTypeARM_PAIR = 0x16,
|
||||
COFF_RelocTypeARM_COUNT = 20
|
||||
};
|
||||
|
||||
typedef U16 COFF_RelocTypeARM64;
|
||||
enum
|
||||
{
|
||||
COFF_RelocTypeARM64_ABS = 0x0,
|
||||
COFF_RelocTypeARM64_ADDR32 = 0x1,
|
||||
COFF_RelocTypeARM64_ADDR32NB = 0x2,
|
||||
COFF_RelocTypeARM64_BRANCH26 = 0x3,
|
||||
COFF_RelocTypeARM64_PAGEBASE_REL21 = 0x4,
|
||||
COFF_RelocTypeARM64_REL21 = 0x5,
|
||||
COFF_RelocTypeARM64_PAGEOFFSET_12A = 0x6,
|
||||
COFF_RelocTypeARM64_SECREL = 0x8,
|
||||
COFF_RelocTypeARM64_SECREL_LOW12A = 0x9,
|
||||
COFF_RelocTypeARM64_SECREL_HIGH12A = 0xA,
|
||||
COFF_RelocTypeARM64_SECREL_LOW12L = 0xB,
|
||||
COFF_RelocTypeARM64_TOKEN = 0xC,
|
||||
COFF_RelocTypeARM64_SECTION = 0xD,
|
||||
COFF_RelocTypeARM64_ADDR64 = 0xE,
|
||||
COFF_RelocTypeARM64_BRANCH19 = 0xF,
|
||||
COFF_RelocTypeARM64_BRANCH14 = 0x10,
|
||||
COFF_RelocTypeARM64_REL32 = 0x11,
|
||||
COFF_RelocTypeARM64_COUNT = 17
|
||||
COFF_RelocTypeARM64_ABS = 0x0,
|
||||
COFF_RelocTypeARM64_ADDR32 = 0x1,
|
||||
COFF_RelocTypeARM64_ADDR32NB = 0x2,
|
||||
COFF_RelocTypeARM64_BRANCH26 = 0x3,
|
||||
COFF_RelocTypeARM64_PAGEBASE_REL21 = 0x4,
|
||||
COFF_RelocTypeARM64_REL21 = 0x5,
|
||||
COFF_RelocTypeARM64_PAGEOFFSET_12A = 0x6,
|
||||
COFF_RelocTypeARM64_SECREL = 0x8,
|
||||
COFF_RelocTypeARM64_SECREL_LOW12A = 0x9,
|
||||
COFF_RelocTypeARM64_SECREL_HIGH12A = 0xA,
|
||||
COFF_RelocTypeARM64_SECREL_LOW12L = 0xB,
|
||||
COFF_RelocTypeARM64_TOKEN = 0xC,
|
||||
COFF_RelocTypeARM64_SECTION = 0xD,
|
||||
COFF_RelocTypeARM64_ADDR64 = 0xE,
|
||||
COFF_RelocTypeARM64_BRANCH19 = 0xF,
|
||||
COFF_RelocTypeARM64_BRANCH14 = 0x10,
|
||||
COFF_RelocTypeARM64_REL32 = 0x11,
|
||||
COFF_RelocTypeARM64_COUNT = 17
|
||||
};
|
||||
|
||||
typedef U8 COFF_SymType;
|
||||
@@ -273,8 +261,7 @@ enum
|
||||
COFF_SymType_STRUCT,
|
||||
COFF_SymType_UNION,
|
||||
COFF_SymType_ENUM,
|
||||
COFF_SymType_MOE,
|
||||
// member of enumeration
|
||||
COFF_SymType_MOE, // member of enumeration
|
||||
COFF_SymType_BYTE,
|
||||
COFF_SymType_WORD,
|
||||
COFF_SymType_UINT,
|
||||
@@ -285,100 +272,100 @@ enum
|
||||
typedef U8 COFF_SymStorageClass;
|
||||
enum
|
||||
{
|
||||
COFF_SymStorageClass_END_OF_FUNCTION = 0xff,
|
||||
COFF_SymStorageClass_NULL = 0,
|
||||
COFF_SymStorageClass_AUTOMATIC = 1,
|
||||
COFF_SymStorageClass_EXTERNAL = 2,
|
||||
COFF_SymStorageClass_STATIC = 3,
|
||||
COFF_SymStorageClass_REGISTER = 4,
|
||||
COFF_SymStorageClass_EXTERNAL_DEF = 5,
|
||||
COFF_SymStorageClass_LABEL = 6,
|
||||
COFF_SymStorageClass_UNDEFINED_LABEL = 7,
|
||||
COFF_SymStorageClass_MEMBER_OF_STRUCT = 8,
|
||||
COFF_SymStorageClass_ARGUMENT = 9,
|
||||
COFF_SymStorageClass_STRUCT_TAG = 10,
|
||||
COFF_SymStorageClass_MEMBER_OF_UNION = 11,
|
||||
COFF_SymStorageClass_UNION_TAG = 12,
|
||||
COFF_SymStorageClass_TYPE_DEFINITION = 13,
|
||||
COFF_SymStorageClass_UNDEFINED_STATIC = 14,
|
||||
COFF_SymStorageClass_ENUM_TAG = 15,
|
||||
COFF_SymStorageClass_MEMBER_OF_ENUM = 16,
|
||||
COFF_SymStorageClass_REGISTER_PARAM = 17,
|
||||
COFF_SymStorageClass_BIT_FIELD = 18,
|
||||
COFF_SymStorageClass_BLOCK = 100,
|
||||
COFF_SymStorageClass_FUNCTION = 101,
|
||||
COFF_SymStorageClass_END_OF_STRUCT = 102,
|
||||
COFF_SymStorageClass_FILE = 103,
|
||||
COFF_SymStorageClass_SECTION = 104,
|
||||
COFF_SymStorageClass_WEAK_EXTERNAL = 105,
|
||||
COFF_SymStorageClass_CLR_TOKEN = 107,
|
||||
COFF_SymStorageClass_COUNT = 27
|
||||
COFF_SymStorageClass_END_OF_FUNCTION = 0xff,
|
||||
COFF_SymStorageClass_NULL = 0,
|
||||
COFF_SymStorageClass_AUTOMATIC = 1,
|
||||
COFF_SymStorageClass_EXTERNAL = 2,
|
||||
COFF_SymStorageClass_STATIC = 3,
|
||||
COFF_SymStorageClass_REGISTER = 4,
|
||||
COFF_SymStorageClass_EXTERNAL_DEF = 5,
|
||||
COFF_SymStorageClass_LABEL = 6,
|
||||
COFF_SymStorageClass_UNDEFINED_LABEL = 7,
|
||||
COFF_SymStorageClass_MEMBER_OF_STRUCT = 8,
|
||||
COFF_SymStorageClass_ARGUMENT = 9,
|
||||
COFF_SymStorageClass_STRUCT_TAG = 10,
|
||||
COFF_SymStorageClass_MEMBER_OF_UNION = 11,
|
||||
COFF_SymStorageClass_UNION_TAG = 12,
|
||||
COFF_SymStorageClass_TYPE_DEFINITION = 13,
|
||||
COFF_SymStorageClass_UNDEFINED_STATIC = 14,
|
||||
COFF_SymStorageClass_ENUM_TAG = 15,
|
||||
COFF_SymStorageClass_MEMBER_OF_ENUM = 16,
|
||||
COFF_SymStorageClass_REGISTER_PARAM = 17,
|
||||
COFF_SymStorageClass_BIT_FIELD = 18,
|
||||
COFF_SymStorageClass_BLOCK = 100,
|
||||
COFF_SymStorageClass_FUNCTION = 101,
|
||||
COFF_SymStorageClass_END_OF_STRUCT = 102,
|
||||
COFF_SymStorageClass_FILE = 103,
|
||||
COFF_SymStorageClass_SECTION = 104,
|
||||
COFF_SymStorageClass_WEAK_EXTERNAL = 105,
|
||||
COFF_SymStorageClass_CLR_TOKEN = 107,
|
||||
COFF_SymStorageClass_COUNT = 27
|
||||
};
|
||||
|
||||
typedef U16 COFF_SymSecNumber;
|
||||
enum
|
||||
{
|
||||
COFF_SymSecNumber_NUMBER_UNDEFINED = 0,
|
||||
COFF_SymSecNumber_ABSOLUTE = 0xffff,
|
||||
COFF_SymSecNumber_DEBUG = 0xfffe,
|
||||
COFF_SymSecNumber_COUNT = 3
|
||||
COFF_SymSecNumber_NUMBER_UNDEFINED = 0,
|
||||
COFF_SymSecNumber_ABSOLUTE = 0xffff,
|
||||
COFF_SymSecNumber_DEBUG = 0xfffe,
|
||||
COFF_SymSecNumber_COUNT = 3
|
||||
};
|
||||
|
||||
typedef U8 COFF_SymDType;
|
||||
enum
|
||||
{
|
||||
COFF_SymDType_NULL = 0,
|
||||
COFF_SymDType_PTR = 16,
|
||||
COFF_SymDType_FUNC = 32,
|
||||
COFF_SymDType_ARRAY = 48,
|
||||
COFF_SymDType_COUNT = 4
|
||||
COFF_SymDType_NULL = 0,
|
||||
COFF_SymDType_PTR = 16,
|
||||
COFF_SymDType_FUNC = 32,
|
||||
COFF_SymDType_ARRAY = 48,
|
||||
COFF_SymDType_COUNT = 4
|
||||
};
|
||||
|
||||
typedef U32 COFF_WeakExtType;
|
||||
enum
|
||||
{
|
||||
COFF_WeakExtType_NOLIBRARY = 1,
|
||||
COFF_WeakExtType_SEARCH_LIBRARY = 2,
|
||||
COFF_WeakExtType_SEARCH_ALIAS = 3,
|
||||
COFF_WeakExtType_COUNT = 3
|
||||
COFF_WeakExtType_NOLIBRARY = 1,
|
||||
COFF_WeakExtType_SEARCH_LIBRARY = 2,
|
||||
COFF_WeakExtType_SEARCH_ALIAS = 3,
|
||||
COFF_WeakExtType_COUNT = 3
|
||||
};
|
||||
|
||||
typedef U32 COFF_ImportHeaderType;
|
||||
enum
|
||||
{
|
||||
COFF_ImportHeaderType_CODE = 0,
|
||||
COFF_ImportHeaderType_DATA = 1,
|
||||
COFF_ImportHeaderType_CONST = 2,
|
||||
COFF_ImportHeaderType_COUNT = 3
|
||||
COFF_ImportHeaderType_CODE = 0,
|
||||
COFF_ImportHeaderType_DATA = 1,
|
||||
COFF_ImportHeaderType_CONST = 2,
|
||||
COFF_ImportHeaderType_COUNT = 3
|
||||
};
|
||||
|
||||
typedef U32 COFF_ImportHeaderNameType;
|
||||
enum
|
||||
{
|
||||
COFF_ImportHeaderNameType_ORDINAL = 0,
|
||||
COFF_ImportHeaderNameType_NAME = 1,
|
||||
COFF_ImportHeaderNameType_NAME_NOPREFIX = 2,
|
||||
COFF_ImportHeaderNameType_UNDECORATE = 3,
|
||||
COFF_ImportHeaderNameType_COUNT = 4
|
||||
COFF_ImportHeaderNameType_ORDINAL = 0,
|
||||
COFF_ImportHeaderNameType_NAME = 1,
|
||||
COFF_ImportHeaderNameType_NAME_NOPREFIX = 2,
|
||||
COFF_ImportHeaderNameType_UNDECORATE = 3,
|
||||
COFF_ImportHeaderNameType_COUNT = 4
|
||||
};
|
||||
|
||||
#define COFF_IMPORT_HEADER_TYPE_MASK 0x03
|
||||
#define COFF_IMPORT_HEADER_TYPE_SHIFT 0
|
||||
#define COFF_IMPORT_HEADER_TYPE_MASK 0x03
|
||||
#define COFF_IMPORT_HEADER_TYPE_SHIFT 0
|
||||
#define COFF_IMPORT_HEADER_NAME_TYPE_MASK 0x1c
|
||||
#define COFF_IMPORT_HEADER_NAME_TYPE_SHIFT 2
|
||||
#define COFF_IMPORT_HEADER_GET_TYPE(x) (((x) & COFF_IMPORT_HEADER_TYPE_MASK) >> COFF_IMPORT_HEADER_TYPE_SHIFT)
|
||||
#define COFF_IMPORT_HEADER_GET_NAME_TYPE(x) (((x) & COFF_IMPORT_HEADER_NAME_TYPE_MASK) >> COFF_IMPORT_HEADER_NAME_TYPE_SHIFT)
|
||||
typedef struct COFF_ImportHeader
|
||||
{
|
||||
U16 sig1;
|
||||
U16 sig2;
|
||||
U16 version;
|
||||
U16 machine;
|
||||
U16 sig1;
|
||||
U16 sig2;
|
||||
U16 version;
|
||||
U16 machine;
|
||||
COFF_TimeStamp time_stamp;
|
||||
U32 data_size;
|
||||
U16 hint;
|
||||
U16 type;
|
||||
U16 name_type;
|
||||
U32 data_size;
|
||||
U16 hint;
|
||||
U16 type;
|
||||
U16 name_type;
|
||||
// type : 2
|
||||
// name type : 3
|
||||
// reserved : 11
|
||||
@@ -390,30 +377,18 @@ typedef struct COFF_ImportHeader
|
||||
typedef U8 COFF_ComdatSelectType;
|
||||
enum
|
||||
{
|
||||
COFF_ComdatSelectType_NULL = 0,
|
||||
// Only one symbol is allowed to be in global symbol table, otherwise multiply defintion error is thrown.
|
||||
COFF_ComdatSelectType_NODUPLICATES = 1,
|
||||
// Select any symbol, even if there are multiple definitions. (we default to first declaration)
|
||||
COFF_ComdatSelectType_ANY = 2,
|
||||
// Sections that symbols reference must match in size, otherwise multiply definition error is thrown.
|
||||
COFF_ComdatSelectType_SAME_SIZE = 3,
|
||||
// Sections that symbols reference must have identical checksums, otherwise multiply defintion error is thrown.
|
||||
COFF_ComdatSelectType_EXACT_MATCH = 4,
|
||||
// Symbols with associative type form a chain of sections are related to each other. (next link is indicated in COFF_SecDef in 'number')
|
||||
COFF_ComdatSelectType_ASSOCIATIVE = 5,
|
||||
// Linker selects section with largest size.
|
||||
COFF_ComdatSelectType_LARGEST = 6,
|
||||
COFF_ComdatSelectType_COUNT = 7
|
||||
COFF_ComdatSelectType_NULL = 0, // Only one symbol is allowed to be in global symbol table, otherwise multiply defintion error is thrown.
|
||||
COFF_ComdatSelectType_NODUPLICATES = 1, // Select any symbol, even if there are multiple definitions. (we default to first declaration)
|
||||
COFF_ComdatSelectType_ANY = 2, // Sections that symbols reference must match in size, otherwise multiply definition error is thrown.
|
||||
COFF_ComdatSelectType_SAME_SIZE = 3, // Sections that symbols reference must have identical checksums, otherwise multiply defintion error is thrown.
|
||||
COFF_ComdatSelectType_EXACT_MATCH = 4, // Symbols with associative type form a chain of sections are related to each other. (next link is indicated in COFF_SecDef in 'number')
|
||||
COFF_ComdatSelectType_ASSOCIATIVE = 5, // Linker selects section with largest size.
|
||||
COFF_ComdatSelectType_LARGEST = 6,
|
||||
COFF_ComdatSelectType_COUNT = 7
|
||||
};
|
||||
|
||||
#define COFF_MIN_BIG_OBJ_VERSION 2
|
||||
|
||||
global U8 coff_big_obj_magic[] =
|
||||
{
|
||||
0xC7,0xA1,0xBA,0xD1,0xEE,0xBA,0xA9,0x4B,
|
||||
0xAF,0x20,0xFA,0xF6,0x6A,0xA4,0xDC,0xB8,
|
||||
};
|
||||
|
||||
typedef struct COFF_HeaderBigObj COFF_HeaderBigObj;
|
||||
struct COFF_HeaderBigObj
|
||||
{
|
||||
@@ -422,7 +397,7 @@ struct COFF_HeaderBigObj
|
||||
U16 version;
|
||||
U16 machine;
|
||||
U32 time_stamp;
|
||||
U8 magic[16];
|
||||
U8 magic[16];
|
||||
U32 unused[4];
|
||||
U32 section_count;
|
||||
U32 pointer_to_symbol_table;
|
||||
@@ -454,8 +429,8 @@ typedef struct COFF_Symbol16 COFF_Symbol16;
|
||||
struct COFF_Symbol16
|
||||
{
|
||||
COFF_SymbolName name;
|
||||
U32 value;
|
||||
U16 section_number;
|
||||
U32 value;
|
||||
U16 section_number;
|
||||
union
|
||||
{
|
||||
struct
|
||||
@@ -473,8 +448,8 @@ typedef struct COFF_Symbol32 COFF_Symbol32;
|
||||
struct COFF_Symbol32
|
||||
{
|
||||
COFF_SymbolName name;
|
||||
U32 value;
|
||||
U32 section_number;
|
||||
U32 value;
|
||||
U32 section_number;
|
||||
union
|
||||
{
|
||||
struct
|
||||
@@ -494,11 +469,11 @@ struct COFF_Symbol32
|
||||
// storage class: FUNCTION
|
||||
typedef struct COFF_SymbolFunc
|
||||
{
|
||||
U8 unused[4];
|
||||
U8 unused[4];
|
||||
U16 ln;
|
||||
U8 unused2[2];
|
||||
U8 unused2[2];
|
||||
U32 ptr_to_next_func;
|
||||
U8 unused3[2];
|
||||
U8 unused3[2];
|
||||
} COFF_SymbolFunc;
|
||||
|
||||
// storage class: WEAK_EXTERNAL
|
||||
@@ -506,7 +481,7 @@ typedef struct COFF_SymbolWeakExt
|
||||
{
|
||||
U32 tag_index;
|
||||
U32 characteristics;
|
||||
U8 unused[10];
|
||||
U8 unused[10];
|
||||
} COFF_SymbolWeakExt;
|
||||
|
||||
typedef struct COFF_SymbolFile
|
||||
@@ -522,9 +497,10 @@ typedef struct COFF_SymbolSecDef
|
||||
U16 number_of_relocations;
|
||||
U16 number_of_ln;
|
||||
U32 check_sum;
|
||||
U16 number; // one-based section index
|
||||
U8 selection;
|
||||
U8 unused[3];
|
||||
U16 number_lo; // one-based section index
|
||||
U8 selection;
|
||||
U8 unused;
|
||||
U16 number_hi;
|
||||
} COFF_SymbolSecDef;
|
||||
|
||||
// specifies how section data should be modified when placed in the image file.
|
||||
@@ -556,11 +532,6 @@ typedef U32 COFF_FeatFlags;
|
||||
|
||||
#define COFF_RES_ALIGN 4u
|
||||
|
||||
read_only U8 g_coff_res_magic[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
typedef struct COFF_ResourceHeaderPrefix
|
||||
{
|
||||
U32 data_size;
|
||||
@@ -589,7 +560,7 @@ typedef struct COFF_ResourceID_16
|
||||
COFF_ResourceIDType type;
|
||||
union
|
||||
{
|
||||
U16 number;
|
||||
U16 number;
|
||||
String16 string;
|
||||
} u;
|
||||
} COFF_ResourceID_16;
|
||||
@@ -599,20 +570,21 @@ typedef struct COFF_ResourceID
|
||||
COFF_ResourceIDType type;
|
||||
union
|
||||
{
|
||||
U16 number;
|
||||
U16 number;
|
||||
String8 string;
|
||||
} u;
|
||||
} COFF_ResourceID;
|
||||
|
||||
typedef struct COFF_Resource
|
||||
{
|
||||
COFF_ResourceID type;
|
||||
COFF_ResourceID name;
|
||||
U16 language_id;
|
||||
U32 data_version;
|
||||
U32 version;
|
||||
COFF_ResourceID type;
|
||||
COFF_ResourceID name;
|
||||
U32 data_version;
|
||||
COFF_ResourceMemoryFlags memory_flags;
|
||||
String8 data;
|
||||
U16 language_id;
|
||||
U32 version;
|
||||
U32 characteristics;
|
||||
String8 data;
|
||||
} COFF_Resource;
|
||||
|
||||
typedef struct COFF_ResourceDataEntry
|
||||
@@ -625,12 +597,12 @@ typedef struct COFF_ResourceDataEntry
|
||||
|
||||
typedef struct COFF_ResourceDirTable
|
||||
{
|
||||
U32 characteristics;
|
||||
U32 characteristics;
|
||||
COFF_TimeStamp time_stamp;
|
||||
U16 major_version;
|
||||
U16 minor_version;
|
||||
U16 name_entry_count;
|
||||
U16 id_entry_count;
|
||||
U16 major_version;
|
||||
U16 minor_version;
|
||||
U16 name_entry_count;
|
||||
U16 id_entry_count;
|
||||
} COFF_ResourceDirTable;
|
||||
|
||||
#define COFF_RESOURCE_SUB_DIR_FLAG (1u << 31u)
|
||||
@@ -648,22 +620,19 @@ typedef struct COFF_ResourceDirEntry
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
read_only global U8 g_coff_archive_sig[8] = "!<arch>\n";
|
||||
read_only global U8 g_coff_thin_archive_sig[8] = "!<thin>\n";
|
||||
|
||||
#define COFF_ARCHIVE_ALIGN 2
|
||||
#define COFF_ARCHIVE_MAX_SHORT_NAME_SIZE 15
|
||||
#define COFF_ARCHIVE_MEMBER_HEADER_SIZE 60
|
||||
|
||||
typedef struct COFF_ArchiveMemberHeader
|
||||
{
|
||||
String8 name; // padded to 16 bytes with spaces
|
||||
U32 date; // unix time
|
||||
U32 user_id; // unix artifact that does not have meaning on windows
|
||||
U32 group_id; // unix artifact that does not have meaning on windows
|
||||
String8 mode; // octal representation the members file mode
|
||||
U32 size; // size of the member data, not including header
|
||||
B32 is_end_correct; // set to true if found correct signature after header
|
||||
String8 name; // padded to 16 bytes with spaces
|
||||
U32 date; // unix time
|
||||
U32 user_id; // unix artifact that does not have meaning on windows
|
||||
U32 group_id; // unix artifact that does not have meaning on windows
|
||||
String8 mode; // octal representation the members file mode
|
||||
U32 size; // size of the member data, not including header
|
||||
B32 is_end_correct; // set to true if found correct signature after header
|
||||
} COFF_ArchiveMemberHeader;
|
||||
|
||||
////////////////////////////////
|
||||
@@ -681,71 +650,61 @@ typedef U32 COFF_DataType;
|
||||
typedef struct COFF_HeaderInfo
|
||||
{
|
||||
COFF_MachineType machine;
|
||||
U64 section_array_off;
|
||||
U64 section_count_no_null;
|
||||
U64 string_table_off;
|
||||
U64 symbol_size;
|
||||
U64 symbol_off;
|
||||
U64 symbol_count;
|
||||
COFF_DataType type;
|
||||
U64 section_array_off;
|
||||
U64 section_count_no_null;
|
||||
U64 string_table_off;
|
||||
U64 symbol_size;
|
||||
U64 symbol_off;
|
||||
U64 symbol_count;
|
||||
} COFF_HeaderInfo;
|
||||
|
||||
enum
|
||||
{
|
||||
// symbol has section and offset.
|
||||
COFF_SymbolValueInterp_REGULAR,
|
||||
|
||||
// symbol is overridable
|
||||
COFF_SymbolValueInterp_WEAK,
|
||||
|
||||
// symbol doesn't have a reference section.
|
||||
COFF_SymbolValueInterp_UNDEFINED,
|
||||
|
||||
// symbol has no section but still has size.
|
||||
COFF_SymbolValueInterp_COMMON,
|
||||
|
||||
// symbol has an absolute (non-relocatable) value and is not an address.
|
||||
COFF_SymbolValueInterp_ABS,
|
||||
|
||||
// symbol is used to provide general type of debugging information.
|
||||
COFF_SymbolValueInterp_DEBUG
|
||||
COFF_SymbolValueInterp_REGULAR, // symbol has section and offset.
|
||||
COFF_SymbolValueInterp_WEAK, // symbol is overridable
|
||||
COFF_SymbolValueInterp_UNDEFINED, // symbol doesn't have a reference section.
|
||||
COFF_SymbolValueInterp_COMMON, // symbol has no section but still has size.
|
||||
COFF_SymbolValueInterp_ABS, // symbol has an absolute (non-relocatable) value and is not an address.
|
||||
COFF_SymbolValueInterp_DEBUG // symbol is used to provide general type of debugging information.
|
||||
};
|
||||
typedef U32 COFF_SymbolValueInterpType;
|
||||
|
||||
typedef struct COFF_Symbol16Node
|
||||
{
|
||||
struct COFF_Symbol16Node *next;
|
||||
COFF_Symbol16 data;
|
||||
COFF_Symbol16 data;
|
||||
} COFF_Symbol16Node;
|
||||
|
||||
typedef struct COFF_Symbol16List
|
||||
{
|
||||
U64 count;
|
||||
U64 count;
|
||||
COFF_Symbol16Node *first;
|
||||
COFF_Symbol16Node *last;
|
||||
} COFF_Symbol16List;
|
||||
|
||||
typedef struct COFF_Symbol32Array
|
||||
{
|
||||
U64 count;
|
||||
U64 count;
|
||||
COFF_Symbol32 *v;
|
||||
} COFF_Symbol32Array;
|
||||
|
||||
typedef struct COFF_RelocNode
|
||||
{
|
||||
struct COFF_RelocNode *next;
|
||||
COFF_Reloc data;
|
||||
COFF_Reloc data;
|
||||
} COFF_RelocNode;
|
||||
|
||||
typedef struct COFF_RelocList
|
||||
{
|
||||
U64 count;
|
||||
U64 count;
|
||||
COFF_RelocNode *first;
|
||||
COFF_RelocNode *last;
|
||||
} COFF_RelocList;
|
||||
|
||||
typedef struct COFF_RelocArray
|
||||
{
|
||||
U64 count;
|
||||
U64 count;
|
||||
COFF_Reloc *v;
|
||||
} COFF_RelocArray;
|
||||
|
||||
@@ -758,12 +717,12 @@ typedef struct COFF_RelocInfo
|
||||
typedef struct COFF_ResourceNode
|
||||
{
|
||||
struct COFF_ResourceNode *next;
|
||||
COFF_Resource data;
|
||||
COFF_Resource data;
|
||||
} COFF_ResourceNode;
|
||||
|
||||
typedef struct COFF_ResourceList
|
||||
{
|
||||
U64 count;
|
||||
U64 count;
|
||||
COFF_ResourceNode *first;
|
||||
COFF_ResourceNode *last;
|
||||
} COFF_ResourceList;
|
||||
@@ -773,21 +732,21 @@ typedef struct COFF_ResourceList
|
||||
typedef struct COFF_ArchiveMember
|
||||
{
|
||||
COFF_ArchiveMemberHeader header;
|
||||
U64 offset;
|
||||
String8 data;
|
||||
U64 offset;
|
||||
String8 data;
|
||||
} COFF_ArchiveMember;
|
||||
|
||||
typedef struct COFF_ArchiveFirstMember
|
||||
{
|
||||
U32 symbol_count;
|
||||
U32 symbol_count;
|
||||
String8 member_offsets;
|
||||
String8 string_table;
|
||||
} COFF_ArchiveFirstMember;
|
||||
|
||||
typedef struct COFF_ArchiveSecondMember
|
||||
{
|
||||
U32 member_count;
|
||||
U32 symbol_count;
|
||||
U32 member_count;
|
||||
U32 symbol_count;
|
||||
String8 member_offsets;
|
||||
String8 symbol_indices;
|
||||
String8 string_table;
|
||||
@@ -796,12 +755,12 @@ typedef struct COFF_ArchiveSecondMember
|
||||
typedef struct COFF_ArchiveMemberNode
|
||||
{
|
||||
struct COFF_ArchiveMemberNode *next;
|
||||
COFF_ArchiveMember data;
|
||||
COFF_ArchiveMember data;
|
||||
} COFF_ArchiveMemberNode;
|
||||
|
||||
typedef struct COFF_ArchiveMemberList
|
||||
{
|
||||
U64 count;
|
||||
U64 count;
|
||||
COFF_ArchiveMemberNode *first;
|
||||
COFF_ArchiveMemberNode *last;
|
||||
} COFF_ArchiveMemberList;
|
||||
@@ -815,22 +774,37 @@ typedef enum
|
||||
|
||||
typedef struct COFF_ArchiveParse
|
||||
{
|
||||
COFF_ArchiveFirstMember first_member;
|
||||
COFF_ArchiveFirstMember first_member;
|
||||
COFF_ArchiveSecondMember second_member;
|
||||
String8 long_names;
|
||||
String8 long_names;
|
||||
} COFF_ArchiveParse;
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
typedef struct COFF_SectionHeaderArray
|
||||
{
|
||||
U64 count;
|
||||
U64 count;
|
||||
COFF_SectionHeader *v;
|
||||
} COFF_SectionHeaderArray;
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
read_only global U8 coff_big_obj_magic[] =
|
||||
{
|
||||
0xC7,0xA1,0xBA,0xD1,0xEE,0xBA,0xA9,0x4B,
|
||||
0xAF,0x20,0xFA,0xF6,0x6A,0xA4,0xDC,0xB8,
|
||||
};
|
||||
|
||||
read_only global U8 g_coff_archive_sig[8] = "!<arch>\n";
|
||||
read_only global U8 g_coff_thin_archive_sig[8] = "!<thin>\n";
|
||||
|
||||
read_only global U8 g_coff_res_magic[] =
|
||||
{
|
||||
0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
read_only global COFF_SectionHeader coff_section_header_nil = {0};
|
||||
|
||||
////////////////////////////////
|
||||
@@ -840,6 +814,7 @@ internal B32 coff_is_big_obj(String8 data);
|
||||
internal B32 coff_is_obj(String8 data);
|
||||
internal COFF_HeaderInfo coff_header_info_from_data(String8 data);
|
||||
internal U64 coff_align_size_from_section_flags(COFF_SectionFlags flags);
|
||||
internal COFF_SectionFlags coff_section_flag_from_align_size(U64 align);
|
||||
internal COFF_SymbolValueInterpType coff_interp_symbol(COFF_Symbol32 *symbol);
|
||||
|
||||
internal U64 coff_foff_from_voff(COFF_SectionHeader *sections, U64 section_count, U64 voff);
|
||||
@@ -877,25 +852,24 @@ internal String8 coff_make_import_header_by_ordinal(Arena *arena,
|
||||
U16 ordinal,
|
||||
COFF_ImportHeaderType type);
|
||||
|
||||
////////////////////////////////
|
||||
//~ Resources
|
||||
|
||||
internal B32 coff_resource_id_is_equal(COFF_ResourceID a, COFF_ResourceID b);
|
||||
internal COFF_ResourceID coff_resource_id_copy(Arena *arena, COFF_ResourceID id);
|
||||
internal U64 coff_sizeof_resource_id(COFF_ResourceID id);
|
||||
internal COFF_ResourceID coff_convert_resource_id(Arena *arena, COFF_ResourceID_16 *id_16);
|
||||
internal U64 coff_read_resource_id(String8 res, U64 off, COFF_ResourceID_16 *id_out);
|
||||
internal String8 coff_resource_string_from_str16(Arena *arena, String16 string);
|
||||
internal String8 coff_resource_string_from_str8(Arena *arena, String8 string);
|
||||
internal String8 coff_resource_number_from_u16(Arena *arena, U16 number);
|
||||
|
||||
internal B32 coff_resource_id_is_equal(COFF_ResourceID a, COFF_ResourceID b);
|
||||
internal COFF_ResourceID coff_utf8_resource_id_from_utf16(Arena *arena, COFF_ResourceID_16 *id_16);
|
||||
|
||||
internal U64 coff_read_resource_id_utf16(String8 res, U64 off, COFF_ResourceID_16 *id_out);
|
||||
internal U64 coff_read_resource(String8 data, U64 off, Arena *arena, COFF_Resource *res_out);
|
||||
internal COFF_ResourceList coff_resource_list_from_data(Arena *arena, String8 data);
|
||||
|
||||
internal void coff_write_resource_id(Arena *arena, String8List *srl, COFF_ResourceID id);
|
||||
internal String8List coff_write_resource(Arena *arena,
|
||||
COFF_ResourceID type,
|
||||
COFF_ResourceID name,
|
||||
U32 data_version,
|
||||
COFF_ResourceMemoryFlags memory_flags,
|
||||
U16 language_id,
|
||||
U32 version,
|
||||
U32 characteristics,
|
||||
String8 data);
|
||||
internal String8 coff_write_resource_id(Arena *arena, COFF_ResourceID id);
|
||||
internal String8 coff_write_resource(Arena *arena, COFF_ResourceID type, COFF_ResourceID name, U32 data_version, COFF_ResourceMemoryFlags memory_flags, U16 language_id, U32 version, U32 characteristics, String8 data);
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal COFF_DataType coff_data_type_from_data(String8 data);
|
||||
internal B32 coff_is_import(String8 data);
|
||||
|
||||
+494
-246
@@ -81,6 +81,7 @@ ctrl_string_from_msg_kind(CTRL_MsgKind kind)
|
||||
case CTRL_MsgKind_Launch: {result = str8_lit("Launch");}break;
|
||||
case CTRL_MsgKind_Attach: {result = str8_lit("Attach");}break;
|
||||
case CTRL_MsgKind_Kill: {result = str8_lit("Kill");}break;
|
||||
case CTRL_MsgKind_KillAll: {result = str8_lit("KillAll");}break;
|
||||
case CTRL_MsgKind_Detach: {result = str8_lit("Detach");}break;
|
||||
case CTRL_MsgKind_Run: {result = str8_lit("Run");}break;
|
||||
case CTRL_MsgKind_SingleStep: {result = str8_lit("SingleStep");}break;
|
||||
@@ -270,6 +271,7 @@ ctrl_serialized_string_from_msg_list(Arena *arena, CTRL_MsgList *msgs)
|
||||
str8_serial_push_struct(scratch.arena, &msgs_srlzed, &msg->entity_id);
|
||||
str8_serial_push_struct(scratch.arena, &msgs_srlzed, &msg->exit_code);
|
||||
str8_serial_push_struct(scratch.arena, &msgs_srlzed, &msg->env_inherit);
|
||||
str8_serial_push_struct(scratch.arena, &msgs_srlzed, &msg->debug_subprocesses);
|
||||
str8_serial_push_array (scratch.arena, &msgs_srlzed, &msg->exception_code_filters[0], ArrayCount(msg->exception_code_filters));
|
||||
|
||||
// rjf: write path string
|
||||
@@ -370,6 +372,7 @@ ctrl_msg_list_from_serialized_string(Arena *arena, String8 string)
|
||||
read_off += str8_deserial_read_struct(string, read_off, &msg->entity_id);
|
||||
read_off += str8_deserial_read_struct(string, read_off, &msg->exit_code);
|
||||
read_off += str8_deserial_read_struct(string, read_off, &msg->env_inherit);
|
||||
read_off += str8_deserial_read_struct(string, read_off, &msg->debug_subprocesses);
|
||||
read_off += str8_deserial_read_array (string, read_off, &msg->exception_code_filters[0], ArrayCount(msg->exception_code_filters));
|
||||
|
||||
// rjf: read path string
|
||||
@@ -1283,6 +1286,7 @@ ctrl_init(void)
|
||||
ctrl_state->dmn_event_arena = arena_alloc();
|
||||
ctrl_state->user_entry_point_arena = arena_alloc();
|
||||
ctrl_state->user_meta_eval_arena = arena_alloc();
|
||||
ctrl_state->dbg_dir_arena = arena_alloc();
|
||||
for(CTRL_ExceptionCodeKind k = (CTRL_ExceptionCodeKind)0; k < CTRL_ExceptionCodeKind_COUNT; k = (CTRL_ExceptionCodeKind)(k+1))
|
||||
{
|
||||
if(ctrl_exception_code_kind_default_enable_table[k])
|
||||
@@ -1296,12 +1300,6 @@ ctrl_init(void)
|
||||
ctrl_state->u2ms_ring_cv = os_condition_variable_alloc();
|
||||
ctrl_state->ctrl_thread_log = log_alloc();
|
||||
ctrl_state->ctrl_thread = os_thread_launch(ctrl_thread__entry_point, 0, 0);
|
||||
ctrl_state->ms_thread_count = Clamp(1, os_get_system_info()->logical_processor_count-1, 4);
|
||||
ctrl_state->ms_threads = push_array(arena, OS_Handle, ctrl_state->ms_thread_count);
|
||||
for(U64 idx = 0; idx < ctrl_state->ms_thread_count; idx += 1)
|
||||
{
|
||||
ctrl_state->ms_threads[idx] = os_thread_launch(ctrl_mem_stream_thread__entry_point, (void *)idx, 0);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
@@ -1447,24 +1445,28 @@ ctrl_stored_hash_from_process_vaddr_range(CTRL_Handle process, Rng1U64 range, B3
|
||||
//- rjf: not good, or is stale -> submit hash request
|
||||
if((!is_good || is_stale) && os_now_microseconds() >= last_time_requested_us+100000)
|
||||
{
|
||||
if(ctrl_u2ms_enqueue_req(process, range, zero_terminated, endt_us)) OS_MutexScopeW(process_stripe->rw_mutex)
|
||||
if(ctrl_u2ms_enqueue_req(process, range, zero_terminated, endt_us))
|
||||
{
|
||||
for(CTRL_ProcessMemoryCacheNode *n = process_slot->first; n != 0; n = n->next)
|
||||
OS_MutexScopeW(process_stripe->rw_mutex)
|
||||
{
|
||||
if(ctrl_handle_match(n->handle, process))
|
||||
for(CTRL_ProcessMemoryCacheNode *n = process_slot->first; n != 0; n = n->next)
|
||||
{
|
||||
U64 range_slot_idx = range_hash%n->range_hash_slots_count;
|
||||
CTRL_ProcessMemoryRangeHashSlot *range_slot = &n->range_hash_slots[range_slot_idx];
|
||||
for(CTRL_ProcessMemoryRangeHashNode *range_n = range_slot->first; range_n != 0; range_n = range_n->next)
|
||||
if(ctrl_handle_match(n->handle, process))
|
||||
{
|
||||
if(MemoryMatchStruct(&range_n->vaddr_range, &range) && range_n->zero_terminated == zero_terminated)
|
||||
U64 range_slot_idx = range_hash%n->range_hash_slots_count;
|
||||
CTRL_ProcessMemoryRangeHashSlot *range_slot = &n->range_hash_slots[range_slot_idx];
|
||||
for(CTRL_ProcessMemoryRangeHashNode *range_n = range_slot->first; range_n != 0; range_n = range_n->next)
|
||||
{
|
||||
range_n->last_time_requested_us = os_now_microseconds();
|
||||
break;
|
||||
if(MemoryMatchStruct(&range_n->vaddr_range, &range) && range_n->zero_terminated == zero_terminated)
|
||||
{
|
||||
range_n->last_time_requested_us = os_now_microseconds();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
async_push_work(ctrl_mem_stream_work);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1613,12 +1615,12 @@ ctrl_query_cached_data_from_process_vaddr_range(Arena *arena, CTRL_Handle proces
|
||||
}
|
||||
|
||||
// rjf: increment past this chunk
|
||||
write_off += in_range_data.size;
|
||||
if(data.size < page_size)
|
||||
U64 bytes_to_skip = page_size;
|
||||
if(page_idx == 0 && range.min > data_vaddr_range.min)
|
||||
{
|
||||
U64 missed_byte_count = page_size-data.size;
|
||||
write_off += missed_byte_count;
|
||||
bytes_to_skip -= (range.min-data_vaddr_range.min);
|
||||
}
|
||||
write_off += bytes_to_skip;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1781,7 +1783,7 @@ ctrl_query_cached_reg_block_from_thread(Arena *arena, CTRL_EntityStore *store, C
|
||||
CTRL_ThreadRegCacheSlot *slot = &cache->slots[slot_idx];
|
||||
CTRL_ThreadRegCacheStripe *stripe = &cache->stripes[stripe_idx];
|
||||
void *result = push_array(arena, U8, reg_block_size);
|
||||
OS_MutexScopeR(stripe->rw_mutex)
|
||||
OS_MutexScopeW(stripe->rw_mutex)
|
||||
{
|
||||
// rjf: find existing node
|
||||
CTRL_ThreadRegCacheNode *node = 0;
|
||||
@@ -1797,33 +1799,11 @@ ctrl_query_cached_reg_block_from_thread(Arena *arena, CTRL_EntityStore *store, C
|
||||
// rjf: allocate existing node
|
||||
if(!node)
|
||||
{
|
||||
OS_MutexScopeRWPromote(stripe->rw_mutex)
|
||||
{
|
||||
for(CTRL_ThreadRegCacheNode *n = slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(ctrl_handle_match(n->handle, handle))
|
||||
{
|
||||
node = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!node)
|
||||
{
|
||||
node = push_array(stripe->arena, CTRL_ThreadRegCacheNode, 1);
|
||||
DLLPushBack(slot->first, slot->last, node);
|
||||
node->handle = handle;
|
||||
node->block_size = reg_block_size;
|
||||
node->block = push_array(stripe->arena, U8, reg_block_size);
|
||||
}
|
||||
}
|
||||
for(CTRL_ThreadRegCacheNode *n = slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(ctrl_handle_match(n->handle, handle))
|
||||
{
|
||||
node = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
node = push_array(stripe->arena, CTRL_ThreadRegCacheNode, 1);
|
||||
DLLPushBack(slot->first, slot->last, node);
|
||||
node->handle = handle;
|
||||
node->block_size = reg_block_size;
|
||||
node->block = push_array(stripe->arena, U8, reg_block_size);
|
||||
}
|
||||
|
||||
// rjf: copy from node
|
||||
@@ -1833,22 +1813,11 @@ ctrl_query_cached_reg_block_from_thread(Arena *arena, CTRL_EntityStore *store, C
|
||||
B32 need_stale = 1;
|
||||
if(node->reg_gen != current_reg_gen && dmn_thread_read_reg_block(handle.dmn_handle, result))
|
||||
{
|
||||
OS_MutexScopeRWPromote(stripe->rw_mutex)
|
||||
if(node != 0)
|
||||
{
|
||||
for(CTRL_ThreadRegCacheNode *n = slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(ctrl_handle_match(n->handle, handle))
|
||||
{
|
||||
node = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(node != 0)
|
||||
{
|
||||
need_stale = 0;
|
||||
node->reg_gen = current_reg_gen;
|
||||
MemoryCopy(node->block, result, reg_block_size);
|
||||
}
|
||||
need_stale = 0;
|
||||
node->reg_gen = current_reg_gen;
|
||||
MemoryCopy(node->block, result, reg_block_size);
|
||||
}
|
||||
}
|
||||
if(need_stale)
|
||||
@@ -3108,12 +3077,11 @@ ctrl_u2c_push_msgs(CTRL_MsgList *msgs, U64 endt_us)
|
||||
{
|
||||
U64 unconsumed_size = (ctrl_state->u2c_ring_write_pos-ctrl_state->u2c_ring_read_pos);
|
||||
U64 available_size = ctrl_state->u2c_ring_size-unconsumed_size;
|
||||
if(available_size >= sizeof(U64) + msgs_srlzed_baked.size)
|
||||
U64 needed_size = sizeof(msgs_srlzed_baked.size) + msgs_srlzed_baked.size;
|
||||
if(available_size >= needed_size)
|
||||
{
|
||||
ctrl_state->u2c_ring_write_pos += ring_write_struct(ctrl_state->u2c_ring_base, ctrl_state->u2c_ring_size, ctrl_state->u2c_ring_write_pos, &msgs_srlzed_baked.size);
|
||||
ctrl_state->u2c_ring_write_pos += ring_write(ctrl_state->u2c_ring_base, ctrl_state->u2c_ring_size, ctrl_state->u2c_ring_write_pos, msgs_srlzed_baked.str, msgs_srlzed_baked.size);
|
||||
ctrl_state->u2c_ring_write_pos += 7;
|
||||
ctrl_state->u2c_ring_write_pos -= ctrl_state->u2c_ring_write_pos%8;
|
||||
good = 1;
|
||||
break;
|
||||
}
|
||||
@@ -3146,8 +3114,6 @@ ctrl_u2c_pop_msgs(Arena *arena)
|
||||
msgs_srlzed_baked.size = size_to_decode;
|
||||
msgs_srlzed_baked.str = push_array_no_zero(scratch.arena, U8, msgs_srlzed_baked.size);
|
||||
ctrl_state->u2c_ring_read_pos += ring_read(ctrl_state->u2c_ring_base, ctrl_state->u2c_ring_size, ctrl_state->u2c_ring_read_pos, msgs_srlzed_baked.str, size_to_decode);
|
||||
ctrl_state->u2c_ring_read_pos += 7;
|
||||
ctrl_state->u2c_ring_read_pos -= ctrl_state->u2c_ring_read_pos%8;
|
||||
break;
|
||||
}
|
||||
os_condition_variable_wait(ctrl_state->u2c_ring_cv, ctrl_state->u2c_ring_mutex, max_U64);
|
||||
@@ -3174,12 +3140,11 @@ ctrl_c2u_push_events(CTRL_EventList *events)
|
||||
{
|
||||
U64 unconsumed_size = (ctrl_state->c2u_ring_write_pos-ctrl_state->c2u_ring_read_pos);
|
||||
U64 available_size = ctrl_state->c2u_ring_size-unconsumed_size;
|
||||
if(available_size >= sizeof(U64) + event_srlzed.size)
|
||||
U64 needed_size = sizeof(event_srlzed.size) + event_srlzed.size;
|
||||
if(available_size >= needed_size)
|
||||
{
|
||||
ctrl_state->c2u_ring_write_pos += ring_write_struct(ctrl_state->c2u_ring_base, ctrl_state->c2u_ring_size, ctrl_state->c2u_ring_write_pos, &event_srlzed.size);
|
||||
ctrl_state->c2u_ring_write_pos += ring_write(ctrl_state->c2u_ring_base, ctrl_state->c2u_ring_size, ctrl_state->c2u_ring_write_pos, event_srlzed.str, event_srlzed.size);
|
||||
ctrl_state->c2u_ring_write_pos += 7;
|
||||
ctrl_state->c2u_ring_write_pos -= ctrl_state->c2u_ring_write_pos%8;
|
||||
break;
|
||||
}
|
||||
os_condition_variable_wait(ctrl_state->c2u_ring_cv, ctrl_state->c2u_ring_mutex, os_now_microseconds()+100);
|
||||
@@ -3211,8 +3176,6 @@ ctrl_c2u_pop_events(Arena *arena)
|
||||
event_srlzed.size = size_to_decode;
|
||||
event_srlzed.str = push_array_no_zero(scratch.arena, U8, event_srlzed.size);
|
||||
ctrl_state->c2u_ring_read_pos += ring_read(ctrl_state->c2u_ring_base, ctrl_state->c2u_ring_size, ctrl_state->c2u_ring_read_pos, event_srlzed.str, event_srlzed.size);
|
||||
ctrl_state->c2u_ring_read_pos += 7;
|
||||
ctrl_state->c2u_ring_read_pos -= ctrl_state->c2u_ring_read_pos%8;
|
||||
CTRL_Event *new_event = ctrl_event_list_push(arena, &events);
|
||||
*new_event = ctrl_event_from_serialized_string(arena, event_srlzed);
|
||||
}
|
||||
@@ -3250,8 +3213,7 @@ ctrl_thread__entry_point(void *p)
|
||||
//- rjf: process messages
|
||||
DMN_CtrlExclusiveAccessScope
|
||||
{
|
||||
B32 done = 0;
|
||||
for(CTRL_MsgNode *msg_n = msgs.first; msg_n != 0 && done == 0; msg_n = msg_n->next)
|
||||
for(CTRL_MsgNode *msg_n = msgs.first; msg_n != 0; msg_n = msg_n->next)
|
||||
{
|
||||
CTRL_Msg *msg = &msg_n->v;
|
||||
{
|
||||
@@ -3275,9 +3237,10 @@ ctrl_thread__entry_point(void *p)
|
||||
case CTRL_MsgKind_Launch: {ctrl_thread__launch (ctrl_ctx, msg);}break;
|
||||
case CTRL_MsgKind_Attach: {ctrl_thread__attach (ctrl_ctx, msg);}break;
|
||||
case CTRL_MsgKind_Kill: {ctrl_thread__kill (ctrl_ctx, msg);}break;
|
||||
case CTRL_MsgKind_KillAll: {ctrl_thread__kill_all (ctrl_ctx, msg);}break;
|
||||
case CTRL_MsgKind_Detach: {ctrl_thread__detach (ctrl_ctx, msg);}break;
|
||||
case CTRL_MsgKind_Run: {ctrl_thread__run (ctrl_ctx, msg); done = 1;}break;
|
||||
case CTRL_MsgKind_SingleStep: {ctrl_thread__single_step (ctrl_ctx, msg); done = 1;}break;
|
||||
case CTRL_MsgKind_Run: {ctrl_thread__run (ctrl_ctx, msg);}break;
|
||||
case CTRL_MsgKind_SingleStep: {ctrl_thread__single_step (ctrl_ctx, msg);}break;
|
||||
|
||||
//- rjf: configuration
|
||||
case CTRL_MsgKind_SetUserEntryPoints:
|
||||
@@ -3474,10 +3437,10 @@ ctrl_thread__module_open(CTRL_Handle process, CTRL_Handle module, Rng1U64 vaddr_
|
||||
Rng1U64 tls_vaddr_range = {0};
|
||||
U32 pdb_dbg_time = 0;
|
||||
U32 pdb_dbg_age = 0;
|
||||
OS_Guid pdb_dbg_guid = {0};
|
||||
Guid pdb_dbg_guid = {0};
|
||||
String8 pdb_dbg_path = str8_zero();
|
||||
U32 rdi_dbg_time = 0;
|
||||
OS_Guid rdi_dbg_guid = {0};
|
||||
Guid rdi_dbg_guid = {0};
|
||||
String8 rdi_dbg_path = str8_zero();
|
||||
ProfScope("unpack relevant PE info")
|
||||
{
|
||||
@@ -3614,7 +3577,6 @@ ctrl_thread__module_open(CTRL_Handle process, CTRL_Handle module, Rng1U64 vaddr_
|
||||
tls_vaddr_range = r1u64(tls_header.index_address, tls_header.index_address+sizeof(U32));
|
||||
|
||||
// rjf: grab data about debug info
|
||||
|
||||
if(data_dir_count > PE_DataDirectoryIndex_DEBUG)
|
||||
{
|
||||
// rjf: read data dir
|
||||
@@ -3683,27 +3645,28 @@ ctrl_thread__module_open(CTRL_Handle process, CTRL_Handle module, Rng1U64 vaddr_
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
String8 exe_folder = str8_chop_last_slash(path);
|
||||
String8 rdi_path__absolute = rdi_dbg_path;
|
||||
String8 rdi_path__relative = push_str8f(scratch.arena, "%S/%S", exe_folder, rdi_dbg_path);
|
||||
String8 pdb_path__absolute = pdb_dbg_path;
|
||||
String8 pdb_path__relative = push_str8f(scratch.arena, "%S/%S", exe_folder, pdb_dbg_path);
|
||||
String8 dbg_path_candidates[] =
|
||||
String8List dbg_path_candidates = {0};
|
||||
if(rdi_dbg_path.size != 0)
|
||||
{
|
||||
/* inferred (treated as absolute): */ rdi_path__absolute,
|
||||
/* inferred (treated as relative): */ rdi_path__relative,
|
||||
/* inferred (treated as absolute): */ pdb_path__absolute,
|
||||
/* inferred (treated as relative): */ pdb_path__relative,
|
||||
/* "foo.exe" -> "foo.rdi" */ push_str8f(scratch.arena, "%S.rdi", str8_chop_last_dot(path)),
|
||||
/* "foo.exe" -> "foo.exe.rdi" */ push_str8f(scratch.arena, "%S.rdi", path),
|
||||
/* "foo.exe" -> "foo.pdb" */ push_str8f(scratch.arena, "%S.pdb", str8_chop_last_dot(path)),
|
||||
/* "foo.exe" -> "foo.exe.pdb" */ push_str8f(scratch.arena, "%S.pdb", path),
|
||||
};
|
||||
for(U64 idx = 0; idx < ArrayCount(dbg_path_candidates); idx += 1)
|
||||
str8_list_push(scratch.arena, &dbg_path_candidates, rdi_dbg_path);
|
||||
str8_list_pushf(scratch.arena, &dbg_path_candidates, "%S/%S", exe_folder, rdi_dbg_path);
|
||||
}
|
||||
if(pdb_dbg_path.size != 0)
|
||||
{
|
||||
FileProperties props = os_properties_from_file_path(dbg_path_candidates[idx]);
|
||||
str8_list_push(scratch.arena, &dbg_path_candidates, pdb_dbg_path);
|
||||
str8_list_pushf(scratch.arena, &dbg_path_candidates, "%S/%S", exe_folder, pdb_dbg_path);
|
||||
}
|
||||
str8_list_pushf(scratch.arena, &dbg_path_candidates, "%S.pdb", str8_chop_last_dot(path));
|
||||
str8_list_pushf(scratch.arena, &dbg_path_candidates, "%S.pdb", path);
|
||||
str8_list_pushf(scratch.arena, &dbg_path_candidates, "%S.rdi", str8_chop_last_dot(path));
|
||||
str8_list_pushf(scratch.arena, &dbg_path_candidates, "%S.rdi", path);
|
||||
for(String8Node *n = dbg_path_candidates.first; n != 0; n = n->next)
|
||||
{
|
||||
String8 candidate_path = n->string;
|
||||
FileProperties props = os_properties_from_file_path(candidate_path);
|
||||
if(props.modified != 0 && props.size != 0)
|
||||
{
|
||||
initial_debug_info_path = push_str8_copy(arena, dbg_path_candidates[idx]);
|
||||
initial_debug_info_path = push_str8_copy(arena, candidate_path);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -4146,6 +4109,196 @@ ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg,
|
||||
}
|
||||
ctrl_c2u_push_events(&evts);
|
||||
|
||||
//- rjf: if this is the first process in a session, clear the debug directory
|
||||
// cache state
|
||||
if(ctrl_state->process_counter == 1 && event->kind == DMN_EventKind_CreateProcess)
|
||||
{
|
||||
arena_clear(ctrl_state->dbg_dir_arena);
|
||||
ctrl_state->dbg_dir_root = push_array(ctrl_state->dbg_dir_arena, CTRL_DbgDirNode, 1);
|
||||
}
|
||||
|
||||
//- rjf: when a new module is loaded, pre-emptively try to open all adjacent
|
||||
// debug infos. with debug events, we learn about loaded modules serially,
|
||||
// and we need to completely load debug info before continuing. for massive
|
||||
// projects, this is a problem, because completely loading debug info isn't a
|
||||
// trivial cost, and there are often 1000s of DLLs.
|
||||
//
|
||||
// an imperfect but usually reasonable heuristic is to look at adjacent
|
||||
// debug info files, in the same or under the directory as the initially
|
||||
// loaded, and pre-emptively convert all of them (which for us is the
|
||||
// heaviest part of debug info loading, if native RDI is not used).
|
||||
//
|
||||
// only do this on the first ever loaded module, *or* once we get beyond 256
|
||||
// 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 &&
|
||||
(ctrl_state->ctrl_thread_entity_store->entity_kind_counts[CTRL_EntityKind_Module] > 256 ||
|
||||
ctrl_state->ctrl_thread_entity_store->entity_kind_counts[CTRL_EntityKind_Module] == 1))
|
||||
{
|
||||
//- 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);
|
||||
CTRL_Entity *process = ctrl_entity_from_handle(ctrl_state->ctrl_thread_entity_store, process_handle);
|
||||
CTRL_Entity *loaded_module = ctrl_entity_from_handle(ctrl_state->ctrl_thread_entity_store, loaded_module_handle);
|
||||
|
||||
//- rjf: for each module, use its full path as the start to a new limited recursive
|
||||
// directory search. cache each directory once traversed in the dbg_dir tree. if any
|
||||
// node is not cached, then scan it & pre-emptively convert debug info.
|
||||
ProfScope("pre-emptively load adjacent debug info for %.*s", str8_varg(loaded_module->string))
|
||||
{
|
||||
//- rjf: calculate seed path
|
||||
DI_Key loaded_di_key = ctrl_dbgi_key_from_module(loaded_module);
|
||||
String8 loaded_di_name = str8_skip_last_slash(loaded_di_key.path);
|
||||
String8 debug_info_ext = str8_skip_last_dot(loaded_di_key.path);
|
||||
String8 seed_folder_path = str8_chop_last_slash(loaded_di_key.path);
|
||||
if(seed_folder_path.size == 0)
|
||||
{
|
||||
String8 module_path = loaded_module->string;
|
||||
seed_folder_path = str8_chop_last_slash(module_path);
|
||||
}
|
||||
|
||||
//- rjf: split seed path
|
||||
String8List seed_path_parts = str8_split_path(scratch.arena, seed_folder_path);
|
||||
|
||||
//- rjf: find parent dir node for this module's debug info; build tree leading to this dir
|
||||
CTRL_DbgDirNode *parent_dir_node = ctrl_state->dbg_dir_root;
|
||||
for(String8Node *n = seed_path_parts.first; n != 0; n = n->next)
|
||||
{
|
||||
String8 name = n->string;
|
||||
CTRL_DbgDirNode *next_child = 0;
|
||||
for(CTRL_DbgDirNode *child = parent_dir_node->first; child != 0; child = child->next)
|
||||
{
|
||||
if(str8_match(child->name, name, StringMatchFlag_CaseInsensitive))
|
||||
{
|
||||
next_child = child;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(next_child == 0)
|
||||
{
|
||||
next_child = push_array(ctrl_state->dbg_dir_arena, CTRL_DbgDirNode, 1);
|
||||
DLLPushBack(parent_dir_node->first, parent_dir_node->last, next_child);
|
||||
next_child->parent = parent_dir_node;
|
||||
next_child->name = push_str8_copy(ctrl_state->dbg_dir_arena, name);
|
||||
parent_dir_node->child_count += 1;
|
||||
}
|
||||
parent_dir_node = next_child;
|
||||
}
|
||||
|
||||
//- rjf: count modules
|
||||
{
|
||||
parent_dir_node->module_direct_count += 1;
|
||||
}
|
||||
|
||||
//- rjf: iterate from dir node up its ancestor chain - do recursive
|
||||
// searches if this is an ancestor of loaded modules, it has not been
|
||||
// searched yet, but it has >4 child branches, meaning it looks like
|
||||
// project directory
|
||||
//
|
||||
DI_KeyList preemptively_loaded_keys = {0};
|
||||
for(CTRL_DbgDirNode *dir_node = parent_dir_node; dir_node != 0; dir_node = dir_node->parent)
|
||||
{
|
||||
if(dir_node->search_count == 0 && dir_node->module_direct_count >= 1)
|
||||
{
|
||||
//- rjf: form full path of this directory node
|
||||
String8List dir_node_path_parts = {0};
|
||||
for(CTRL_DbgDirNode *n = dir_node; n != 0; n = n->parent)
|
||||
{
|
||||
if(n->name.size != 0)
|
||||
{
|
||||
str8_list_push_front(scratch.arena, &dir_node_path_parts, n->name);
|
||||
}
|
||||
}
|
||||
String8 dir_node_path = str8_list_join(scratch.arena, &dir_node_path_parts, &(StringJoin){.sep = str8_lit("/")});
|
||||
|
||||
//- rjf: iterate downwards from this directory recursively, locate
|
||||
// debug infos, and pre-emptively convert
|
||||
typedef struct Task Task;
|
||||
struct Task
|
||||
{
|
||||
Task *next;
|
||||
CTRL_DbgDirNode *node;
|
||||
String8 path;
|
||||
};
|
||||
Task start_task = {0, dir_node, dir_node_path};
|
||||
Task *first_task = &start_task;
|
||||
Task *last_task = first_task;
|
||||
U64 task_count = 0;
|
||||
for(Task *t = first_task; t != 0; t = t->next)
|
||||
{
|
||||
ProfBegin("search task %.*s", str8_varg(t->path));
|
||||
|
||||
// rjf: increment search counter
|
||||
t->node->search_count += 1;
|
||||
|
||||
// rjf: iterate this directory. if debug infos are encountered,
|
||||
// kick off pre-emptive conversion, and gather key. if folders
|
||||
// are encountered, then add them to the tree, and kick off a
|
||||
// sub-search if needed.
|
||||
OS_FileIter *it = os_file_iter_begin(scratch.arena, t->path, 0);
|
||||
U64 idx = 0;
|
||||
for(OS_FileInfo info = {0}; idx < 16384 && os_file_iter_next(scratch.arena, it, &info); idx += 1)
|
||||
{
|
||||
// rjf: folder -> do sub-search if not duplicative
|
||||
if(info.props.flags & FilePropertyFlag_IsFolder && task_count < 16384 && !str8_match(str8_prefix(info.name, 1), str8_lit("."), 0))
|
||||
{
|
||||
CTRL_DbgDirNode *existing_dir_child = 0;
|
||||
for(CTRL_DbgDirNode *child = t->node->first; child != 0; child = child->next)
|
||||
{
|
||||
if(str8_match(child->name, info.name, StringMatchFlag_CaseInsensitive))
|
||||
{
|
||||
existing_dir_child = child;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(existing_dir_child == 0)
|
||||
{
|
||||
existing_dir_child = push_array(ctrl_state->dbg_dir_arena, CTRL_DbgDirNode, 1);
|
||||
DLLPushBack(t->node->first, t->node->last, existing_dir_child);
|
||||
existing_dir_child->parent = t->node;
|
||||
existing_dir_child->name = push_str8_copy(ctrl_state->dbg_dir_arena, info.name);
|
||||
t->node->child_count += 1;
|
||||
}
|
||||
if(existing_dir_child->search_count == 0)
|
||||
{
|
||||
Task *task = push_array(scratch.arena, Task, 1);
|
||||
task->node = existing_dir_child;
|
||||
task->path = push_str8f(scratch.arena, "%S/%S", t->path, info.name);
|
||||
SLLQueuePush(first_task, last_task, task);
|
||||
task_count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: debug info file -> kick off open
|
||||
else if(preemptively_loaded_keys.count < 4096 &&
|
||||
!(info.props.flags & FilePropertyFlag_IsFolder) &&
|
||||
str8_match(str8_skip_last_dot(info.name), debug_info_ext, StringMatchFlag_CaseInsensitive) &&
|
||||
!str8_match(loaded_di_name, info.name, StringMatchFlag_CaseInsensitive))
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
os_file_iter_end(it);
|
||||
ProfEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//- 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, max_U64);
|
||||
di_scope_close(di_scope);
|
||||
di_close(&n->v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: clear process memory cache, if we've just started a lone process
|
||||
if(event->kind == DMN_EventKind_CreateProcess && ctrl_state->process_counter == 1)
|
||||
{
|
||||
@@ -4301,13 +4454,14 @@ ctrl_thread__launch(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg)
|
||||
//- rjf: launch
|
||||
OS_ProcessLaunchParams params = {0};
|
||||
{
|
||||
params.cmd_line = msg->cmd_line_string_list;
|
||||
params.path = msg->path;
|
||||
params.env = msg->env_string_list;
|
||||
params.inherit_env = msg->env_inherit;
|
||||
params.stdout_file = stdout_handle;
|
||||
params.stderr_file = stderr_handle;
|
||||
params.stdin_file = stdin_handle;
|
||||
params.cmd_line = msg->cmd_line_string_list;
|
||||
params.path = msg->path;
|
||||
params.env = msg->env_string_list;
|
||||
params.inherit_env = msg->env_inherit;
|
||||
params.debug_subprocesses = msg->debug_subprocesses;
|
||||
params.stdout_file = stdout_handle;
|
||||
params.stderr_file = stderr_handle;
|
||||
params.stdin_file = stdin_handle;
|
||||
}
|
||||
U32 id = dmn_ctrl_launch(ctrl_ctx, ¶ms);
|
||||
|
||||
@@ -4391,6 +4545,7 @@ ctrl_thread__kill(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg)
|
||||
B32 kill_worked = dmn_ctrl_kill(ctrl_ctx, process, exit_code);
|
||||
|
||||
//- rjf: wait for process to be dead
|
||||
CTRL_EventCause cause = CTRL_EventCause_Finished;
|
||||
if(kill_worked)
|
||||
{
|
||||
DMN_RunCtrls run_ctrls = {0};
|
||||
@@ -4401,12 +4556,102 @@ ctrl_thread__kill(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg)
|
||||
for(B32 done = 0; done == 0;)
|
||||
{
|
||||
DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, ctrl_ctx, msg, &run_ctrls, 0);
|
||||
if(event->kind == DMN_EventKind_ExitProcess && dmn_handle_match(event->process, process))
|
||||
switch(event->kind)
|
||||
{
|
||||
done = 1;
|
||||
default:{}break;
|
||||
case DMN_EventKind_ExitProcess:
|
||||
if(dmn_handle_match(event->process, process))
|
||||
{
|
||||
done = 1;
|
||||
}break;
|
||||
case DMN_EventKind_Error:{done = 1; cause = CTRL_EventCause_Error;}break;
|
||||
case DMN_EventKind_Halt: {done = 1; cause = CTRL_EventCause_InterruptedByHalt;}break;
|
||||
}
|
||||
if(event->kind == DMN_EventKind_Null ||
|
||||
event->kind == DMN_EventKind_Error)
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: record stop
|
||||
{
|
||||
CTRL_EventList evts = {0};
|
||||
CTRL_Event *event = ctrl_event_list_push(scratch.arena, &evts);
|
||||
event->kind = CTRL_EventKind_Stopped;
|
||||
event->cause = cause;
|
||||
event->msg_id = msg->msg_id;
|
||||
if(kill_worked)
|
||||
{
|
||||
event->entity = msg->entity;
|
||||
}
|
||||
ctrl_c2u_push_events(&evts);
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
ProfEnd();
|
||||
}
|
||||
|
||||
internal void
|
||||
ctrl_thread__kill_all(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
U32 exit_code = msg->exit_code;
|
||||
|
||||
//- rjf: gather all currently existing processes
|
||||
CTRL_EntityList initial_processes = ctrl_entity_list_from_kind(ctrl_state->ctrl_thread_entity_store, CTRL_EntityKind_Process);
|
||||
typedef struct Task Task;
|
||||
struct Task
|
||||
{
|
||||
Task *next;
|
||||
Task *prev;
|
||||
CTRL_Entity *process;
|
||||
};
|
||||
Task *first_task = 0;
|
||||
Task *last_task = 0;
|
||||
for(CTRL_EntityNode *n = initial_processes.first; n != 0; n = n->next)
|
||||
{
|
||||
Task *t = push_array(scratch.arena, Task, 1);
|
||||
t->process = n->v;
|
||||
DLLPushBack(first_task, last_task, t);
|
||||
}
|
||||
|
||||
//- rjf: kill processes as needed, wait for all processes to be dead
|
||||
CTRL_EventCause cause = CTRL_EventCause_Finished;
|
||||
if(first_task != 0)
|
||||
{
|
||||
DMN_RunCtrls run_ctrls = {0};
|
||||
for(B32 done = 0; !done;)
|
||||
{
|
||||
// rjf: kill remaining processes
|
||||
for(Task *t = first_task, *next = 0; t != 0; t = next)
|
||||
{
|
||||
next = t->next;
|
||||
B32 kill_worked = dmn_ctrl_kill(ctrl_ctx, t->process->handle.dmn_handle, exit_code);
|
||||
if(kill_worked)
|
||||
{
|
||||
DLLRemove(first_task, last_task, t);
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: get next event
|
||||
DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, ctrl_ctx, msg, &run_ctrls, 0);
|
||||
|
||||
// rjf: process event
|
||||
switch(event->kind)
|
||||
{
|
||||
default:{}break;
|
||||
case DMN_EventKind_CreateProcess:
|
||||
{
|
||||
CTRL_Entity *new_process = ctrl_entity_from_handle(ctrl_state->ctrl_thread_entity_store, ctrl_handle_make(CTRL_MachineID_Local, event->process));
|
||||
Task *t = push_array(scratch.arena, Task, 1);
|
||||
t->process = new_process;
|
||||
DLLPushBack(first_task, last_task, t);
|
||||
}break;
|
||||
case DMN_EventKind_Error:{done = 1; cause = CTRL_EventCause_Error;}break;
|
||||
case DMN_EventKind_Halt: {done = 1; cause = CTRL_EventCause_InterruptedByHalt;}break;
|
||||
}
|
||||
|
||||
// rjf: end if all processes are gone
|
||||
CTRL_EntityList processes = ctrl_entity_list_from_kind(ctrl_state->ctrl_thread_entity_store, CTRL_EntityKind_Process);
|
||||
if(processes.count == 0)
|
||||
{
|
||||
done = 1;
|
||||
}
|
||||
@@ -4418,12 +4663,8 @@ ctrl_thread__kill(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg)
|
||||
CTRL_EventList evts = {0};
|
||||
CTRL_Event *event = ctrl_event_list_push(scratch.arena, &evts);
|
||||
event->kind = CTRL_EventKind_Stopped;
|
||||
event->cause = CTRL_EventCause_Finished;
|
||||
event->cause = cause;
|
||||
event->msg_id = msg->msg_id;
|
||||
if(kill_worked)
|
||||
{
|
||||
event->entity = msg->entity;
|
||||
}
|
||||
ctrl_c2u_push_events(&evts);
|
||||
}
|
||||
|
||||
@@ -4623,6 +4864,12 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg)
|
||||
switch(event->kind)
|
||||
{
|
||||
default:{}break;
|
||||
case DMN_EventKind_ExitThread:
|
||||
if(dmn_handle_match(event->thread, thread))
|
||||
{
|
||||
stop_cause = CTRL_EventCause_Error;
|
||||
goto stop;
|
||||
}break;
|
||||
case DMN_EventKind_Error: stop_cause = CTRL_EventCause_Error; goto stop;
|
||||
case DMN_EventKind_Exception: stop_cause = CTRL_EventCause_InterruptedByException; goto stop;
|
||||
case DMN_EventKind_Trap: stop_cause = CTRL_EventCause_InterruptedByTrap; goto stop;
|
||||
@@ -5700,167 +5947,168 @@ ctrl_u2ms_dequeue_req(CTRL_Handle *out_process, Rng1U64 *out_vaddr_range, B32 *o
|
||||
|
||||
//- rjf: entry point
|
||||
|
||||
internal void
|
||||
ctrl_mem_stream_thread__entry_point(void *p)
|
||||
ASYNC_WORK_DEF(ctrl_mem_stream_work)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
CTRL_ProcessMemoryCache *cache = &ctrl_state->process_memory_cache;
|
||||
for(;;)
|
||||
//- rjf: unpack next request
|
||||
CTRL_Handle process = {0};
|
||||
Rng1U64 vaddr_range = {0};
|
||||
B32 zero_terminated = 0;
|
||||
ctrl_u2ms_dequeue_req(&process, &vaddr_range, &zero_terminated);
|
||||
U128 key = ctrl_calc_hash_store_key_from_process_vaddr_range(process, vaddr_range, zero_terminated);
|
||||
ProfBegin("memory stream request");
|
||||
|
||||
//- rjf: unpack process memory cache key
|
||||
U64 process_hash = ctrl_hash_from_string(str8_struct(&process));
|
||||
U64 process_slot_idx = process_hash%cache->slots_count;
|
||||
U64 process_stripe_idx = process_slot_idx%cache->stripes_count;
|
||||
CTRL_ProcessMemoryCacheSlot *process_slot = &cache->slots[process_slot_idx];
|
||||
CTRL_ProcessMemoryCacheStripe *process_stripe = &cache->stripes[process_stripe_idx];
|
||||
|
||||
//- rjf: unpack address range hash cache key
|
||||
U64 range_hash = ctrl_hash_from_string(str8_struct(&vaddr_range));
|
||||
|
||||
//- rjf: take task
|
||||
B32 got_task = 0;
|
||||
U64 preexisting_mem_gen = 0;
|
||||
U128 preexisting_hash = {0};
|
||||
Rng1U64 vaddr_range_clamped = {0};
|
||||
OS_MutexScopeW(process_stripe->rw_mutex)
|
||||
{
|
||||
//- rjf: unpack next request
|
||||
CTRL_Handle process = {0};
|
||||
Rng1U64 vaddr_range = {0};
|
||||
B32 zero_terminated = 0;
|
||||
ctrl_u2ms_dequeue_req(&process, &vaddr_range, &zero_terminated);
|
||||
U128 key = ctrl_calc_hash_store_key_from_process_vaddr_range(process, vaddr_range, zero_terminated);
|
||||
|
||||
//- rjf: unpack process memory cache key
|
||||
U64 process_hash = ctrl_hash_from_string(str8_struct(&process));
|
||||
U64 process_slot_idx = process_hash%cache->slots_count;
|
||||
U64 process_stripe_idx = process_slot_idx%cache->stripes_count;
|
||||
CTRL_ProcessMemoryCacheSlot *process_slot = &cache->slots[process_slot_idx];
|
||||
CTRL_ProcessMemoryCacheStripe *process_stripe = &cache->stripes[process_stripe_idx];
|
||||
|
||||
//- rjf: unpack address range hash cache key
|
||||
U64 range_hash = ctrl_hash_from_string(str8_struct(&vaddr_range));
|
||||
|
||||
//- rjf: take task
|
||||
B32 got_task = 0;
|
||||
U64 preexisting_mem_gen = 0;
|
||||
U128 preexisting_hash = {0};
|
||||
Rng1U64 vaddr_range_clamped = {0};
|
||||
OS_MutexScopeW(process_stripe->rw_mutex)
|
||||
for(CTRL_ProcessMemoryCacheNode *n = process_slot->first; n != 0; n = n->next)
|
||||
{
|
||||
for(CTRL_ProcessMemoryCacheNode *n = process_slot->first; n != 0; n = n->next)
|
||||
if(ctrl_handle_match(n->handle, process))
|
||||
{
|
||||
if(ctrl_handle_match(n->handle, process))
|
||||
U64 range_slot_idx = range_hash%n->range_hash_slots_count;
|
||||
CTRL_ProcessMemoryRangeHashSlot *range_slot = &n->range_hash_slots[range_slot_idx];
|
||||
for(CTRL_ProcessMemoryRangeHashNode *range_n = range_slot->first; range_n != 0; range_n = range_n->next)
|
||||
{
|
||||
U64 range_slot_idx = range_hash%n->range_hash_slots_count;
|
||||
CTRL_ProcessMemoryRangeHashSlot *range_slot = &n->range_hash_slots[range_slot_idx];
|
||||
for(CTRL_ProcessMemoryRangeHashNode *range_n = range_slot->first; range_n != 0; range_n = range_n->next)
|
||||
if(MemoryMatchStruct(&range_n->vaddr_range, &vaddr_range) && range_n->zero_terminated == zero_terminated)
|
||||
{
|
||||
if(MemoryMatchStruct(&range_n->vaddr_range, &vaddr_range) && range_n->zero_terminated == zero_terminated)
|
||||
{
|
||||
got_task = !ins_atomic_u32_eval_cond_assign(&range_n->is_taken, 1, 0);
|
||||
preexisting_mem_gen = range_n->mem_gen;
|
||||
preexisting_hash = range_n->hash;
|
||||
vaddr_range_clamped = range_n->vaddr_range_clamped;
|
||||
goto take_task__break_all;
|
||||
}
|
||||
got_task = !ins_atomic_u32_eval_cond_assign(&range_n->is_taken, 1, 0);
|
||||
preexisting_mem_gen = range_n->mem_gen;
|
||||
preexisting_hash = range_n->hash;
|
||||
vaddr_range_clamped = range_n->vaddr_range_clamped;
|
||||
goto take_task__break_all;
|
||||
}
|
||||
}
|
||||
}
|
||||
take_task__break_all:;
|
||||
}
|
||||
|
||||
//- rjf: task was taken -> read memory
|
||||
U64 range_size = 0;
|
||||
Arena *range_arena = 0;
|
||||
void *range_base = 0;
|
||||
U64 zero_terminated_size = 0;
|
||||
U64 pre_read_mem_gen = dmn_mem_gen();
|
||||
U64 post_read_mem_gen = 0;
|
||||
if(got_task && pre_read_mem_gen != preexisting_mem_gen)
|
||||
take_task__break_all:;
|
||||
}
|
||||
|
||||
//- rjf: task was taken -> read memory
|
||||
U64 range_size = 0;
|
||||
Arena *range_arena = 0;
|
||||
void *range_base = 0;
|
||||
U64 zero_terminated_size = 0;
|
||||
U64 pre_read_mem_gen = dmn_mem_gen();
|
||||
U64 post_read_mem_gen = 0;
|
||||
if(got_task && pre_read_mem_gen != preexisting_mem_gen)
|
||||
{
|
||||
range_size = dim_1u64(vaddr_range_clamped);
|
||||
U64 page_size = os_get_system_info()->page_size;
|
||||
U64 arena_size = AlignPow2(range_size + ARENA_HEADER_SIZE, page_size);
|
||||
range_arena = arena_alloc(.reserve_size = range_size+ARENA_HEADER_SIZE, .commit_size = range_size+ARENA_HEADER_SIZE);
|
||||
if(range_arena == 0)
|
||||
{
|
||||
range_size = dim_1u64(vaddr_range_clamped);
|
||||
U64 page_size = os_get_system_info()->page_size;
|
||||
U64 arena_size = AlignPow2(range_size + ARENA_HEADER_SIZE, page_size);
|
||||
range_arena = arena_alloc(.reserve_size = range_size+ARENA_HEADER_SIZE, .commit_size = range_size+ARENA_HEADER_SIZE);
|
||||
if(range_arena == 0)
|
||||
range_size = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
range_base = push_array_no_zero(range_arena, U8, range_size);
|
||||
U64 bytes_read = 0;
|
||||
U64 retry_count = 0;
|
||||
U64 retry_limit = range_size > page_size ? 64 : 0;
|
||||
for(Rng1U64 vaddr_range_clamped_retry = vaddr_range_clamped;
|
||||
retry_count <= retry_limit;
|
||||
retry_count += 1)
|
||||
{
|
||||
range_size = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
range_base = push_array_no_zero(range_arena, U8, range_size);
|
||||
U64 bytes_read = 0;
|
||||
U64 retry_count = 0;
|
||||
U64 retry_limit = range_size > page_size ? 64 : 0;
|
||||
for(Rng1U64 vaddr_range_clamped_retry = vaddr_range_clamped;
|
||||
retry_count <= retry_limit;
|
||||
retry_count += 1)
|
||||
bytes_read = dmn_process_read(process.dmn_handle, vaddr_range_clamped_retry, range_base);
|
||||
if(bytes_read == 0 && vaddr_range_clamped_retry.max > vaddr_range_clamped_retry.min)
|
||||
{
|
||||
bytes_read = dmn_process_read(process.dmn_handle, vaddr_range_clamped_retry, range_base);
|
||||
if(bytes_read == 0 && vaddr_range_clamped_retry.max > vaddr_range_clamped_retry.min)
|
||||
{
|
||||
U64 diff = (vaddr_range_clamped_retry.max-vaddr_range_clamped_retry.min)/2;
|
||||
vaddr_range_clamped_retry.max -= diff;
|
||||
vaddr_range_clamped_retry.max = AlignDownPow2(vaddr_range_clamped_retry.max, page_size);
|
||||
if(diff == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
U64 diff = (vaddr_range_clamped_retry.max-vaddr_range_clamped_retry.min)/2;
|
||||
vaddr_range_clamped_retry.max -= diff;
|
||||
vaddr_range_clamped_retry.max = AlignDownPow2(vaddr_range_clamped_retry.max, page_size);
|
||||
if(diff == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(bytes_read == 0)
|
||||
else
|
||||
{
|
||||
arena_release(range_arena);
|
||||
range_base = 0;
|
||||
range_size = 0;
|
||||
range_arena = 0;
|
||||
}
|
||||
else if(bytes_read < range_size)
|
||||
{
|
||||
MemoryZero((U8 *)range_base + bytes_read, range_size-bytes_read);
|
||||
}
|
||||
zero_terminated_size = range_size;
|
||||
if(zero_terminated)
|
||||
{
|
||||
for(U64 idx = 0; idx < bytes_read; idx += 1)
|
||||
{
|
||||
if(((U8 *)range_base)[idx] == 0)
|
||||
{
|
||||
zero_terminated_size = idx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
post_read_mem_gen = dmn_mem_gen();
|
||||
}
|
||||
|
||||
//- rjf: read successful -> submit to hash store
|
||||
U128 hash = {0};
|
||||
if(got_task && range_base != 0 && pre_read_mem_gen == post_read_mem_gen)
|
||||
{
|
||||
hash = hs_submit_data(key, &range_arena, str8((U8*)range_base, zero_terminated_size));
|
||||
}
|
||||
else if(range_arena != 0)
|
||||
{
|
||||
arena_release(range_arena);
|
||||
}
|
||||
|
||||
//- rjf: commit hash to cache
|
||||
if(got_task) OS_MutexScopeW(process_stripe->rw_mutex)
|
||||
{
|
||||
for(CTRL_ProcessMemoryCacheNode *n = process_slot->first; n != 0; n = n->next)
|
||||
if(bytes_read == 0)
|
||||
{
|
||||
if(ctrl_handle_match(n->handle, process))
|
||||
arena_release(range_arena);
|
||||
range_base = 0;
|
||||
range_size = 0;
|
||||
range_arena = 0;
|
||||
}
|
||||
else if(bytes_read < range_size)
|
||||
{
|
||||
MemoryZero((U8 *)range_base + bytes_read, range_size-bytes_read);
|
||||
}
|
||||
zero_terminated_size = range_size;
|
||||
if(zero_terminated)
|
||||
{
|
||||
for(U64 idx = 0; idx < bytes_read; idx += 1)
|
||||
{
|
||||
U64 range_slot_idx = range_hash%n->range_hash_slots_count;
|
||||
CTRL_ProcessMemoryRangeHashSlot *range_slot = &n->range_hash_slots[range_slot_idx];
|
||||
for(CTRL_ProcessMemoryRangeHashNode *range_n = range_slot->first; range_n != 0; range_n = range_n->next)
|
||||
if(((U8 *)range_base)[idx] == 0)
|
||||
{
|
||||
if(MemoryMatchStruct(&range_n->vaddr_range, &vaddr_range) && range_n->zero_terminated == zero_terminated)
|
||||
{
|
||||
if(!u128_match(u128_zero(), hash))
|
||||
{
|
||||
range_n->hash = hash;
|
||||
range_n->mem_gen = post_read_mem_gen;
|
||||
}
|
||||
ins_atomic_u32_eval_assign(&range_n->is_taken, 0);
|
||||
goto commit__break_all;
|
||||
}
|
||||
zero_terminated_size = idx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
commit__break_all:;
|
||||
}
|
||||
|
||||
//- rjf: broadcast changes
|
||||
os_condition_variable_broadcast(process_stripe->cv);
|
||||
post_read_mem_gen = dmn_mem_gen();
|
||||
}
|
||||
|
||||
//- rjf: read successful -> submit to hash store
|
||||
U128 hash = {0};
|
||||
if(got_task && range_base != 0 && pre_read_mem_gen == post_read_mem_gen)
|
||||
{
|
||||
hash = hs_submit_data(key, &range_arena, str8((U8*)range_base, zero_terminated_size));
|
||||
}
|
||||
else if(range_arena != 0)
|
||||
{
|
||||
arena_release(range_arena);
|
||||
}
|
||||
|
||||
//- rjf: commit hash to cache
|
||||
if(got_task) OS_MutexScopeW(process_stripe->rw_mutex)
|
||||
{
|
||||
for(CTRL_ProcessMemoryCacheNode *n = process_slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(ctrl_handle_match(n->handle, process))
|
||||
{
|
||||
U64 range_slot_idx = range_hash%n->range_hash_slots_count;
|
||||
CTRL_ProcessMemoryRangeHashSlot *range_slot = &n->range_hash_slots[range_slot_idx];
|
||||
for(CTRL_ProcessMemoryRangeHashNode *range_n = range_slot->first; range_n != 0; range_n = range_n->next)
|
||||
{
|
||||
if(MemoryMatchStruct(&range_n->vaddr_range, &vaddr_range) && range_n->zero_terminated == zero_terminated)
|
||||
{
|
||||
if(!u128_match(u128_zero(), hash))
|
||||
{
|
||||
range_n->hash = hash;
|
||||
range_n->mem_gen = post_read_mem_gen;
|
||||
}
|
||||
ins_atomic_u32_eval_assign(&range_n->is_taken, 0);
|
||||
goto commit__break_all;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
commit__break_all:;
|
||||
}
|
||||
|
||||
//- rjf: broadcast changes
|
||||
os_condition_variable_broadcast(process_stripe->cv);
|
||||
ProfEnd();
|
||||
ProfEnd();
|
||||
return 0;
|
||||
}
|
||||
|
||||
+45
-10
@@ -15,6 +15,20 @@ typedef U64 CTRL_MachineID;
|
||||
////////////////////////////////
|
||||
//~ rjf: Meta Evaluation Types
|
||||
|
||||
//- rjf: auto-checkbox b32s
|
||||
|
||||
typedef struct CTRL_CheckB32 CTRL_CheckB32;
|
||||
struct CTRL_CheckB32
|
||||
{
|
||||
B32 b32;
|
||||
};
|
||||
|
||||
struct_members(CTRL_CheckB32)
|
||||
{
|
||||
member_lit_comp(CTRL_CheckB32, type(B32), b32),
|
||||
};
|
||||
struct_type(CTRL_CheckB32);
|
||||
|
||||
//- rjf: styled string types
|
||||
|
||||
ptr_type(CTRL_PlainString8__str_ptr_type, type(U8), .flags = TypeFlag_IsPlainText,.count_delimiter_name = str8_lit_comp("size"));
|
||||
@@ -74,12 +88,13 @@ typedef struct CTRL_MetaEval CTRL_MetaEval;
|
||||
struct CTRL_MetaEval
|
||||
{
|
||||
#define CTRL_MetaEval_MemberXList \
|
||||
X(B32, enabled, "Enabled")\
|
||||
X(B32, frozen, "Frozen")\
|
||||
X(U64, hit_count, "Hit Count")\
|
||||
X(U64, id, "ID")\
|
||||
X(Rng1U64, vaddr_range, "Address Range")\
|
||||
X(U32, color, "Color")\
|
||||
X(B32, enabled, "Enabled")\
|
||||
X(B32, frozen, "Frozen")\
|
||||
X(U64, hit_count, "Hit Count")\
|
||||
X(U64, id, "ID")\
|
||||
X(Rng1U64, vaddr_range, "Address Range")\
|
||||
X(U32, color, "Color")\
|
||||
X(CTRL_CheckB32, debug_subprocesses,"Debug Subprocesses")\
|
||||
Y(String8, type(CTRL_CodeString8), label, "Label")\
|
||||
Y(String8, type(CTRL_PathString8), exe, "Executable Path")\
|
||||
Y(String8, type(CTRL_PathString8), dbg, "Debug Info Path")\
|
||||
@@ -138,6 +153,7 @@ struct_members(CTRL_TargetMetaEval)
|
||||
member_lit_comp(CTRL_MetaEval, type(CTRL_PathString8), stdout_path, .pretty_name = str8_lit_comp("Standard Output Path")),
|
||||
member_lit_comp(CTRL_MetaEval, type(CTRL_PathString8), stderr_path, .pretty_name = str8_lit_comp("Standard Error Path")),
|
||||
member_lit_comp(CTRL_MetaEval, type(CTRL_PathString8), stdin_path, .pretty_name = str8_lit_comp("Standard Input Path")),
|
||||
member_lit_comp(CTRL_MetaEval, type(CTRL_CheckB32), debug_subprocesses, .pretty_name = str8_lit_comp("Debug Subprocesses")),
|
||||
};
|
||||
|
||||
struct_members(CTRL_PinMetaEval)
|
||||
@@ -517,6 +533,7 @@ typedef enum CTRL_MsgKind
|
||||
CTRL_MsgKind_Launch,
|
||||
CTRL_MsgKind_Attach,
|
||||
CTRL_MsgKind_Kill,
|
||||
CTRL_MsgKind_KillAll,
|
||||
CTRL_MsgKind_Detach,
|
||||
CTRL_MsgKind_Run,
|
||||
CTRL_MsgKind_SingleStep,
|
||||
@@ -545,6 +562,7 @@ struct CTRL_Msg
|
||||
U32 entity_id;
|
||||
U32 exit_code;
|
||||
B32 env_inherit;
|
||||
B32 debug_subprocesses;
|
||||
U64 exception_code_filters[(CTRL_ExceptionCodeKind_COUNT+63)/64];
|
||||
String8 path;
|
||||
String8List entry_points;
|
||||
@@ -822,6 +840,23 @@ struct CTRL_ModuleImageInfoCache
|
||||
CTRL_ModuleImageInfoCacheStripe *stripes;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Touched Debug Info Directory Cache
|
||||
|
||||
typedef struct CTRL_DbgDirNode CTRL_DbgDirNode;
|
||||
struct CTRL_DbgDirNode
|
||||
{
|
||||
CTRL_DbgDirNode *first;
|
||||
CTRL_DbgDirNode *last;
|
||||
CTRL_DbgDirNode *next;
|
||||
CTRL_DbgDirNode *prev;
|
||||
CTRL_DbgDirNode *parent;
|
||||
String8 name;
|
||||
U64 search_count;
|
||||
U64 child_count;
|
||||
U64 module_direct_count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Wakeup Hook Function Types
|
||||
|
||||
@@ -878,6 +913,8 @@ struct CTRL_State
|
||||
CTRL_MetaEvalArray user_meta_evals;
|
||||
U64 exception_code_filters[(CTRL_ExceptionCodeKind_COUNT+63)/64];
|
||||
U64 process_counter;
|
||||
Arena *dbg_dir_arena;
|
||||
CTRL_DbgDirNode *dbg_dir_root;
|
||||
|
||||
// rjf: user -> memstream ring buffer
|
||||
U64 u2ms_ring_size;
|
||||
@@ -886,10 +923,6 @@ struct CTRL_State
|
||||
U64 u2ms_ring_read_pos;
|
||||
OS_Handle u2ms_ring_mutex;
|
||||
OS_Handle u2ms_ring_cv;
|
||||
|
||||
// rjf: memory stream threads
|
||||
U64 ms_thread_count;
|
||||
OS_Handle *ms_threads;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
@@ -1141,6 +1174,7 @@ internal void ctrl_thread__end_and_flush_info_log(void);
|
||||
internal void ctrl_thread__launch(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg);
|
||||
internal void ctrl_thread__attach(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg);
|
||||
internal void ctrl_thread__kill(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg);
|
||||
internal void ctrl_thread__kill_all(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg);
|
||||
internal void ctrl_thread__detach(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg);
|
||||
internal void ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg);
|
||||
internal void ctrl_thread__single_step(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg);
|
||||
@@ -1153,6 +1187,7 @@ internal B32 ctrl_u2ms_enqueue_req(CTRL_Handle process, Rng1U64 vaddr_range, B32
|
||||
internal void ctrl_u2ms_dequeue_req(CTRL_Handle *out_process, Rng1U64 *out_vaddr_range, B32 *out_zero_terminated);
|
||||
|
||||
//- rjf: entry point
|
||||
ASYNC_WORK_DEF(ctrl_mem_stream_work);
|
||||
internal void ctrl_mem_stream_thread__entry_point(void *p);
|
||||
|
||||
#endif // CTRL_CORE_H
|
||||
|
||||
+281
-300
@@ -41,7 +41,14 @@ dasm_inst_from_code(Arena *arena, Arch arch, U64 vaddr, String8 code, DASM_Synta
|
||||
ZydisDecodedOperand *first_visible_op = (zinst.info.operand_count_visible > 0 ? &zinst.operands[0] : 0);
|
||||
ZydisDecodedOperand *first_op = (zinst.info.operand_count > 0 ? &zinst.operands[0] : 0);
|
||||
ZydisDecodedOperand *second_op = (zinst.info.operand_count > 1 ? &zinst.operands[1] : 0);
|
||||
if(first_visible_op != 0)
|
||||
if(first_visible_op != 0 &&
|
||||
(first_visible_op->encoding == ZYDIS_OPERAND_ENCODING_JIMM8 ||
|
||||
first_visible_op->encoding == ZYDIS_OPERAND_ENCODING_JIMM16 ||
|
||||
first_visible_op->encoding == ZYDIS_OPERAND_ENCODING_JIMM32 ||
|
||||
first_visible_op->encoding == ZYDIS_OPERAND_ENCODING_JIMM64 ||
|
||||
first_visible_op->encoding == ZYDIS_OPERAND_ENCODING_JIMM16_32_64 ||
|
||||
first_visible_op->encoding == ZYDIS_OPERAND_ENCODING_JIMM32_32_64 ||
|
||||
first_visible_op->encoding == ZYDIS_OPERAND_ENCODING_JIMM16_32_32))
|
||||
{
|
||||
ZydisCalcAbsoluteAddress(&zinst.info, first_visible_op, vaddr, &jump_dest_vaddr);
|
||||
}
|
||||
@@ -267,31 +274,9 @@ dasm_init(void)
|
||||
dasm_shared->u2p_ring_base = push_array_no_zero(arena, U8, dasm_shared->u2p_ring_size);
|
||||
dasm_shared->u2p_ring_cv = os_condition_variable_alloc();
|
||||
dasm_shared->u2p_ring_mutex = os_mutex_alloc();
|
||||
dasm_shared->parse_thread_count = 1;
|
||||
dasm_shared->parse_threads = push_array(arena, OS_Handle, dasm_shared->parse_thread_count);
|
||||
for(U64 idx = 0; idx < dasm_shared->parse_thread_count; idx += 1)
|
||||
{
|
||||
dasm_shared->parse_threads[idx] = os_thread_launch(dasm_parse_thread__entry_point, (void *)idx, 0);
|
||||
}
|
||||
dasm_shared->evictor_detector_thread = os_thread_launch(dasm_evictor_detector_thread__entry_point, 0, 0);
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: User Clock
|
||||
|
||||
internal void
|
||||
dasm_user_clock_tick(void)
|
||||
{
|
||||
ins_atomic_u64_inc_eval(&dasm_shared->user_clock_idx);
|
||||
}
|
||||
|
||||
internal U64
|
||||
dasm_user_clock_idx(void)
|
||||
{
|
||||
U64 idx = ins_atomic_u64_eval(&dasm_shared->user_clock_idx);
|
||||
return idx;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Scoped Access
|
||||
|
||||
@@ -341,7 +326,7 @@ dasm_scope_touch_node__stripe_r_guarded(DASM_Scope *scope, DASM_Node *node)
|
||||
DASM_Touch *touch = push_array(dasm_tctx->arena, DASM_Touch, 1);
|
||||
ins_atomic_u64_inc_eval(&node->scope_ref_count);
|
||||
ins_atomic_u64_eval_assign(&node->last_time_touched_us, os_now_microseconds());
|
||||
ins_atomic_u64_eval_assign(&node->last_user_clock_idx_touched, dasm_user_clock_idx());
|
||||
ins_atomic_u64_eval_assign(&node->last_user_clock_idx_touched, update_tick_idx());
|
||||
touch->hash = node->hash;
|
||||
MemoryCopyStruct(&touch->params, &node->params);
|
||||
touch->params.dbgi_key = di_key_copy(dasm_tctx->arena, &touch->params.dbgi_key);
|
||||
@@ -423,6 +408,7 @@ dasm_info_from_hash_params(DASM_Scope *scope, U128 hash, DASM_Params *params)
|
||||
if(node_is_new)
|
||||
{
|
||||
dasm_u2p_enqueue_req(hash, params, max_U64);
|
||||
async_push_work(dasm_parse_work);
|
||||
}
|
||||
}
|
||||
return info;
|
||||
@@ -471,8 +457,6 @@ dasm_u2p_enqueue_req(U128 hash, DASM_Params *params, U64 endt_us)
|
||||
dasm_shared->u2p_ring_write_pos += ring_write_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_write_pos, ¶ms->dbgi_key.path.size);
|
||||
dasm_shared->u2p_ring_write_pos += ring_write(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_write_pos, params->dbgi_key.path.str, params->dbgi_key.path.size);
|
||||
dasm_shared->u2p_ring_write_pos += ring_write_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_write_pos, ¶ms->dbgi_key.min_timestamp);
|
||||
dasm_shared->u2p_ring_write_pos += 7;
|
||||
dasm_shared->u2p_ring_write_pos -= dasm_shared->u2p_ring_write_pos%8;
|
||||
break;
|
||||
}
|
||||
if(os_now_microseconds() >= endt_us)
|
||||
@@ -506,8 +490,6 @@ dasm_u2p_dequeue_req(Arena *arena, U128 *hash_out, DASM_Params *params_out)
|
||||
params_out->dbgi_key.path.str = push_array(arena, U8, params_out->dbgi_key.path.size);
|
||||
dasm_shared->u2p_ring_read_pos += ring_read(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_read_pos, params_out->dbgi_key.path.str, params_out->dbgi_key.path.size);
|
||||
dasm_shared->u2p_ring_read_pos += ring_read_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_read_pos, ¶ms_out->dbgi_key.min_timestamp);
|
||||
dasm_shared->u2p_ring_read_pos += 7;
|
||||
dasm_shared->u2p_ring_read_pos -= dasm_shared->u2p_ring_read_pos%8;
|
||||
break;
|
||||
}
|
||||
os_condition_variable_wait(dasm_shared->u2p_ring_cv, dasm_shared->u2p_ring_mutex, max_U64);
|
||||
@@ -515,284 +497,282 @@ dasm_u2p_dequeue_req(Arena *arena, U128 *hash_out, DASM_Params *params_out)
|
||||
os_condition_variable_broadcast(dasm_shared->u2p_ring_cv);
|
||||
}
|
||||
|
||||
internal void
|
||||
dasm_parse_thread__entry_point(void *p)
|
||||
ASYNC_WORK_DEF(dasm_parse_work)
|
||||
{
|
||||
ThreadNameF("[dasm] parse thread #%I64u", (U64)p);
|
||||
for(;;)
|
||||
ProfBeginFunction();
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
HS_Scope *hs_scope = hs_scope_open();
|
||||
DI_Scope *di_scope = di_scope_open();
|
||||
TXT_Scope *txt_scope = txt_scope_open();
|
||||
|
||||
//- rjf: get next request
|
||||
U128 hash = {0};
|
||||
DASM_Params params = {0};
|
||||
dasm_u2p_dequeue_req(scratch.arena, &hash, ¶ms);
|
||||
U64 change_gen = fs_change_gen();
|
||||
|
||||
//- rjf: unpack hash
|
||||
U64 slot_idx = hash.u64[1]%dasm_shared->slots_count;
|
||||
U64 stripe_idx = slot_idx%dasm_shared->stripes_count;
|
||||
DASM_Slot *slot = &dasm_shared->slots[slot_idx];
|
||||
DASM_Stripe *stripe = &dasm_shared->stripes[stripe_idx];
|
||||
|
||||
//- rjf: take task
|
||||
B32 got_task = 0;
|
||||
OS_MutexScopeR(stripe->rw_mutex)
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
HS_Scope *hs_scope = hs_scope_open();
|
||||
DI_Scope *di_scope = di_scope_open();
|
||||
TXT_Scope *txt_scope = txt_scope_open();
|
||||
|
||||
//- rjf: get next request
|
||||
U128 hash = {0};
|
||||
DASM_Params params = {0};
|
||||
dasm_u2p_dequeue_req(scratch.arena, &hash, ¶ms);
|
||||
U64 change_gen = fs_change_gen();
|
||||
|
||||
//- rjf: unpack hash
|
||||
U64 slot_idx = hash.u64[1]%dasm_shared->slots_count;
|
||||
U64 stripe_idx = slot_idx%dasm_shared->stripes_count;
|
||||
DASM_Slot *slot = &dasm_shared->slots[slot_idx];
|
||||
DASM_Stripe *stripe = &dasm_shared->stripes[stripe_idx];
|
||||
|
||||
//- rjf: take task
|
||||
B32 got_task = 0;
|
||||
OS_MutexScopeR(stripe->rw_mutex)
|
||||
for(DASM_Node *n = slot->first; n != 0; n = n->next)
|
||||
{
|
||||
for(DASM_Node *n = slot->first; n != 0; n = n->next)
|
||||
if(u128_match(n->hash, hash) && dasm_params_match(&n->params, ¶ms))
|
||||
{
|
||||
if(u128_match(n->hash, hash) && dasm_params_match(&n->params, ¶ms))
|
||||
{
|
||||
got_task = !ins_atomic_u32_eval_cond_assign(&n->is_working, 1, 0);
|
||||
break;
|
||||
}
|
||||
got_task = !ins_atomic_u32_eval_cond_assign(&n->is_working, 1, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: get dbg info
|
||||
RDI_Parsed *rdi = &di_rdi_parsed_nil;
|
||||
if(got_task && params.dbgi_key.path.size != 0)
|
||||
{
|
||||
rdi = di_rdi_from_key(di_scope, ¶ms.dbgi_key, max_U64);
|
||||
}
|
||||
|
||||
//- rjf: hash -> data
|
||||
String8 data = {0};
|
||||
if(got_task)
|
||||
{
|
||||
data = hs_data_from_hash(hs_scope, hash);
|
||||
}
|
||||
|
||||
//- rjf: data * arch * addr * dbg -> decode artifacts
|
||||
DASM_LineChunkList line_list = {0};
|
||||
String8List inst_strings = {0};
|
||||
if(got_task)
|
||||
{
|
||||
switch(params.arch)
|
||||
{
|
||||
default:{}break;
|
||||
|
||||
//- rjf: x86/x64 decoding
|
||||
case Arch_x64:
|
||||
case Arch_x86:
|
||||
{
|
||||
// rjf: disassemble
|
||||
RDI_SourceFile *last_file = &rdi_nil_element_union.source_file;
|
||||
RDI_Line *last_line = 0;
|
||||
for(U64 off = 0; off < data.size;)
|
||||
{
|
||||
// rjf: disassemble one instruction
|
||||
DASM_Inst inst = dasm_inst_from_code(scratch.arena, params.arch, params.vaddr+off, str8_skip(data, off), params.syntax);
|
||||
if(inst.size == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// rjf: push strings derived from voff -> line info
|
||||
if(params.style_flags & (DASM_StyleFlag_SourceFilesNames|DASM_StyleFlag_SourceLines))
|
||||
{
|
||||
if(rdi != &di_rdi_parsed_nil)
|
||||
{
|
||||
U64 voff = (params.vaddr+off) - params.base_vaddr;
|
||||
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);
|
||||
RDI_LineTable *line_table = rdi_element_from_name_idx(rdi, LineTables, unit->line_table_idx);
|
||||
RDI_ParsedLineTable unit_line_info = {0};
|
||||
rdi_parsed_from_line_table(rdi, line_table, &unit_line_info);
|
||||
U64 line_info_idx = rdi_line_info_idx_from_voff(&unit_line_info, voff);
|
||||
if(line_info_idx < unit_line_info.count)
|
||||
{
|
||||
RDI_Line *line = &unit_line_info.lines[line_info_idx];
|
||||
RDI_SourceFile *file = rdi_element_from_name_idx(rdi, SourceFiles, line->file_idx);
|
||||
String8 file_normalized_full_path = {0};
|
||||
file_normalized_full_path.str = rdi_string_from_idx(rdi, file->normal_full_path_string_idx, &file_normalized_full_path.size);
|
||||
if(file != last_file)
|
||||
{
|
||||
if(params.style_flags & DASM_StyleFlag_SourceFilesNames &&
|
||||
file->normal_full_path_string_idx != 0 && file_normalized_full_path.size != 0)
|
||||
{
|
||||
String8 inst_string = push_str8f(scratch.arena, "> %S", file_normalized_full_path);
|
||||
DASM_Line inst = {u32_from_u64_saturate(off), DASM_LineFlag_Decorative, 0, r1u64(inst_strings.total_size + inst_strings.node_count,
|
||||
inst_strings.total_size + inst_strings.node_count + inst_string.size)};
|
||||
dasm_line_chunk_list_push(scratch.arena, &line_list, 1024, &inst);
|
||||
str8_list_push(scratch.arena, &inst_strings, inst_string);
|
||||
}
|
||||
if(params.style_flags & DASM_StyleFlag_SourceFilesNames && file->normal_full_path_string_idx == 0)
|
||||
{
|
||||
String8 inst_string = str8_lit(">");
|
||||
DASM_Line inst = {u32_from_u64_saturate(off), DASM_LineFlag_Decorative, 0, r1u64(inst_strings.total_size + inst_strings.node_count,
|
||||
inst_strings.total_size + inst_strings.node_count + inst_string.size)};
|
||||
dasm_line_chunk_list_push(scratch.arena, &line_list, 1024, &inst);
|
||||
str8_list_push(scratch.arena, &inst_strings, inst_string);
|
||||
}
|
||||
last_file = file;
|
||||
}
|
||||
if(line && line != last_line && file->normal_full_path_string_idx != 0 &&
|
||||
params.style_flags & DASM_StyleFlag_SourceLines &&
|
||||
file_normalized_full_path.size != 0)
|
||||
{
|
||||
FileProperties props = os_properties_from_file_path(file_normalized_full_path);
|
||||
if(props.modified != 0)
|
||||
{
|
||||
// TODO(rjf): need redirection path - this may map to a different path on the local machine,
|
||||
// need frontend to communicate path remapping info to this layer
|
||||
U128 key = fs_key_from_path_range(file_normalized_full_path, r1u64(0, max_U64));
|
||||
TXT_LangKind lang_kind = txt_lang_kind_from_extension(file_normalized_full_path);
|
||||
U64 endt_us = max_U64;
|
||||
U128 hash = {0};
|
||||
TXT_TextInfo text_info = {0};
|
||||
for(;os_now_microseconds() <= endt_us;)
|
||||
{
|
||||
text_info = txt_text_info_from_key_lang(txt_scope, key, lang_kind, &hash);
|
||||
if(!u128_match(hash, u128_zero()))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(0 < line->line_num && line->line_num < text_info.lines_count)
|
||||
{
|
||||
String8 data = hs_data_from_hash(hs_scope, hash);
|
||||
String8 line_text = str8_skip_chop_whitespace(str8_substr(data, text_info.lines_ranges[line->line_num-1]));
|
||||
if(line_text.size != 0)
|
||||
{
|
||||
String8 inst_string = push_str8f(scratch.arena, "> %S", line_text);
|
||||
DASM_Line inst = {u32_from_u64_saturate(off), DASM_LineFlag_Decorative, 0, r1u64(inst_strings.total_size + inst_strings.node_count,
|
||||
inst_strings.total_size + inst_strings.node_count + inst_string.size)};
|
||||
dasm_line_chunk_list_push(scratch.arena, &line_list, 1024, &inst);
|
||||
str8_list_push(scratch.arena, &inst_strings, inst_string);
|
||||
}
|
||||
}
|
||||
}
|
||||
last_line = line;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: push line
|
||||
String8 addr_part = {0};
|
||||
if(params.style_flags & DASM_StyleFlag_Addresses)
|
||||
{
|
||||
addr_part = push_str8f(scratch.arena, "%s0x%016I64x ", rdi != &di_rdi_parsed_nil ? " " : "", params.vaddr+off);
|
||||
}
|
||||
String8 code_bytes_part = {0};
|
||||
if(params.style_flags & DASM_StyleFlag_CodeBytes)
|
||||
{
|
||||
String8List code_bytes_strings = {0};
|
||||
str8_list_push(scratch.arena, &code_bytes_strings, str8_lit("{"));
|
||||
for(U64 byte_idx = 0; byte_idx < inst.size || byte_idx < 16; byte_idx += 1)
|
||||
{
|
||||
if(byte_idx < inst.size)
|
||||
{
|
||||
str8_list_pushf(scratch.arena, &code_bytes_strings, "%02x%s ", (U32)data.str[off+byte_idx], byte_idx == inst.size-1 ? "}" : "");
|
||||
}
|
||||
else if(byte_idx < 8)
|
||||
{
|
||||
str8_list_push(scratch.arena, &code_bytes_strings, str8_lit(" "));
|
||||
}
|
||||
}
|
||||
str8_list_push(scratch.arena, &code_bytes_strings, str8_lit(" "));
|
||||
code_bytes_part = str8_list_join(scratch.arena, &code_bytes_strings, 0);
|
||||
}
|
||||
String8 symbol_part = {0};
|
||||
if(inst.jump_dest_vaddr != 0 && rdi != &di_rdi_parsed_nil && params.style_flags & DASM_StyleFlag_SymbolNames)
|
||||
{
|
||||
RDI_U32 scope_idx = rdi_vmap_idx_from_section_kind_voff(rdi, RDI_SectionKind_ScopeVMap, inst.jump_dest_vaddr-params.base_vaddr);
|
||||
if(scope_idx != 0)
|
||||
{
|
||||
RDI_Scope *scope = rdi_element_from_name_idx(rdi, Scopes, scope_idx);
|
||||
RDI_U32 procedure_idx = scope->proc_idx;
|
||||
RDI_Procedure *procedure = rdi_element_from_name_idx(rdi, Procedures, procedure_idx);
|
||||
String8 procedure_name = {0};
|
||||
procedure_name.str = rdi_string_from_idx(rdi, procedure->name_string_idx, &procedure_name.size);
|
||||
if(procedure_name.size != 0)
|
||||
{
|
||||
symbol_part = push_str8f(scratch.arena, " (%S)", procedure_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
String8 inst_string = push_str8f(scratch.arena, "%S%S%S%S", addr_part, code_bytes_part, inst.string, symbol_part);
|
||||
DASM_Line line = {u32_from_u64_saturate(off), 0, inst.jump_dest_vaddr, r1u64(inst_strings.total_size + inst_strings.node_count,
|
||||
inst_strings.total_size + inst_strings.node_count + inst_string.size)};
|
||||
dasm_line_chunk_list_push(scratch.arena, &line_list, 1024, &line);
|
||||
str8_list_push(scratch.arena, &inst_strings, inst_string);
|
||||
|
||||
// rjf: increment
|
||||
off += inst.size;
|
||||
}
|
||||
}break;
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: artifacts -> value bundle
|
||||
Arena *info_arena = 0;
|
||||
DASM_Info info = {0};
|
||||
if(got_task)
|
||||
{
|
||||
//- rjf: produce joined text
|
||||
Arena *text_arena = arena_alloc();
|
||||
StringJoin text_join = {0};
|
||||
text_join.sep = str8_lit("\n");
|
||||
String8 text = str8_list_join(text_arena, &inst_strings, &text_join);
|
||||
|
||||
//- rjf: produce unique key for this disassembly's text
|
||||
U128 text_key = {0};
|
||||
{
|
||||
U64 hash_data[] =
|
||||
{
|
||||
hash.u64[0],
|
||||
hash.u64[1],
|
||||
params.vaddr,
|
||||
(U64)params.arch,
|
||||
(U64)params.style_flags,
|
||||
(U64)params.syntax,
|
||||
(U64)rdi,
|
||||
0x4d534144,
|
||||
};
|
||||
text_key = hs_hash_from_data(str8((U8 *)hash_data, sizeof(hash_data)));
|
||||
}
|
||||
|
||||
//- rjf: submit text data to hash store
|
||||
U128 text_hash = hs_submit_data(text_key, &text_arena, text);
|
||||
|
||||
//- rjf: produce value bundle
|
||||
info_arena = arena_alloc();
|
||||
info.text_key = text_key;
|
||||
info.lines = dasm_line_array_from_chunk_list(info_arena, &line_list);
|
||||
}
|
||||
|
||||
//- rjf: commit results to cache
|
||||
if(got_task) OS_MutexScopeW(stripe->rw_mutex)
|
||||
{
|
||||
for(DASM_Node *n = slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(u128_match(n->hash, hash) && dasm_params_match(&n->params, ¶ms))
|
||||
{
|
||||
n->info_arena = info_arena;
|
||||
MemoryCopyStruct(&n->info, &info);
|
||||
if(rdi != &di_rdi_parsed_nil && params.style_flags & (DASM_StyleFlag_SourceLines|DASM_StyleFlag_SourceFilesNames))
|
||||
{
|
||||
n->change_gen = change_gen;
|
||||
}
|
||||
else
|
||||
{
|
||||
n->change_gen = 0;
|
||||
}
|
||||
ins_atomic_u32_eval_assign(&n->is_working, 0);
|
||||
ins_atomic_u64_inc_eval(&n->load_count);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
txt_scope_close(txt_scope);
|
||||
di_scope_close(di_scope);
|
||||
hs_scope_close(hs_scope);
|
||||
scratch_end(scratch);
|
||||
}
|
||||
|
||||
//- rjf: get dbg info
|
||||
RDI_Parsed *rdi = &di_rdi_parsed_nil;
|
||||
if(got_task && params.dbgi_key.path.size != 0)
|
||||
{
|
||||
rdi = di_rdi_from_key(di_scope, ¶ms.dbgi_key, max_U64);
|
||||
}
|
||||
|
||||
//- rjf: hash -> data
|
||||
String8 data = {0};
|
||||
if(got_task)
|
||||
{
|
||||
data = hs_data_from_hash(hs_scope, hash);
|
||||
}
|
||||
|
||||
//- rjf: data * arch * addr * dbg -> decode artifacts
|
||||
DASM_LineChunkList line_list = {0};
|
||||
String8List inst_strings = {0};
|
||||
if(got_task)
|
||||
{
|
||||
switch(params.arch)
|
||||
{
|
||||
default:{}break;
|
||||
|
||||
//- rjf: x86/x64 decoding
|
||||
case Arch_x64:
|
||||
case Arch_x86:
|
||||
{
|
||||
// rjf: disassemble
|
||||
RDI_SourceFile *last_file = &rdi_nil_element_union.source_file;
|
||||
RDI_Line *last_line = 0;
|
||||
for(U64 off = 0; off < data.size;)
|
||||
{
|
||||
// rjf: disassemble one instruction
|
||||
DASM_Inst inst = dasm_inst_from_code(scratch.arena, params.arch, params.vaddr+off, str8_skip(data, off), params.syntax);
|
||||
if(inst.size == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// rjf: push strings derived from voff -> line info
|
||||
if(params.style_flags & (DASM_StyleFlag_SourceFilesNames|DASM_StyleFlag_SourceLines))
|
||||
{
|
||||
if(rdi != &di_rdi_parsed_nil)
|
||||
{
|
||||
U64 voff = (params.vaddr+off) - params.base_vaddr;
|
||||
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);
|
||||
RDI_LineTable *line_table = rdi_element_from_name_idx(rdi, LineTables, unit->line_table_idx);
|
||||
RDI_ParsedLineTable unit_line_info = {0};
|
||||
rdi_parsed_from_line_table(rdi, line_table, &unit_line_info);
|
||||
U64 line_info_idx = rdi_line_info_idx_from_voff(&unit_line_info, voff);
|
||||
if(line_info_idx < unit_line_info.count)
|
||||
{
|
||||
RDI_Line *line = &unit_line_info.lines[line_info_idx];
|
||||
RDI_SourceFile *file = rdi_element_from_name_idx(rdi, SourceFiles, line->file_idx);
|
||||
String8 file_normalized_full_path = {0};
|
||||
file_normalized_full_path.str = rdi_string_from_idx(rdi, file->normal_full_path_string_idx, &file_normalized_full_path.size);
|
||||
if(file != last_file)
|
||||
{
|
||||
if(params.style_flags & DASM_StyleFlag_SourceFilesNames &&
|
||||
file->normal_full_path_string_idx != 0 && file_normalized_full_path.size != 0)
|
||||
{
|
||||
String8 inst_string = push_str8f(scratch.arena, "> %S", file_normalized_full_path);
|
||||
DASM_Line inst = {u32_from_u64_saturate(off), DASM_LineFlag_Decorative, 0, r1u64(inst_strings.total_size + inst_strings.node_count,
|
||||
inst_strings.total_size + inst_strings.node_count + inst_string.size)};
|
||||
dasm_line_chunk_list_push(scratch.arena, &line_list, 1024, &inst);
|
||||
str8_list_push(scratch.arena, &inst_strings, inst_string);
|
||||
}
|
||||
if(params.style_flags & DASM_StyleFlag_SourceFilesNames && file->normal_full_path_string_idx == 0)
|
||||
{
|
||||
String8 inst_string = str8_lit(">");
|
||||
DASM_Line inst = {u32_from_u64_saturate(off), DASM_LineFlag_Decorative, 0, r1u64(inst_strings.total_size + inst_strings.node_count,
|
||||
inst_strings.total_size + inst_strings.node_count + inst_string.size)};
|
||||
dasm_line_chunk_list_push(scratch.arena, &line_list, 1024, &inst);
|
||||
str8_list_push(scratch.arena, &inst_strings, inst_string);
|
||||
}
|
||||
last_file = file;
|
||||
}
|
||||
if(line && line != last_line && file->normal_full_path_string_idx != 0 &&
|
||||
params.style_flags & DASM_StyleFlag_SourceLines &&
|
||||
file_normalized_full_path.size != 0)
|
||||
{
|
||||
FileProperties props = os_properties_from_file_path(file_normalized_full_path);
|
||||
if(props.modified != 0)
|
||||
{
|
||||
// TODO(rjf): need redirection path - this may map to a different path on the local machine,
|
||||
// need frontend to communicate path remapping info to this layer
|
||||
U128 key = fs_key_from_path_range(file_normalized_full_path, r1u64(0, max_U64));
|
||||
TXT_LangKind lang_kind = txt_lang_kind_from_extension(file_normalized_full_path);
|
||||
U64 endt_us = max_U64;
|
||||
U128 hash = {0};
|
||||
TXT_TextInfo text_info = {0};
|
||||
for(;os_now_microseconds() <= endt_us;)
|
||||
{
|
||||
text_info = txt_text_info_from_key_lang(txt_scope, key, lang_kind, &hash);
|
||||
if(!u128_match(hash, u128_zero()))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(0 < line->line_num && line->line_num < text_info.lines_count)
|
||||
{
|
||||
String8 data = hs_data_from_hash(hs_scope, hash);
|
||||
String8 line_text = str8_skip_chop_whitespace(str8_substr(data, text_info.lines_ranges[line->line_num-1]));
|
||||
if(line_text.size != 0)
|
||||
{
|
||||
String8 inst_string = push_str8f(scratch.arena, "> %S", line_text);
|
||||
DASM_Line inst = {u32_from_u64_saturate(off), DASM_LineFlag_Decorative, 0, r1u64(inst_strings.total_size + inst_strings.node_count,
|
||||
inst_strings.total_size + inst_strings.node_count + inst_string.size)};
|
||||
dasm_line_chunk_list_push(scratch.arena, &line_list, 1024, &inst);
|
||||
str8_list_push(scratch.arena, &inst_strings, inst_string);
|
||||
}
|
||||
}
|
||||
}
|
||||
last_line = line;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: push line
|
||||
String8 addr_part = {0};
|
||||
if(params.style_flags & DASM_StyleFlag_Addresses)
|
||||
{
|
||||
addr_part = push_str8f(scratch.arena, "%s0x%016I64x ", rdi != &di_rdi_parsed_nil ? " " : "", params.vaddr+off);
|
||||
}
|
||||
String8 code_bytes_part = {0};
|
||||
if(params.style_flags & DASM_StyleFlag_CodeBytes)
|
||||
{
|
||||
String8List code_bytes_strings = {0};
|
||||
str8_list_push(scratch.arena, &code_bytes_strings, str8_lit("{"));
|
||||
for(U64 byte_idx = 0; byte_idx < inst.size || byte_idx < 16; byte_idx += 1)
|
||||
{
|
||||
if(byte_idx < inst.size)
|
||||
{
|
||||
str8_list_pushf(scratch.arena, &code_bytes_strings, "%02x%s ", (U32)data.str[off+byte_idx], byte_idx == inst.size-1 ? "}" : "");
|
||||
}
|
||||
else if(byte_idx < 8)
|
||||
{
|
||||
str8_list_push(scratch.arena, &code_bytes_strings, str8_lit(" "));
|
||||
}
|
||||
}
|
||||
str8_list_push(scratch.arena, &code_bytes_strings, str8_lit(" "));
|
||||
code_bytes_part = str8_list_join(scratch.arena, &code_bytes_strings, 0);
|
||||
}
|
||||
String8 symbol_part = {0};
|
||||
if(inst.jump_dest_vaddr != 0 && rdi != &di_rdi_parsed_nil && params.style_flags & DASM_StyleFlag_SymbolNames)
|
||||
{
|
||||
RDI_U32 scope_idx = rdi_vmap_idx_from_section_kind_voff(rdi, RDI_SectionKind_ScopeVMap, inst.jump_dest_vaddr-params.base_vaddr);
|
||||
if(scope_idx != 0)
|
||||
{
|
||||
RDI_Scope *scope = rdi_element_from_name_idx(rdi, Scopes, scope_idx);
|
||||
RDI_U32 procedure_idx = scope->proc_idx;
|
||||
RDI_Procedure *procedure = rdi_element_from_name_idx(rdi, Procedures, procedure_idx);
|
||||
String8 procedure_name = {0};
|
||||
procedure_name.str = rdi_string_from_idx(rdi, procedure->name_string_idx, &procedure_name.size);
|
||||
if(procedure_name.size != 0)
|
||||
{
|
||||
symbol_part = push_str8f(scratch.arena, " (%S)", procedure_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
String8 inst_string = push_str8f(scratch.arena, "%S%S%S%S", addr_part, code_bytes_part, inst.string, symbol_part);
|
||||
DASM_Line line = {u32_from_u64_saturate(off), 0, inst.jump_dest_vaddr, r1u64(inst_strings.total_size + inst_strings.node_count,
|
||||
inst_strings.total_size + inst_strings.node_count + inst_string.size)};
|
||||
dasm_line_chunk_list_push(scratch.arena, &line_list, 1024, &line);
|
||||
str8_list_push(scratch.arena, &inst_strings, inst_string);
|
||||
|
||||
// rjf: increment
|
||||
off += inst.size;
|
||||
}
|
||||
}break;
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: artifacts -> value bundle
|
||||
Arena *info_arena = 0;
|
||||
DASM_Info info = {0};
|
||||
if(got_task)
|
||||
{
|
||||
//- rjf: produce joined text
|
||||
Arena *text_arena = arena_alloc();
|
||||
StringJoin text_join = {0};
|
||||
text_join.sep = str8_lit("\n");
|
||||
String8 text = str8_list_join(text_arena, &inst_strings, &text_join);
|
||||
|
||||
//- rjf: produce unique key for this disassembly's text
|
||||
U128 text_key = {0};
|
||||
{
|
||||
U64 hash_data[] =
|
||||
{
|
||||
hash.u64[0],
|
||||
hash.u64[1],
|
||||
params.vaddr,
|
||||
(U64)params.arch,
|
||||
(U64)params.style_flags,
|
||||
(U64)params.syntax,
|
||||
(U64)rdi,
|
||||
0x4d534144,
|
||||
};
|
||||
text_key = hs_hash_from_data(str8((U8 *)hash_data, sizeof(hash_data)));
|
||||
}
|
||||
|
||||
//- rjf: submit text data to hash store
|
||||
U128 text_hash = hs_submit_data(text_key, &text_arena, text);
|
||||
|
||||
//- rjf: produce value bundle
|
||||
info_arena = arena_alloc();
|
||||
info.text_key = text_key;
|
||||
info.lines = dasm_line_array_from_chunk_list(info_arena, &line_list);
|
||||
}
|
||||
|
||||
//- rjf: commit results to cache
|
||||
if(got_task) OS_MutexScopeW(stripe->rw_mutex)
|
||||
{
|
||||
for(DASM_Node *n = slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(u128_match(n->hash, hash) && dasm_params_match(&n->params, ¶ms))
|
||||
{
|
||||
n->info_arena = info_arena;
|
||||
MemoryCopyStruct(&n->info, &info);
|
||||
if(rdi != &di_rdi_parsed_nil && params.style_flags & (DASM_StyleFlag_SourceLines|DASM_StyleFlag_SourceFilesNames))
|
||||
{
|
||||
n->change_gen = change_gen;
|
||||
}
|
||||
else
|
||||
{
|
||||
n->change_gen = 0;
|
||||
}
|
||||
ins_atomic_u32_eval_assign(&n->is_working, 0);
|
||||
ins_atomic_u64_inc_eval(&n->load_count);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
txt_scope_close(txt_scope);
|
||||
di_scope_close(di_scope);
|
||||
hs_scope_close(hs_scope);
|
||||
scratch_end(scratch);
|
||||
ProfEnd();
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
@@ -806,7 +786,7 @@ dasm_evictor_detector_thread__entry_point(void *p)
|
||||
{
|
||||
U64 change_gen = fs_change_gen();
|
||||
U64 check_time_us = os_now_microseconds();
|
||||
U64 check_time_user_clocks = dasm_user_clock_idx();
|
||||
U64 check_time_user_clocks = update_tick_idx();
|
||||
U64 evict_threshold_us = 10*1000000;
|
||||
U64 retry_threshold_us = 1*1000000;
|
||||
U64 evict_threshold_user_clocks = 10;
|
||||
@@ -863,6 +843,7 @@ dasm_evictor_detector_thread__entry_point(void *p)
|
||||
{
|
||||
if(dasm_u2p_enqueue_req(n->hash, &n->params, max_U64))
|
||||
{
|
||||
async_push_work(dasm_parse_work);
|
||||
n->last_time_requested_us = os_now_microseconds();
|
||||
n->last_user_clock_idx_requested = check_time_user_clocks;
|
||||
}
|
||||
|
||||
@@ -246,9 +246,6 @@ struct DASM_Shared
|
||||
{
|
||||
Arena *arena;
|
||||
|
||||
// rjf: user clock
|
||||
U64 user_clock_idx;
|
||||
|
||||
// rjf: cache
|
||||
U64 slots_count;
|
||||
U64 stripes_count;
|
||||
@@ -263,10 +260,6 @@ struct DASM_Shared
|
||||
OS_Handle u2p_ring_cv;
|
||||
OS_Handle u2p_ring_mutex;
|
||||
|
||||
// rjf: parse threads
|
||||
U64 parse_thread_count;
|
||||
OS_Handle *parse_threads;
|
||||
|
||||
// rjf: evictor/detector thread
|
||||
OS_Handle evictor_detector_thread;
|
||||
};
|
||||
@@ -305,12 +298,6 @@ internal U64 dasm_line_array_code_off_from_idx(DASM_LineArray *array, U64 idx);
|
||||
|
||||
internal void dasm_init(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: User Clock
|
||||
|
||||
internal void dasm_user_clock_tick(void);
|
||||
internal U64 dasm_user_clock_idx(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Scoped Access
|
||||
|
||||
@@ -329,7 +316,7 @@ internal DASM_Info dasm_info_from_key_params(DASM_Scope *scope, U128 key, DASM_P
|
||||
|
||||
internal B32 dasm_u2p_enqueue_req(U128 hash, DASM_Params *params, U64 endt_us);
|
||||
internal void dasm_u2p_dequeue_req(Arena *arena, U128 *hash_out, DASM_Params *params_out);
|
||||
internal void dasm_parse_thread__entry_point(void *p);
|
||||
ASYNC_WORK_DEF(dasm_parse_work);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Evictor/Detector Thread
|
||||
|
||||
@@ -107,7 +107,6 @@ D_ViewRuleTable:
|
||||
@table(name)
|
||||
D_DevToggleTable:
|
||||
{
|
||||
{telemetry_capture}
|
||||
{simulate_lag}
|
||||
{draw_ui_text_pos}
|
||||
{draw_ui_focus_debug}
|
||||
|
||||
@@ -942,6 +942,100 @@ d_lines_from_dbgi_key_voff(Arena *arena, DI_Key *dbgi_key, U64 voff)
|
||||
|
||||
// TODO(rjf): this depends on file path maps, needs to move
|
||||
|
||||
internal D_LineListArray
|
||||
d_lines_array_from_dbgi_key_file_path_line_range(Arena *arena, DI_Key dbgi_key, String8 file_path, Rng1S64 line_num_range)
|
||||
{
|
||||
D_LineListArray array = {0};
|
||||
{
|
||||
array.count = dim_1s64(line_num_range)+1;
|
||||
array.v = push_array(arena, D_LineList, array.count);
|
||||
di_key_list_push(arena, &array.dbgi_keys, &dbgi_key);
|
||||
}
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
U64 *lines_num_voffs = push_array(scratch.arena, U64, array.count);
|
||||
DI_Scope *scope = di_scope_open();
|
||||
String8List overrides = rd_possible_overrides_from_file_path(scratch.arena, file_path);
|
||||
for(String8Node *override_n = overrides.first;
|
||||
override_n != 0;
|
||||
override_n = override_n->next)
|
||||
{
|
||||
String8 file_path = override_n->string;
|
||||
String8 file_path_normalized = lower_from_str8(scratch.arena, file_path);
|
||||
|
||||
// rjf: binary -> rdi
|
||||
RDI_Parsed *rdi = di_rdi_from_key(scope, &dbgi_key, 0);
|
||||
|
||||
// rjf: file_path_normalized * rdi -> src_id
|
||||
B32 good_src_id = 0;
|
||||
U32 src_id = 0;
|
||||
if(rdi != &di_rdi_parsed_nil) ProfScope("file_path_normalized * rdi -> src_id")
|
||||
{
|
||||
RDI_NameMap *mapptr = rdi_element_from_name_idx(rdi, NameMaps, RDI_NameMapKind_NormalSourcePaths);
|
||||
RDI_ParsedNameMap map = {0};
|
||||
rdi_parsed_from_name_map(rdi, mapptr, &map);
|
||||
RDI_NameMapNode *node = rdi_name_map_lookup(rdi, &map, file_path_normalized.str, file_path_normalized.size);
|
||||
if(node != 0)
|
||||
{
|
||||
U32 id_count = 0;
|
||||
U32 *ids = rdi_matches_from_map_node(rdi, node, &id_count);
|
||||
if(id_count > 0)
|
||||
{
|
||||
good_src_id = 1;
|
||||
src_id = ids[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: good src-id -> look up line info for visible range
|
||||
if(good_src_id) ProfScope("good src-id -> look up line info for visible range")
|
||||
{
|
||||
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);
|
||||
RDI_ParsedSourceLineMap line_map = {0};
|
||||
rdi_parsed_from_source_line_map(rdi, src_line_map, &line_map);
|
||||
U64 line_idx = 0;
|
||||
for(S64 line_num = line_num_range.min;
|
||||
line_num <= line_num_range.max;
|
||||
line_num += 1, line_idx += 1)
|
||||
{
|
||||
D_LineList *list = &array.v[line_idx];
|
||||
U32 voff_count = 0;
|
||||
U64 *voffs = rdi_line_voffs_from_num(&line_map, u32_from_u64_saturate((U64)line_num), &voff_count);
|
||||
if(lines_num_voffs[line_idx] < 8) ProfScope("iterate voffs (%i)", voff_count) for(U64 idx = 0; idx < voff_count; idx += 1)
|
||||
{
|
||||
U64 base_voff = voffs[idx];
|
||||
U64 unit_idx = rdi_vmap_idx_from_section_kind_voff(rdi, RDI_SectionKind_UnitVMap, base_voff);
|
||||
RDI_Unit *unit = rdi_element_from_name_idx(rdi, Units, unit_idx);
|
||||
RDI_LineTable *line_table = rdi_element_from_name_idx(rdi, LineTables, unit->line_table_idx);
|
||||
RDI_ParsedLineTable unit_line_info = {0};
|
||||
rdi_parsed_from_line_table(rdi, line_table, &unit_line_info);
|
||||
U64 line_info_idx = rdi_line_info_idx_from_voff(&unit_line_info, base_voff);
|
||||
if(unit_line_info.voffs != 0)
|
||||
{
|
||||
Rng1U64 range = r1u64(base_voff, unit_line_info.voffs[line_info_idx+1]);
|
||||
S64 actual_line = (S64)unit_line_info.lines[line_info_idx].line_num;
|
||||
D_LineNode *n = push_array(arena, D_LineNode, 1);
|
||||
n->v.voff_range = range;
|
||||
n->v.pt.line = (S64)actual_line;
|
||||
n->v.pt.column = 1;
|
||||
n->v.dbgi_key = dbgi_key;
|
||||
SLLQueuePush(list->first, list->last, n);
|
||||
list->count += 1;
|
||||
lines_num_voffs[line_idx] += 1;
|
||||
if(lines_num_voffs[line_idx] >= 8)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
di_scope_close(scope);
|
||||
scratch_end(scratch);
|
||||
return array;
|
||||
}
|
||||
|
||||
internal D_LineListArray
|
||||
d_lines_array_from_file_path_line_range(Arena *arena, String8 file_path, Rng1S64 line_num_range)
|
||||
{
|
||||
@@ -1047,6 +1141,18 @@ d_lines_array_from_file_path_line_range(Arena *arena, String8 file_path, Rng1S64
|
||||
return array;
|
||||
}
|
||||
|
||||
internal D_LineList
|
||||
d_lines_from_dbgi_key_file_path_line_num(Arena *arena, DI_Key dbgi_key, String8 file_path, S64 line_num)
|
||||
{
|
||||
D_LineListArray array = d_lines_array_from_dbgi_key_file_path_line_range(arena, dbgi_key, file_path, r1s64(line_num, line_num+1));
|
||||
D_LineList list = {0};
|
||||
if(array.count != 0)
|
||||
{
|
||||
list = array.v[0];
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
internal D_LineList
|
||||
d_lines_from_file_path_line_num(Arena *arena, String8 file_path, S64 line_num)
|
||||
{
|
||||
@@ -1974,21 +2080,6 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: start/stop telemetry captures
|
||||
//
|
||||
ProfScope("start/stop telemetry captures")
|
||||
{
|
||||
if(!ProfIsCapturing() && DEV_telemetry_capture)
|
||||
{
|
||||
ProfBeginCapture("raddbg");
|
||||
}
|
||||
if(ProfIsCapturing() && !DEV_telemetry_capture)
|
||||
{
|
||||
ProfEndCapture();
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: process top-level commands
|
||||
//
|
||||
@@ -2083,6 +2174,7 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P
|
||||
msg->stdout_path = stdout_path;
|
||||
msg->stderr_path = stderr_path;
|
||||
msg->stdin_path = stdin_path;
|
||||
msg->debug_subprocesses = target->debug_subprocesses;
|
||||
msg->env_inherit = 1;
|
||||
MemoryCopyArray(msg->exception_code_filters, exception_code_filters);
|
||||
MemoryCopyStruct(&msg->meta_evals, meta_evals);
|
||||
@@ -2123,16 +2215,11 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P
|
||||
}break;
|
||||
case D_CmdKind_KillAll:
|
||||
{
|
||||
CTRL_EntityList processes = ctrl_entity_list_from_kind(d_state->ctrl_entity_store, CTRL_EntityKind_Process);
|
||||
for(CTRL_EntityNode *n = processes.first; n != 0; n = n->next)
|
||||
{
|
||||
CTRL_Msg *msg = ctrl_msg_list_push(scratch.arena, &ctrl_msgs);
|
||||
msg->kind = CTRL_MsgKind_Kill;
|
||||
msg->exit_code = 1;
|
||||
msg->entity = n->v->handle;
|
||||
MemoryCopyArray(msg->exception_code_filters, exception_code_filters);
|
||||
MemoryCopyStruct(&msg->meta_evals, meta_evals);
|
||||
}
|
||||
CTRL_Msg *msg = ctrl_msg_list_push(scratch.arena, &ctrl_msgs);
|
||||
msg->kind = CTRL_MsgKind_KillAll;
|
||||
msg->exit_code = 1;
|
||||
MemoryCopyArray(msg->exception_code_filters, exception_code_filters);
|
||||
MemoryCopyStruct(&msg->meta_evals, meta_evals);
|
||||
}break;
|
||||
case D_CmdKind_Detach:
|
||||
{
|
||||
@@ -2320,8 +2407,12 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P
|
||||
}break;
|
||||
case D_CmdKind_Restart:
|
||||
{
|
||||
d_cmd(D_CmdKind_KillAll);
|
||||
d_cmd(D_CmdKind_LaunchAndRun);
|
||||
CTRL_EntityList processes = ctrl_entity_list_from_kind(d_state->ctrl_entity_store, CTRL_EntityKind_Process);
|
||||
if(processes.count != 0)
|
||||
{
|
||||
d_cmd(D_CmdKind_KillAll);
|
||||
d_cmd(D_CmdKind_LaunchAndRun);
|
||||
}
|
||||
}break;
|
||||
case D_CmdKind_StepInto:
|
||||
case D_CmdKind_StepOver:
|
||||
|
||||
@@ -17,6 +17,7 @@ struct D_Target
|
||||
String8 stdout_path;
|
||||
String8 stderr_path;
|
||||
String8 stdin_path;
|
||||
B32 debug_subprocesses;
|
||||
String8List env;
|
||||
};
|
||||
|
||||
@@ -443,7 +444,10 @@ internal D_LineList d_lines_from_dbgi_key_voff(Arena *arena, DI_Key *dbgi_key, U
|
||||
|
||||
//- rjf: file:line -> line info
|
||||
// TODO(rjf): this depends on file path maps, needs to move
|
||||
// TODO(rjf): need to clean this up & dedup
|
||||
internal D_LineListArray d_lines_array_from_dbgi_key_file_path_line_range(Arena *arena, DI_Key dbgi_key, String8 file_path, Rng1S64 line_num_range);
|
||||
internal D_LineListArray d_lines_array_from_file_path_line_range(Arena *arena, String8 file_path, Rng1S64 line_num_range);
|
||||
internal D_LineList d_lines_from_dbgi_key_file_path_line_num(Arena *arena, DI_Key dbgi_key, String8 file_path, S64 line_num);
|
||||
internal D_LineList d_lines_from_file_path_line_num(Arena *arena, String8 file_path, S64 line_num);
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
@@ -71,7 +71,6 @@ D_ViewRuleKind_Geo3D,
|
||||
D_ViewRuleKind_COUNT,
|
||||
} D_ViewRuleKind;
|
||||
|
||||
global B32 DEV_telemetry_capture = 0;
|
||||
global B32 DEV_simulate_lag = 0;
|
||||
global B32 DEV_draw_ui_text_pos = 0;
|
||||
global B32 DEV_draw_ui_focus_debug = 0;
|
||||
@@ -83,7 +82,6 @@ global B32 DEV_scratch_mouse_draw = 0;
|
||||
global B32 DEV_updating_indicator = 0;
|
||||
struct {B32 *value_ptr; String8 name;} DEV_toggle_table[] =
|
||||
{
|
||||
{&DEV_telemetry_capture, str8_lit_comp("telemetry_capture")},
|
||||
{&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")},
|
||||
|
||||
+1199
-290
File diff suppressed because it is too large
Load Diff
+226
-9
@@ -72,7 +72,7 @@ struct DI_EventList
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cache Types
|
||||
//~ rjf: Debug Info Cache Types
|
||||
|
||||
typedef struct DI_StringChunkNode DI_StringChunkNode;
|
||||
struct DI_StringChunkNode
|
||||
@@ -92,7 +92,6 @@ struct DI_Node
|
||||
U64 ref_count;
|
||||
U64 touch_count;
|
||||
U64 is_working;
|
||||
U64 last_time_requested_us;
|
||||
|
||||
// rjf: key
|
||||
DI_Key key;
|
||||
@@ -126,6 +125,91 @@ struct DI_Stripe
|
||||
OS_Handle cv;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Search Cache Types
|
||||
|
||||
typedef struct DI_SearchItem DI_SearchItem;
|
||||
struct DI_SearchItem
|
||||
{
|
||||
U64 idx;
|
||||
U64 dbgi_idx;
|
||||
U64 missed_size;
|
||||
FuzzyMatchRangeList match_ranges;
|
||||
};
|
||||
|
||||
typedef struct DI_SearchItemChunk DI_SearchItemChunk;
|
||||
struct DI_SearchItemChunk
|
||||
{
|
||||
DI_SearchItemChunk *next;
|
||||
DI_SearchItem *v;
|
||||
U64 count;
|
||||
U64 cap;
|
||||
};
|
||||
|
||||
typedef struct DI_SearchItemChunkList DI_SearchItemChunkList;
|
||||
struct DI_SearchItemChunkList
|
||||
{
|
||||
DI_SearchItemChunk *first;
|
||||
DI_SearchItemChunk *last;
|
||||
U64 chunk_count;
|
||||
U64 total_count;
|
||||
};
|
||||
|
||||
typedef struct DI_SearchItemArray DI_SearchItemArray;
|
||||
struct DI_SearchItemArray
|
||||
{
|
||||
DI_SearchItem *v;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
typedef struct DI_SearchParams DI_SearchParams;
|
||||
struct DI_SearchParams
|
||||
{
|
||||
RDI_SectionKind target;
|
||||
DI_KeyArray dbgi_keys;
|
||||
};
|
||||
|
||||
typedef struct DI_SearchBucket DI_SearchBucket;
|
||||
struct DI_SearchBucket
|
||||
{
|
||||
Arena *arena;
|
||||
String8 query;
|
||||
U64 params_hash;
|
||||
DI_SearchParams params;
|
||||
};
|
||||
|
||||
typedef struct DI_SearchNode DI_SearchNode;
|
||||
struct DI_SearchNode
|
||||
{
|
||||
DI_SearchNode *next;
|
||||
DI_SearchNode *prev;
|
||||
U128 key;
|
||||
U64 scope_refcount;
|
||||
U64 work_refcount;
|
||||
U64 last_update_tick_idx;
|
||||
U64 bucket_read_gen;
|
||||
U64 bucket_write_gen;
|
||||
U64 bucket_items_gen;
|
||||
DI_SearchBucket buckets[6];
|
||||
DI_SearchItemArray items;
|
||||
};
|
||||
|
||||
typedef struct DI_SearchSlot DI_SearchSlot;
|
||||
struct DI_SearchSlot
|
||||
{
|
||||
DI_SearchNode *first;
|
||||
DI_SearchNode *last;
|
||||
};
|
||||
|
||||
typedef struct DI_SearchStripe DI_SearchStripe;
|
||||
struct DI_SearchStripe
|
||||
{
|
||||
Arena *arena;
|
||||
DI_SearchNode *free_node;
|
||||
OS_Handle rw_mutex;
|
||||
OS_Handle cv;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Scoped Access Types
|
||||
|
||||
@@ -134,6 +218,7 @@ struct DI_Touch
|
||||
{
|
||||
DI_Touch *next;
|
||||
DI_Node *node;
|
||||
DI_SearchNode *search_node;
|
||||
};
|
||||
|
||||
typedef struct DI_Scope DI_Scope;
|
||||
@@ -152,6 +237,98 @@ struct DI_TCTX
|
||||
DI_Touch *free_touch;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Search Thread State Types
|
||||
|
||||
typedef struct DI_SearchThread DI_SearchThread;
|
||||
struct DI_SearchThread
|
||||
{
|
||||
OS_Handle thread;
|
||||
OS_Handle ring_mutex;
|
||||
OS_Handle ring_cv;
|
||||
U64 ring_size;
|
||||
U8 *ring_base;
|
||||
U64 ring_write_pos;
|
||||
U64 ring_read_pos;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Match Cache State Types
|
||||
|
||||
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_MatchNameNode DI_MatchNameNode;
|
||||
struct DI_MatchNameNode
|
||||
{
|
||||
// rjf: synchronously written by usage code
|
||||
DI_MatchNameNode *next;
|
||||
DI_MatchNameNode *prev;
|
||||
DI_MatchNameNode *lru_next;
|
||||
DI_MatchNameNode *lru_prev;
|
||||
U64 alloc_gen;
|
||||
U64 first_gen_touched;
|
||||
U64 last_gen_touched;
|
||||
U64 req_params_hash;
|
||||
U64 req_count;
|
||||
String8 name;
|
||||
U64 hash;
|
||||
|
||||
// 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;
|
||||
};
|
||||
|
||||
typedef struct DI_MatchNameSlot DI_MatchNameSlot;
|
||||
struct DI_MatchNameSlot
|
||||
{
|
||||
DI_MatchNameNode *first;
|
||||
DI_MatchNameNode *last;
|
||||
};
|
||||
|
||||
typedef struct DI_MatchStore DI_MatchStore;
|
||||
struct DI_MatchStore
|
||||
{
|
||||
Arena *arena;
|
||||
U64 gen;
|
||||
Arena *gen_arenas[2];
|
||||
|
||||
// rjf: parameters
|
||||
Arena *params_arena;
|
||||
OS_Handle params_rw_mutex;
|
||||
U64 params_hash;
|
||||
DI_KeyArray params_keys;
|
||||
|
||||
// rjf: match cache
|
||||
U64 match_name_slots_count;
|
||||
DI_MatchNameSlot *match_name_slots;
|
||||
DI_MatchNameNode *first_free_match_name;
|
||||
DI_Match *first_free_match;
|
||||
DI_MatchNameNode *first_lru_match_name;
|
||||
DI_MatchNameNode *last_lru_match_name;
|
||||
U64 active_match_name_nodes_count;
|
||||
OS_Handle match_rw_mutex;
|
||||
OS_Handle match_cv;
|
||||
|
||||
// rjf: user -> match work ring buffer
|
||||
OS_Handle u2m_ring_cv;
|
||||
OS_Handle u2m_ring_mutex;
|
||||
U64 u2m_ring_size;
|
||||
U8 *u2m_ring_base;
|
||||
U64 u2m_ring_write_pos;
|
||||
U64 u2m_ring_read_pos;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Shared State Types
|
||||
|
||||
@@ -160,12 +337,18 @@ struct DI_Shared
|
||||
{
|
||||
Arena *arena;
|
||||
|
||||
// rjf: node cache
|
||||
// rjf: debug info cache
|
||||
U64 slots_count;
|
||||
DI_Slot *slots;
|
||||
U64 stripes_count;
|
||||
DI_Stripe *stripes;
|
||||
|
||||
// rjf: search cache
|
||||
U64 search_slots_count;
|
||||
DI_SearchSlot *search_slots;
|
||||
U64 search_stripes_count;
|
||||
DI_SearchStripe *search_stripes;
|
||||
|
||||
// rjf: user -> parse ring
|
||||
OS_Handle u2p_ring_mutex;
|
||||
OS_Handle u2p_ring_cv;
|
||||
@@ -182,9 +365,10 @@ struct DI_Shared
|
||||
U64 p2u_ring_write_pos;
|
||||
U64 p2u_ring_read_pos;
|
||||
|
||||
// rjf: threads
|
||||
U64 parse_thread_count;
|
||||
OS_Handle *parse_threads;
|
||||
// rjf: search threads
|
||||
U64 search_threads_count;
|
||||
DI_SearchThread *search_threads;
|
||||
OS_Handle search_evictor_thread;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
@@ -197,6 +381,7 @@ global RDI_Parsed di_rdi_parsed_nil = {0};
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Helpers
|
||||
|
||||
internal U64 di_hash_from_seed_string(U64 seed, String8 string, StringMatchFlags match_flags);
|
||||
internal U64 di_hash_from_string(String8 string, StringMatchFlags match_flags);
|
||||
internal U64 di_hash_from_key(DI_Key *k);
|
||||
internal DI_Key di_key_zero(void);
|
||||
@@ -205,6 +390,12 @@ internal DI_Key di_key_copy(Arena *arena, DI_Key *src);
|
||||
internal DI_Key di_normalized_key_from_key(Arena *arena, DI_Key *src);
|
||||
internal void di_key_list_push(Arena *arena, DI_KeyList *list, DI_Key *key);
|
||||
internal DI_KeyArray di_key_array_from_list(Arena *arena, DI_KeyList *list);
|
||||
internal DI_KeyArray di_key_array_copy(Arena *arena, DI_KeyArray *src);
|
||||
internal DI_SearchParams di_search_params_copy(Arena *arena, DI_SearchParams *src);
|
||||
internal U64 di_hash_from_search_params(DI_SearchParams *params);
|
||||
internal void di_search_item_chunk_list_concat_in_place(DI_SearchItemChunkList *dst, DI_SearchItemChunkList *to_push);
|
||||
internal U64 di_search_item_num_from_array_element_idx__linear_search(DI_SearchItemArray *array, U64 element_idx);
|
||||
internal String8 di_search_item_string_from_rdi_target_element_idx(RDI_Parsed *rdi, RDI_SectionKind target, U64 element_idx);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Main Layer Initialization
|
||||
@@ -217,6 +408,7 @@ internal void di_init(void);
|
||||
internal DI_Scope *di_scope_open(void);
|
||||
internal void di_scope_close(DI_Scope *scope);
|
||||
internal void di_scope_touch_node__stripe_mutex_r_guarded(DI_Scope *scope, DI_Node *node);
|
||||
internal void di_scope_touch_search_node__stripe_mutex_r_guarded(DI_Scope *scope, DI_SearchNode *node);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Per-Slot Functions
|
||||
@@ -237,12 +429,17 @@ internal void di_open(DI_Key *key);
|
||||
internal void di_close(DI_Key *key);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cache Lookups
|
||||
//~ rjf: Debug Info Cache Lookups
|
||||
|
||||
internal RDI_Parsed *di_rdi_from_key(DI_Scope *scope, DI_Key *key, U64 endt_us);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Parse Threads
|
||||
//~ rjf: Search Cache Lookups
|
||||
|
||||
internal DI_SearchItemArray di_search_items_from_key_params_query(DI_Scope *scope, U128 key, DI_SearchParams *params, String8 query, U64 endt_us, B32 *stale_out);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Asynchronous Parse Work
|
||||
|
||||
internal B32 di_u2p_enqueue_key(DI_Key *key, U64 endt_us);
|
||||
internal void di_u2p_dequeue_key(Arena *arena, DI_Key *out_key);
|
||||
@@ -250,6 +447,26 @@ internal void di_u2p_dequeue_key(Arena *arena, DI_Key *out_key);
|
||||
internal void di_p2u_push_event(DI_Event *event);
|
||||
internal DI_EventList di_p2u_pop_events(Arena *arena, U64 endt_us);
|
||||
|
||||
internal void di_parse_thread__entry_point(void *p);
|
||||
ASYNC_WORK_DEF(di_parse_work);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Search Threads
|
||||
|
||||
internal B32 di_u2s_enqueue_req(U128 key, U64 endt_us);
|
||||
internal U128 di_u2s_dequeue_req(U64 thread_idx);
|
||||
|
||||
ASYNC_WORK_DEF(di_search_work);
|
||||
internal int di_qsort_compare_search_items(DI_SearchItem *a, DI_SearchItem *b);
|
||||
internal void di_search_thread__entry_point(void *p);
|
||||
|
||||
internal void di_search_evictor_thread__entry_point(void *p);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Match Store
|
||||
|
||||
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);
|
||||
ASYNC_WORK_DEF(di_match_work);
|
||||
|
||||
#endif // DBGI_H
|
||||
|
||||
@@ -1217,6 +1217,8 @@ dmn_ctrl_launch(DMN_CtrlCtx *ctx, OS_ProcessLaunchParams *params)
|
||||
{
|
||||
String8List args = {0};
|
||||
String8 exe_path = params->cmd_line.first->string;
|
||||
String8List exe_path_parts = str8_split_path(scratch.arena, exe_path);
|
||||
exe_path = str8_list_join(scratch.arena, &exe_path_parts, &(StringJoin){.sep = str8_lit("\\")});
|
||||
str8_list_pushf(scratch.arena, &args, "\"%S\"", exe_path);
|
||||
for(String8Node *n = params->cmd_line.first->next; n != 0; n = n->next)
|
||||
{
|
||||
@@ -1256,7 +1258,15 @@ dmn_ctrl_launch(DMN_CtrlCtx *ctx, OS_ProcessLaunchParams *params)
|
||||
String16 env16 = str16_from_8(scratch.arena, env);
|
||||
|
||||
//- rjf: launch
|
||||
DWORD creation_flags = CREATE_UNICODE_ENVIRONMENT|DEBUG_PROCESS;
|
||||
DWORD creation_flags = CREATE_UNICODE_ENVIRONMENT;
|
||||
if(params->debug_subprocesses)
|
||||
{
|
||||
creation_flags |= DEBUG_PROCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
creation_flags |= DEBUG_ONLY_THIS_PROCESS;
|
||||
}
|
||||
BOOL inherit_handles = 0;
|
||||
STARTUPINFOW startup_info = {sizeof(startup_info)};
|
||||
if(!os_handle_match(params->stdout_file, os_handle_zero()))
|
||||
|
||||
@@ -609,6 +609,7 @@ dr_truncated_fancy_run_fuzzy_matches(Vec2F32 p, DR_FancyRunList *list, F32 max_x
|
||||
internal void
|
||||
dr_text_run(Vec2F32 p, Vec4F32 color, FNT_Run run)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
F32 advance = 0;
|
||||
FNT_Piece *piece_first = run.pieces.v;
|
||||
FNT_Piece *piece_opl = piece_first + run.pieces.count;
|
||||
@@ -629,6 +630,7 @@ dr_text_run(Vec2F32 p, Vec4F32 color, FNT_Run run)
|
||||
}
|
||||
advance += piece->advance;
|
||||
}
|
||||
ProfEnd();
|
||||
}
|
||||
|
||||
internal void
|
||||
|
||||
+1
-1
@@ -132,7 +132,7 @@ internal DR_Bucket *dr_bucket_make(void);
|
||||
internal void dr_push_bucket(DR_Bucket *bucket);
|
||||
internal void dr_pop_bucket(void);
|
||||
internal DR_Bucket *dr_top_bucket(void);
|
||||
#define D_BucketScope(b) DeferLoop(dr_push_bucket(b), dr_pop_bucket())
|
||||
#define DR_BucketScope(b) DeferLoop(dr_push_bucket(b), dr_pop_bucket())
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Bucket Stacks
|
||||
|
||||
@@ -90,6 +90,7 @@ E_ExprKindTable:
|
||||
{ Typeof UnaryPrefix 1 "typeof" "typeof" "(" ")"}
|
||||
{ ByteSwap UnaryPrefix 1 "bswap" "bswap" "(" ")"}
|
||||
|
||||
{ Pos UnaryPrefix 2 "+" "+" "" "" }
|
||||
{ Neg UnaryPrefix 2 "-" "-" "" "" }
|
||||
{ LogNot UnaryPrefix 2 "!" "!" "" "" }
|
||||
{ BitNot UnaryPrefix 2 "~" "~" "" "" }
|
||||
|
||||
@@ -170,7 +170,7 @@ e_value_eval_from_eval(E_Eval eval)
|
||||
U64 valid_bits_mask = 0;
|
||||
for(U64 idx = 0; idx < type->count; idx += 1)
|
||||
{
|
||||
valid_bits_mask |= (1<<idx);
|
||||
valid_bits_mask |= (1ull<<idx);
|
||||
}
|
||||
eval.value.u64 = eval.value.u64 >> type->off;
|
||||
eval.value.u64 = eval.value.u64 & valid_bits_mask;
|
||||
|
||||
@@ -846,6 +846,10 @@ e_irtree_and_type_from_expr(Arena *arena, E_Expr *expr)
|
||||
}break;
|
||||
|
||||
//- rjf: unary operations
|
||||
case E_ExprKind_Pos:
|
||||
{
|
||||
result = e_irtree_and_type_from_expr(arena, expr->first);
|
||||
}break;
|
||||
case E_ExprKind_Neg:
|
||||
case E_ExprKind_LogNot:
|
||||
case E_ExprKind_BitNot:
|
||||
|
||||
+19
-10
@@ -389,6 +389,7 @@ e_token_array_from_text(Arena *arena, String8 text)
|
||||
E_TokenKind active_token_kind = E_TokenKind_Null;
|
||||
B32 active_token_kind_started_with_tick = 0;
|
||||
B32 escaped = 0;
|
||||
B32 exp = 0;
|
||||
for(U64 idx = 0, advance = 0; idx <= text.size; idx += advance)
|
||||
{
|
||||
U8 byte = (idx+0 < text.size) ? text.str[idx+0] : 0;
|
||||
@@ -486,11 +487,17 @@ e_token_array_from_text(Arena *arena, String8 text)
|
||||
}break;
|
||||
case E_TokenKind_Numeric:
|
||||
{
|
||||
if(!char_is_alpha(byte) && !char_is_digit(byte, 10) && byte != '.' && byte != ':')
|
||||
if(exp && (byte == '+' || byte == '-')){}
|
||||
else if(!char_is_alpha(byte) && !char_is_digit(byte, 10) && byte != '.' && byte != ':')
|
||||
{
|
||||
advance = 0;
|
||||
token_formed = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
exp = 0;
|
||||
exp = (byte == 'e');
|
||||
}
|
||||
}break;
|
||||
case E_TokenKind_StringLiteral:
|
||||
{
|
||||
@@ -1357,7 +1364,7 @@ e_parse_expr_from_text_tokens__prec(Arena *arena, String8 text, E_TokenArray *to
|
||||
}
|
||||
|
||||
//- rjf: try members
|
||||
if(mapped_identifier == 0 && (resolution_qualifier.size == 0 || str8_match(resolution_qualifier, str8_lit("member"), 0)))
|
||||
if(mapped_identifier == 0 && (resolution_qualifier.size == 0 || str8_match(resolution_qualifier, str8_lit("member"), 0))) ProfScope("try to map name as member")
|
||||
{
|
||||
U64 data_member_num = e_num_from_string(e_parse_ctx->member_map, token_string);
|
||||
if(data_member_num != 0)
|
||||
@@ -1368,7 +1375,7 @@ e_parse_expr_from_text_tokens__prec(Arena *arena, String8 text, E_TokenArray *to
|
||||
}
|
||||
|
||||
//- rjf: try locals
|
||||
if(mapped_identifier == 0 && (resolution_qualifier.size == 0 || str8_match(resolution_qualifier, str8_lit("local"), 0)))
|
||||
if(mapped_identifier == 0 && (resolution_qualifier.size == 0 || str8_match(resolution_qualifier, str8_lit("local"), 0))) ProfScope("try to map name as local")
|
||||
{
|
||||
E_Module *module = e_parse_ctx->primary_module;
|
||||
RDI_Parsed *rdi = module->rdi;
|
||||
@@ -1432,7 +1439,7 @@ e_parse_expr_from_text_tokens__prec(Arena *arena, String8 text, E_TokenArray *to
|
||||
}
|
||||
|
||||
//- rjf: try registers
|
||||
if(mapped_identifier == 0 && (resolution_qualifier.size == 0 || str8_match(resolution_qualifier, str8_lit("reg"), 0)))
|
||||
if(mapped_identifier == 0 && (resolution_qualifier.size == 0 || str8_match(resolution_qualifier, str8_lit("reg"), 0))) ProfScope("try to map name as register")
|
||||
{
|
||||
U64 reg_num = e_num_from_string(e_parse_ctx->regs_map, token_string);
|
||||
if(reg_num != 0)
|
||||
@@ -1446,7 +1453,7 @@ e_parse_expr_from_text_tokens__prec(Arena *arena, String8 text, E_TokenArray *to
|
||||
}
|
||||
|
||||
//- rjf: try register aliases
|
||||
if(mapped_identifier == 0 && (resolution_qualifier.size == 0 || str8_match(resolution_qualifier, str8_lit("reg"), 0)))
|
||||
if(mapped_identifier == 0 && (resolution_qualifier.size == 0 || str8_match(resolution_qualifier, str8_lit("reg"), 0))) ProfScope("try to map name as register alias")
|
||||
{
|
||||
U64 alias_num = e_num_from_string(e_parse_ctx->reg_alias_map, token_string);
|
||||
if(alias_num != 0)
|
||||
@@ -1460,7 +1467,7 @@ e_parse_expr_from_text_tokens__prec(Arena *arena, String8 text, E_TokenArray *to
|
||||
}
|
||||
|
||||
//- rjf: try global variables
|
||||
if(mapped_identifier == 0 && (resolution_qualifier.size == 0 || str8_match(resolution_qualifier, str8_lit("global"), 0)))
|
||||
if(mapped_identifier == 0 && (resolution_qualifier.size == 0 || str8_match(resolution_qualifier, str8_lit("global"), 0))) ProfScope("try to map name as global variable")
|
||||
{
|
||||
for(U64 module_idx = 0; module_idx < e_parse_ctx->modules_count; module_idx += 1)
|
||||
{
|
||||
@@ -1504,7 +1511,7 @@ e_parse_expr_from_text_tokens__prec(Arena *arena, String8 text, E_TokenArray *to
|
||||
}
|
||||
|
||||
//- rjf: try thread variables
|
||||
if(mapped_identifier == 0 && (resolution_qualifier.size == 0 || str8_match(resolution_qualifier, str8_lit("thread_variable"), 0)))
|
||||
if(mapped_identifier == 0 && (resolution_qualifier.size == 0 || str8_match(resolution_qualifier, str8_lit("thread_variable"), 0))) ProfScope("try to map name as thread variable")
|
||||
{
|
||||
for(U64 module_idx = 0; module_idx < e_parse_ctx->modules_count; module_idx += 1)
|
||||
{
|
||||
@@ -1544,7 +1551,7 @@ e_parse_expr_from_text_tokens__prec(Arena *arena, String8 text, E_TokenArray *to
|
||||
}
|
||||
|
||||
//- rjf: try procedures
|
||||
if(mapped_identifier == 0 && (resolution_qualifier.size == 0 || str8_match(resolution_qualifier, str8_lit("procedure"), 0)))
|
||||
if(mapped_identifier == 0 && (resolution_qualifier.size == 0 || str8_match(resolution_qualifier, str8_lit("procedure"), 0))) ProfScope("try to map name as procedure")
|
||||
{
|
||||
for(U64 module_idx = 0; module_idx < e_parse_ctx->modules_count; module_idx += 1)
|
||||
{
|
||||
@@ -1586,7 +1593,7 @@ e_parse_expr_from_text_tokens__prec(Arena *arena, String8 text, E_TokenArray *to
|
||||
}
|
||||
|
||||
//- rjf: try types
|
||||
if(mapped_identifier == 0 && (resolution_qualifier.size == 0 || str8_match(resolution_qualifier, str8_lit("type"), 0)))
|
||||
if(mapped_identifier == 0 && (resolution_qualifier.size == 0 || str8_match(resolution_qualifier, str8_lit("type"), 0))) ProfScope("try to map name as type")
|
||||
{
|
||||
type_key = e_leaf_type_from_name(token_string);
|
||||
if(!e_type_key_match(e_type_key_zero(), type_key))
|
||||
@@ -1615,7 +1622,7 @@ e_parse_expr_from_text_tokens__prec(Arena *arena, String8 text, E_TokenArray *to
|
||||
}
|
||||
|
||||
//- rjf: attach on map
|
||||
if(mapped_identifier != 0)
|
||||
if(mapped_identifier != 0) ProfScope("attach on map")
|
||||
{
|
||||
it += 1;
|
||||
|
||||
@@ -2106,7 +2113,9 @@ e_parse_expr_from_text_tokens__prec(Arena *arena, String8 text, E_TokenArray *to
|
||||
internal E_Parse
|
||||
e_parse_expr_from_text_tokens(Arena *arena, String8 text, E_TokenArray *tokens)
|
||||
{
|
||||
ProfBegin("parse '%.*s'", str8_varg(text));
|
||||
E_Parse parse = e_parse_expr_from_text_tokens__prec(arena, text, tokens, e_max_precedence);
|
||||
ProfEnd();
|
||||
return parse;
|
||||
}
|
||||
|
||||
|
||||
+42
-17
@@ -403,6 +403,8 @@ e_type_key_cons_(E_ConsTypeParams *params)
|
||||
{
|
||||
node->params.members[idx].name = push_str8_copy(e_type_state->arena, node->params.members[idx].name);
|
||||
node->params.members[idx].inheritance_key_chain = e_type_key_list_copy(e_type_state->arena, &node->params.members[idx].inheritance_key_chain);
|
||||
U64 opl_off = (node->params.members[idx].off + e_type_byte_size_from_key(node->params.members[idx].type_key));
|
||||
node->byte_size = Max(node->byte_size, opl_off);
|
||||
}
|
||||
}
|
||||
else if(params->enum_vals != 0)
|
||||
@@ -413,6 +415,23 @@ e_type_key_cons_(E_ConsTypeParams *params)
|
||||
{
|
||||
node->params.enum_vals[idx].name = push_str8_copy(e_type_state->arena, node->params.enum_vals[idx].name);
|
||||
}
|
||||
node->byte_size = e_type_byte_size_from_key(node->params.direct_key);
|
||||
}
|
||||
else switch(params->kind)
|
||||
{
|
||||
default:
|
||||
{
|
||||
node->byte_size = e_type_byte_size_from_key(node->params.direct_key);
|
||||
}break;
|
||||
case E_TypeKind_Ptr:
|
||||
{
|
||||
node->byte_size = bit_size_from_arch(node->params.arch)/8;
|
||||
}break;
|
||||
case E_TypeKind_Array:
|
||||
{
|
||||
U64 ptee_size = e_type_byte_size_from_key(node->params.direct_key);
|
||||
node->byte_size = ptee_size * node->params.count;
|
||||
}break;
|
||||
}
|
||||
result = key;
|
||||
}
|
||||
@@ -604,21 +623,9 @@ e_type_from_key(Arena *arena, E_TypeKey key)
|
||||
type->name = push_str8_copy(arena, node->params.name);
|
||||
type->direct_type_key = node->params.direct_key;
|
||||
type->count = node->params.count;
|
||||
type->byte_size = node->byte_size;
|
||||
switch(type->kind)
|
||||
{
|
||||
default:
|
||||
{
|
||||
type->byte_size = e_type_byte_size_from_key(type->direct_type_key);
|
||||
}break;
|
||||
case E_TypeKind_Ptr:
|
||||
{
|
||||
type->byte_size = bit_size_from_arch(node->params.arch)/8;
|
||||
}break;
|
||||
case E_TypeKind_Array:
|
||||
{
|
||||
U64 ptee_size = e_type_byte_size_from_key(node->params.direct_key);
|
||||
type->byte_size = ptee_size * type->count;
|
||||
}break;
|
||||
case E_TypeKind_Struct:
|
||||
case E_TypeKind_Union:
|
||||
case E_TypeKind_Class:
|
||||
@@ -1123,6 +1130,7 @@ e_type_from_key(Arena *arena, E_TypeKey key)
|
||||
internal U64
|
||||
e_type_byte_size_from_key(E_TypeKey key)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
U64 result = 0;
|
||||
switch(key.kind)
|
||||
{
|
||||
@@ -1133,14 +1141,31 @@ e_type_byte_size_from_key(E_TypeKey key)
|
||||
result = e_kind_basic_byte_size_table[kind];
|
||||
}break;
|
||||
case E_TypeKeyKind_Ext:
|
||||
{
|
||||
U64 type_node_idx = key.u32[1];
|
||||
U32 rdi_idx = key.u32[2];
|
||||
RDI_Parsed *rdi = e_type_state->ctx->modules[rdi_idx].rdi;
|
||||
RDI_TypeNode *rdi_type = rdi_element_from_name_idx(rdi, TypeNodes, type_node_idx);
|
||||
result = rdi_type->byte_size;
|
||||
}break;
|
||||
case E_TypeKeyKind_Cons:
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
E_Type *type = e_type_from_key(scratch.arena, key);
|
||||
result = type->byte_size;
|
||||
scratch_end(scratch);
|
||||
U64 key_hash = e_hash_from_string(5381, str8_struct(&key));
|
||||
U64 key_slot_idx = key_hash%e_type_state->cons_key_slots_count;
|
||||
E_ConsTypeSlot *key_slot = &e_type_state->cons_key_slots[key_slot_idx];
|
||||
for(E_ConsTypeNode *node = key_slot->first;
|
||||
node != 0;
|
||||
node = node->key_next)
|
||||
{
|
||||
if(e_type_key_match(node->key, key))
|
||||
{
|
||||
result = node->byte_size;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}break;
|
||||
}
|
||||
ProfEnd();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -162,6 +162,7 @@ struct E_ConsTypeNode
|
||||
E_ConsTypeNode *content_next;
|
||||
E_TypeKey key;
|
||||
E_ConsTypeParams params;
|
||||
U64 byte_size;
|
||||
};
|
||||
|
||||
typedef struct E_ConsTypeSlot E_ConsTypeSlot;
|
||||
|
||||
@@ -14,7 +14,7 @@ str8_lit_comp("CharLiteral"),
|
||||
str8_lit_comp("Symbol"),
|
||||
};
|
||||
|
||||
String8 e_expr_kind_strings[47] =
|
||||
String8 e_expr_kind_strings[48] =
|
||||
{
|
||||
str8_lit_comp("Nil"),
|
||||
str8_lit_comp("Ref"),
|
||||
@@ -26,6 +26,7 @@ str8_lit_comp("Cast"),
|
||||
str8_lit_comp("Sizeof"),
|
||||
str8_lit_comp("Typeof"),
|
||||
str8_lit_comp("ByteSwap"),
|
||||
str8_lit_comp("Pos"),
|
||||
str8_lit_comp("Neg"),
|
||||
str8_lit_comp("LogNot"),
|
||||
str8_lit_comp("BitNot"),
|
||||
@@ -80,7 +81,7 @@ str8_lit_comp("Insufficient evaluation machine stack space."),
|
||||
str8_lit_comp("Malformed bytecode."),
|
||||
};
|
||||
|
||||
E_OpInfo e_expr_kind_op_info_table[47] =
|
||||
E_OpInfo e_expr_kind_op_info_table[48] =
|
||||
{
|
||||
{ E_OpKind_Null, 0, str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("") },
|
||||
{ E_OpKind_Null, 0, str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("") },
|
||||
@@ -92,6 +93,7 @@ E_OpInfo e_expr_kind_op_info_table[47] =
|
||||
{ E_OpKind_UnaryPrefix, 1, str8_lit_comp("sizeof"), str8_lit_comp("("), str8_lit_comp(")") },
|
||||
{ E_OpKind_UnaryPrefix, 1, str8_lit_comp("typeof"), str8_lit_comp("("), str8_lit_comp(")") },
|
||||
{ E_OpKind_UnaryPrefix, 1, str8_lit_comp("bswap"), str8_lit_comp("("), str8_lit_comp(")") },
|
||||
{ E_OpKind_UnaryPrefix, 2, str8_lit_comp("+"), str8_lit_comp(""), str8_lit_comp("") },
|
||||
{ E_OpKind_UnaryPrefix, 2, str8_lit_comp("-"), str8_lit_comp(""), str8_lit_comp("") },
|
||||
{ E_OpKind_UnaryPrefix, 2, str8_lit_comp("!"), str8_lit_comp(""), str8_lit_comp("") },
|
||||
{ E_OpKind_UnaryPrefix, 2, str8_lit_comp("~"), str8_lit_comp(""), str8_lit_comp("") },
|
||||
|
||||
@@ -101,6 +101,7 @@ E_ExprKind_Cast,
|
||||
E_ExprKind_Sizeof,
|
||||
E_ExprKind_Typeof,
|
||||
E_ExprKind_ByteSwap,
|
||||
E_ExprKind_Pos,
|
||||
E_ExprKind_Neg,
|
||||
E_ExprKind_LogNot,
|
||||
E_ExprKind_BitNot,
|
||||
@@ -159,9 +160,9 @@ E_InterpretationCode_COUNT,
|
||||
|
||||
C_LINKAGE_BEGIN
|
||||
extern String8 e_token_kind_strings[6];
|
||||
extern String8 e_expr_kind_strings[47];
|
||||
extern String8 e_expr_kind_strings[48];
|
||||
extern String8 e_interpretation_code_display_strings[11];
|
||||
extern E_OpInfo e_expr_kind_op_info_table[47];
|
||||
extern E_OpInfo e_expr_kind_op_info_table[48];
|
||||
extern U8 e_kind_basic_byte_size_table[56];
|
||||
extern String8 e_kind_basic_string_table[56];
|
||||
|
||||
|
||||
@@ -39,6 +39,12 @@ EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_DEF(identity)
|
||||
////////////////////////////////
|
||||
//~ rjf: Key Functions
|
||||
|
||||
#if !defined(XXH_IMPLEMENTATION)
|
||||
# define XXH_IMPLEMENTATION
|
||||
# define XXH_STATIC_LINKING_ONLY
|
||||
# include "linker/third_party_ext/xxHash/xxhash.h"
|
||||
#endif
|
||||
|
||||
internal EV_Key
|
||||
ev_key_make(U64 parent_hash, U64 child_id)
|
||||
{
|
||||
@@ -74,11 +80,7 @@ ev_key_match(EV_Key a, EV_Key b)
|
||||
internal U64
|
||||
ev_hash_from_seed_string(U64 seed, String8 string)
|
||||
{
|
||||
U64 result = seed;
|
||||
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, seed);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -819,7 +821,7 @@ ev_block_tree_from_expr(Arena *arena, EV_View *view, String8 filter, String8 str
|
||||
}
|
||||
|
||||
// rjf: gather children expansions from inverse of expansion state
|
||||
if(!child_count && (expand_info.rows_default_expanded || expand_node == 0 && !expand_info.rows_default_expanded))
|
||||
if(!child_count && (expand_info.rows_default_expanded || (expand_node == 0 && !expand_info.rows_default_expanded)))
|
||||
{
|
||||
child_count = expand_info.row_count;
|
||||
child_keys = push_array(scratch.arena, EV_Key, child_count);
|
||||
@@ -1533,12 +1535,15 @@ ev_string_from_simple_typed_eval(Arena *arena, EV_StringFlags flags, U32 radix,
|
||||
case E_TypeKind_UChar16:
|
||||
case E_TypeKind_UChar32:
|
||||
{
|
||||
B32 type_is_unsigned = (E_TypeKind_UChar8 <= type_kind && type_kind <= E_TypeKind_UChar32);
|
||||
String8 char_str = ev_string_from_ascii_value(arena, eval.value.s64);
|
||||
if(char_str.size != 0)
|
||||
{
|
||||
if(flags & EV_StringFlag_ReadOnlyDisplayRules)
|
||||
{
|
||||
String8 imm_string = str8_from_s64(arena, eval.value.s64, radix, min_digits, digit_group_separator);
|
||||
String8 imm_string = (type_is_unsigned
|
||||
? str8_from_u64(arena, eval.value.u64, radix, min_digits, digit_group_separator)
|
||||
: str8_from_s64(arena, eval.value.s64, radix, min_digits, digit_group_separator));
|
||||
result = push_str8f(arena, "'%S' (%S)", char_str, imm_string);
|
||||
}
|
||||
else
|
||||
@@ -1548,7 +1553,9 @@ ev_string_from_simple_typed_eval(Arena *arena, EV_StringFlags flags, U32 radix,
|
||||
}
|
||||
else
|
||||
{
|
||||
result = str8_from_s64(arena, eval.value.s64, radix, min_digits, digit_group_separator);
|
||||
result = (type_is_unsigned
|
||||
? str8_from_u64(arena, eval.value.u64, radix, min_digits, digit_group_separator)
|
||||
: str8_from_s64(arena, eval.value.s64, radix, min_digits, digit_group_separator));
|
||||
}
|
||||
}break;
|
||||
|
||||
|
||||
+114
-140
@@ -53,12 +53,6 @@ fs_init(void)
|
||||
fs_shared->u2s_ring_base = push_array_no_zero(arena, U8, fs_shared->u2s_ring_size);
|
||||
fs_shared->u2s_ring_cv = os_condition_variable_alloc();
|
||||
fs_shared->u2s_ring_mutex = os_mutex_alloc();
|
||||
fs_shared->streamer_count = Clamp(1, os_get_system_info()->logical_processor_count-1, 4);
|
||||
fs_shared->streamers = push_array(arena, OS_Handle, 1);
|
||||
for(U64 idx = 0; idx < fs_shared->streamer_count; idx += 1)
|
||||
{
|
||||
fs_shared->streamers[idx] = os_thread_launch(fs_streamer_thread__entry_point, (void *)idx, 0);
|
||||
}
|
||||
fs_shared->detector_thread = os_thread_launch(fs_detector_thread__entry_point, 0, 0);
|
||||
}
|
||||
|
||||
@@ -106,7 +100,7 @@ fs_hash_from_path_range(String8 path, Rng1U64 range, U64 endt_us)
|
||||
FS_Stripe *path_stripe = &fs_shared->stripes[path_stripe_idx];
|
||||
|
||||
// rjf: loop: request, check for results, return until we can't
|
||||
OS_MutexScopeR(path_stripe->rw_mutex) for(;;)
|
||||
OS_MutexScopeW(path_stripe->rw_mutex) for(;;)
|
||||
{
|
||||
// rjf: path -> node
|
||||
FS_Node *node = 0;
|
||||
@@ -119,25 +113,14 @@ fs_hash_from_path_range(String8 path, Rng1U64 range, U64 endt_us)
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: node does not exist? -> create & store (we must re-search after promoting r -> w)
|
||||
if(node == 0) OS_MutexScopeRWPromote(path_stripe->rw_mutex)
|
||||
// rjf: node does not exist? -> create & store
|
||||
if(node == 0)
|
||||
{
|
||||
for(FS_Node *n = path_slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(str8_match(path, n->path, 0))
|
||||
{
|
||||
node = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(node == 0)
|
||||
{
|
||||
node = push_array(path_stripe->arena, FS_Node, 1);
|
||||
SLLQueuePush(path_slot->first, path_slot->last, node);
|
||||
node->path = push_str8_copy(path_stripe->arena, path);
|
||||
node->slots_count = 64;
|
||||
node->slots = push_array(path_stripe->arena, FS_RangeSlot, node->slots_count);
|
||||
}
|
||||
node = push_array(path_stripe->arena, FS_Node, 1);
|
||||
SLLQueuePush(path_slot->first, path_slot->last, node);
|
||||
node->path = push_str8_copy(path_stripe->arena, path);
|
||||
node->slots_count = 64;
|
||||
node->slots = push_array(path_stripe->arena, FS_RangeSlot, node->slots_count);
|
||||
}
|
||||
|
||||
// rjf: range -> node
|
||||
@@ -154,30 +137,25 @@ fs_hash_from_path_range(String8 path, Rng1U64 range, U64 endt_us)
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: range node does not exist? create & store (we must re-search after promoting r -> w)
|
||||
if(range_node == 0) OS_MutexScopeRWPromote(path_stripe->rw_mutex)
|
||||
// rjf: range node does not exist? create & store
|
||||
if(range_node == 0)
|
||||
{
|
||||
for(FS_RangeNode *n = range_slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(MemoryMatchStruct(&n->range, &range))
|
||||
{
|
||||
range_node = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(range_node == 0)
|
||||
{
|
||||
range_node = push_array(path_stripe->arena, FS_RangeNode, 1);
|
||||
SLLQueuePush(range_slot->first, range_slot->last, range_node);
|
||||
range_node->range = range;
|
||||
}
|
||||
range_node = push_array(path_stripe->arena, FS_RangeNode, 1);
|
||||
SLLQueuePush(range_slot->first, range_slot->last, range_node);
|
||||
range_node->range = range;
|
||||
}
|
||||
|
||||
// rjf: try to send stream request
|
||||
if(!ins_atomic_u32_eval_cond_assign(&range_node->is_working, 1, 0) &&
|
||||
!fs_u2s_enqueue_req(range, path, endt_us))
|
||||
if((ins_atomic_u64_eval(&range_node->request_count) == ins_atomic_u64_eval(&range_node->completion_count) ||
|
||||
ins_atomic_u64_eval(&range_node->last_time_requested_us)+100000 < os_now_microseconds()) &&
|
||||
fs_u2s_enqueue_req(range, path, endt_us))
|
||||
{
|
||||
ins_atomic_u32_eval_assign(&range_node->is_working, 0);
|
||||
ins_atomic_u64_eval_assign(&range_node->last_time_requested_us, os_now_microseconds());
|
||||
ins_atomic_u64_inc_eval(&range_node->request_count);
|
||||
DeferLoop(os_rw_mutex_drop_w(path_stripe->rw_mutex), os_rw_mutex_take_w(path_stripe->rw_mutex))
|
||||
{
|
||||
async_push_work(fs_stream_work, .completion_counter = &range_node->completion_count);
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: try to reobtain results
|
||||
@@ -186,7 +164,7 @@ fs_hash_from_path_range(String8 path, Rng1U64 range, U64 endt_us)
|
||||
// rjf: have time to wait? -> wait on this stripe; otherwise exit
|
||||
if(u128_match(result, u128_zero()) && os_now_microseconds() <= endt_us)
|
||||
{
|
||||
os_condition_variable_wait_rw_r(path_stripe->cv, path_stripe->rw_mutex, endt_us);
|
||||
os_condition_variable_wait_rw_w(path_stripe->cv, path_stripe->rw_mutex, endt_us);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -275,15 +253,14 @@ fs_u2s_enqueue_req(Rng1U64 range, String8 path, U64 endt_us)
|
||||
{
|
||||
U64 unconsumed_size = fs_shared->u2s_ring_write_pos - fs_shared->u2s_ring_read_pos;
|
||||
U64 available_size = fs_shared->u2s_ring_size - unconsumed_size;
|
||||
if(available_size >= sizeof(U64) + path.size)
|
||||
U64 needed_size = sizeof(range.min) + sizeof(range.max) + sizeof(path.size) + path.size;
|
||||
if(available_size >= needed_size)
|
||||
{
|
||||
result = 1;
|
||||
fs_shared->u2s_ring_write_pos += ring_write_struct(fs_shared->u2s_ring_base, fs_shared->u2s_ring_size, fs_shared->u2s_ring_write_pos, &range.min);
|
||||
fs_shared->u2s_ring_write_pos += ring_write_struct(fs_shared->u2s_ring_base, fs_shared->u2s_ring_size, fs_shared->u2s_ring_write_pos, &range.max);
|
||||
fs_shared->u2s_ring_write_pos += ring_write_struct(fs_shared->u2s_ring_base, fs_shared->u2s_ring_size, fs_shared->u2s_ring_write_pos, &path.size);
|
||||
fs_shared->u2s_ring_write_pos += ring_write(fs_shared->u2s_ring_base, fs_shared->u2s_ring_size, fs_shared->u2s_ring_write_pos, path.str, path.size);
|
||||
fs_shared->u2s_ring_write_pos += 7;
|
||||
fs_shared->u2s_ring_write_pos -= fs_shared->u2s_ring_write_pos%8;
|
||||
break;
|
||||
}
|
||||
os_condition_variable_wait(fs_shared->u2s_ring_cv, fs_shared->u2s_ring_mutex, endt_us);
|
||||
@@ -308,8 +285,6 @@ fs_u2s_dequeue_req(Arena *arena, Rng1U64 *range_out, String8 *path_out)
|
||||
fs_shared->u2s_ring_read_pos += ring_read_struct(fs_shared->u2s_ring_base, fs_shared->u2s_ring_size, fs_shared->u2s_ring_read_pos, &path_out->size);
|
||||
path_out->str = push_array(arena, U8, path_out->size);
|
||||
fs_shared->u2s_ring_read_pos += ring_read(fs_shared->u2s_ring_base, fs_shared->u2s_ring_size, fs_shared->u2s_ring_read_pos, path_out->str, path_out->size);
|
||||
fs_shared->u2s_ring_read_pos += 7;
|
||||
fs_shared->u2s_ring_read_pos -= fs_shared->u2s_ring_read_pos%8;
|
||||
break;
|
||||
}
|
||||
os_condition_variable_wait(fs_shared->u2s_ring_cv, fs_shared->u2s_ring_mutex, max_U64);
|
||||
@@ -317,108 +292,105 @@ fs_u2s_dequeue_req(Arena *arena, Rng1U64 *range_out, String8 *path_out)
|
||||
os_condition_variable_broadcast(fs_shared->u2s_ring_cv);
|
||||
}
|
||||
|
||||
internal void
|
||||
fs_streamer_thread__entry_point(void *p)
|
||||
ASYNC_WORK_DEF(fs_stream_work)
|
||||
{
|
||||
ThreadNameF("[fs] streamer #%I64u", (U64)p);
|
||||
for(;;)
|
||||
ProfBeginFunction();
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
|
||||
//- rjf: get next request
|
||||
Rng1U64 range = {0};
|
||||
String8 path = {0};
|
||||
fs_u2s_dequeue_req(scratch.arena, &range, &path);
|
||||
|
||||
//- rjf: unpack request
|
||||
U128 key = fs_big_hash_from_string_range(path, range);
|
||||
U64 path_hash = fs_little_hash_from_string(path);
|
||||
U64 path_slot_idx = path_hash%fs_shared->slots_count;
|
||||
U64 path_stripe_idx = path_slot_idx%fs_shared->stripes_count;
|
||||
FS_Slot *path_slot = &fs_shared->slots[path_slot_idx];
|
||||
FS_Stripe *path_stripe = &fs_shared->stripes[path_stripe_idx];
|
||||
|
||||
//- rjf: load
|
||||
ProfBegin("load \"%.*s\"", str8_varg(path));
|
||||
FileProperties pre_props = os_properties_from_file_path(path);
|
||||
U64 range_size = dim_1u64(range);
|
||||
U64 read_size = Min(pre_props.size, range_size);
|
||||
OS_Handle file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead|OS_AccessFlag_ShareWrite, path);
|
||||
U64 data_arena_size = read_size+ARENA_HEADER_SIZE;
|
||||
data_arena_size += KB(4)-1;
|
||||
data_arena_size -= data_arena_size%KB(4);
|
||||
ProfBegin("allocate");
|
||||
Arena *data_arena = arena_alloc(.reserve_size = data_arena_size, .commit_size = data_arena_size);
|
||||
ProfEnd();
|
||||
ProfBegin("read");
|
||||
String8 data = os_string_from_file_range(data_arena, file, r1u64(range.min, range.min+read_size));
|
||||
ProfEnd();
|
||||
os_file_close(file);
|
||||
FileProperties post_props = os_properties_from_file_path(path);
|
||||
|
||||
//- rjf: abort if modification timestamps differ - we did not successfully read the file
|
||||
if(pre_props.modified != post_props.modified)
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
|
||||
//- rjf: get next request
|
||||
Rng1U64 range = {0};
|
||||
String8 path = {0};
|
||||
fs_u2s_dequeue_req(scratch.arena, &range, &path);
|
||||
|
||||
//- rjf: unpack request
|
||||
U128 key = fs_big_hash_from_string_range(path, range);
|
||||
U64 path_hash = fs_little_hash_from_string(path);
|
||||
U64 path_slot_idx = path_hash%fs_shared->slots_count;
|
||||
U64 path_stripe_idx = path_slot_idx%fs_shared->stripes_count;
|
||||
FS_Slot *path_slot = &fs_shared->slots[path_slot_idx];
|
||||
FS_Stripe *path_stripe = &fs_shared->stripes[path_stripe_idx];
|
||||
|
||||
//- rjf: load
|
||||
ProfBegin("load \"%.*s\"", str8_varg(path));
|
||||
FileProperties pre_props = os_properties_from_file_path(path);
|
||||
U64 range_size = dim_1u64(range);
|
||||
U64 read_size = Min(pre_props.size, range_size);
|
||||
OS_Handle file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead|OS_AccessFlag_ShareWrite, path);
|
||||
U64 data_arena_size = read_size+ARENA_HEADER_SIZE;
|
||||
data_arena_size += KB(4)-1;
|
||||
data_arena_size -= data_arena_size%KB(4);
|
||||
ProfBegin("allocate");
|
||||
Arena *data_arena = arena_alloc(.reserve_size = data_arena_size, .commit_size = data_arena_size);
|
||||
ProfEnd();
|
||||
ProfBegin("read");
|
||||
String8 data = os_string_from_file_range(data_arena, file, r1u64(range.min, range.min+read_size));
|
||||
ProfEnd();
|
||||
os_file_close(file);
|
||||
FileProperties post_props = os_properties_from_file_path(path);
|
||||
|
||||
//- rjf: abort if modification timestamps differ - we did not successfully read the file
|
||||
if(pre_props.modified != post_props.modified)
|
||||
ProfScope("abort")
|
||||
{
|
||||
ProfScope("abort")
|
||||
arena_release(data_arena);
|
||||
MemoryZeroStruct(&data);
|
||||
data_arena = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: submit
|
||||
else
|
||||
{
|
||||
ProfScope("submit")
|
||||
{
|
||||
hs_submit_data(key, &data_arena, data);
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: commit info to cache
|
||||
ProfScope("commit to cache") OS_MutexScopeW(path_stripe->rw_mutex)
|
||||
{
|
||||
FS_Node *node = 0;
|
||||
for(FS_Node *n = path_slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(str8_match(n->path, path, 0))
|
||||
{
|
||||
arena_release(data_arena);
|
||||
MemoryZeroStruct(&data);
|
||||
data_arena = 0;
|
||||
node = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: submit
|
||||
else
|
||||
if(node != 0)
|
||||
{
|
||||
ProfScope("submit")
|
||||
if(node->timestamp != 0)
|
||||
{
|
||||
hs_submit_data(key, &data_arena, data);
|
||||
ins_atomic_u64_inc_eval(&fs_shared->change_gen);
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: commit info to cache
|
||||
ProfScope("commit to cache") OS_MutexScopeW(path_stripe->rw_mutex)
|
||||
{
|
||||
FS_Node *node = 0;
|
||||
for(FS_Node *n = path_slot->first; n != 0; n = n->next)
|
||||
if(post_props.modified == pre_props.modified)
|
||||
{
|
||||
if(str8_match(n->path, path, 0))
|
||||
node->timestamp = post_props.modified;
|
||||
node->size = post_props.size;
|
||||
}
|
||||
U64 range_hash = fs_little_hash_from_string(str8_struct(&range));
|
||||
U64 range_slot_idx = range_hash%node->slots_count;
|
||||
FS_RangeSlot *range_slot = &node->slots[range_slot_idx];
|
||||
FS_RangeNode *range_node = 0;
|
||||
for(FS_RangeNode *n = range_slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(MemoryMatchStruct(&n->range, &range))
|
||||
{
|
||||
node = n;
|
||||
range_node = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(node != 0)
|
||||
{
|
||||
if(node->timestamp != 0)
|
||||
{
|
||||
ins_atomic_u64_inc_eval(&fs_shared->change_gen);
|
||||
}
|
||||
if(post_props.modified == pre_props.modified)
|
||||
{
|
||||
node->timestamp = post_props.modified;
|
||||
node->size = post_props.size;
|
||||
}
|
||||
U64 range_hash = fs_little_hash_from_string(str8_struct(&range));
|
||||
U64 range_slot_idx = range_hash%node->slots_count;
|
||||
FS_RangeSlot *range_slot = &node->slots[range_slot_idx];
|
||||
FS_RangeNode *range_node = 0;
|
||||
for(FS_RangeNode *n = range_slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(MemoryMatchStruct(&n->range, &range))
|
||||
{
|
||||
range_node = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ins_atomic_u32_eval_assign(&range_node->is_working, 0);
|
||||
}
|
||||
}
|
||||
os_condition_variable_broadcast(path_stripe->cv);
|
||||
|
||||
ProfEnd();
|
||||
scratch_end(scratch);
|
||||
}
|
||||
os_condition_variable_broadcast(path_stripe->cv);
|
||||
|
||||
ProfEnd();
|
||||
scratch_end(scratch);
|
||||
ProfEnd();
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
@@ -427,7 +399,7 @@ fs_streamer_thread__entry_point(void *p)
|
||||
internal void
|
||||
fs_detector_thread__entry_point(void *p)
|
||||
{
|
||||
ThreadNameF("[fs] detector");
|
||||
ThreadNameF("[fs] detector thread");
|
||||
for(;;)
|
||||
{
|
||||
U64 slots_per_stripe = fs_shared->slots_count/fs_shared->stripes_count;
|
||||
@@ -449,10 +421,12 @@ fs_detector_thread__entry_point(void *p)
|
||||
range_n != 0;
|
||||
range_n = range_n->next)
|
||||
{
|
||||
if(!ins_atomic_u32_eval_cond_assign(&range_n->is_working, 1, 0) &&
|
||||
!fs_u2s_enqueue_req(range_n->range, n->path, os_now_microseconds()+100000))
|
||||
if(ins_atomic_u64_eval(&range_n->request_count) == ins_atomic_u64_eval(&range_n->completion_count) &&
|
||||
fs_u2s_enqueue_req(range_n->range, n->path, os_now_microseconds()+100000))
|
||||
{
|
||||
ins_atomic_u32_eval_assign(&range_n->is_working, 0);
|
||||
ins_atomic_u64_eval_assign(&range_n->last_time_requested_us, os_now_microseconds());
|
||||
ins_atomic_u64_inc_eval(&range_n->request_count);
|
||||
async_push_work(fs_stream_work, .completion_counter = &range_n->completion_count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,9 @@ struct FS_RangeNode
|
||||
{
|
||||
FS_RangeNode *next;
|
||||
Rng1U64 range;
|
||||
B32 is_working;
|
||||
U64 request_count;
|
||||
U64 completion_count;
|
||||
U64 last_time_requested_us;
|
||||
};
|
||||
|
||||
typedef struct FS_RangeSlot FS_RangeSlot;
|
||||
@@ -75,10 +77,6 @@ struct FS_Shared
|
||||
OS_Handle u2s_ring_cv;
|
||||
OS_Handle u2s_ring_mutex;
|
||||
|
||||
// rjf: streamer threads
|
||||
U64 streamer_count;
|
||||
OS_Handle *streamers;
|
||||
|
||||
// rjf: change detector threads
|
||||
OS_Handle detector_thread;
|
||||
};
|
||||
@@ -114,12 +112,11 @@ internal U64 fs_timestamp_from_path(String8 path);
|
||||
internal U64 fs_size_from_path(String8 path);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Streamer Threads
|
||||
//~ rjf: Streaming Work
|
||||
|
||||
internal B32 fs_u2s_enqueue_req(Rng1U64 range, String8 path, U64 endt_us);
|
||||
internal void fs_u2s_dequeue_req(Arena *arena, Rng1U64 *range_out, String8 *path_out);
|
||||
|
||||
internal void fs_streamer_thread__entry_point(void *p);
|
||||
ASYNC_WORK_DEF(fs_stream_work);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Change Detector Thread
|
||||
|
||||
+31
-28
@@ -4,28 +4,29 @@
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Functions
|
||||
|
||||
#if !defined(BLAKE2_H)
|
||||
#define HAVE_SSE2
|
||||
#include "third_party/blake2/blake2.h"
|
||||
#include "third_party/blake2/blake2b.c"
|
||||
#if !defined(XXH_IMPLEMENTATION)
|
||||
# define XXH_IMPLEMENTATION
|
||||
# define XXH_STATIC_LINKING_ONLY
|
||||
# include "linker/third_party_ext/xxHash/xxhash.h"
|
||||
#endif
|
||||
|
||||
internal U128
|
||||
fnt_hash_from_string(String8 string)
|
||||
{
|
||||
U128 result = {0};
|
||||
blake2b((U8 *)&result.u64[0], sizeof(result), string.str, string.size, 0, 0);
|
||||
return result;
|
||||
union
|
||||
{
|
||||
XXH128_hash_t xxhash;
|
||||
U128 u128;
|
||||
}
|
||||
hash;
|
||||
hash.xxhash = XXH3_128bits(string.str, string.size);
|
||||
return hash.u128;
|
||||
}
|
||||
|
||||
internal U64
|
||||
fnt_little_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(string.str, string.size);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -575,46 +576,48 @@ fnt_push_run_from_string(Arena *arena, FNT_Tag tag, F32 size, F32 base_align_px,
|
||||
FNT_Hash2StyleRasterCacheNode *hash2style_node = fnt_hash2style_from_tag_size_flags(tag, size, flags);
|
||||
|
||||
//- rjf: decode string & produce run pieces
|
||||
B32 first = 1;
|
||||
FNT_PieceChunkList piece_chunks = {0};
|
||||
Vec2F32 dim = {0};
|
||||
B32 font_handle_mapped_on_miss = 0;
|
||||
FP_Handle font_handle = {0};
|
||||
U64 piece_substring_start_idx = 0;
|
||||
for(U64 idx = 0; idx < string.size; first = 0)
|
||||
U64 piece_substring_end_idx = 0;
|
||||
for(U64 idx = 0; idx <= string.size;)
|
||||
{
|
||||
//- rjf: decode next codepoint & get piece substring, or continuation rule
|
||||
String8 piece_substring;
|
||||
U8 byte = (idx < string.size ? string.str[idx] : 0);
|
||||
B32 need_another_codepoint = 0;
|
||||
switch(utf8_class[string.str[idx]>>3])
|
||||
if(byte == 0)
|
||||
{
|
||||
idx += 1;
|
||||
}
|
||||
else switch(utf8_class[byte>>3])
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
piece_substring.str = &string.str[idx];
|
||||
piece_substring.size = 1;
|
||||
idx += 1;
|
||||
piece_substring_end_idx += 1;
|
||||
need_another_codepoint = 0;
|
||||
}break;
|
||||
default:
|
||||
{
|
||||
UnicodeDecode decode = utf8_decode(string.str+idx, string.size-idx);
|
||||
idx += decode.inc;
|
||||
if(decode.inc == 0) { break; }
|
||||
piece_substring.str = string.str + piece_substring_start_idx;
|
||||
piece_substring.size = decode.inc;
|
||||
// NOTE(rjf): assuming 1 codepoint per piece for now.
|
||||
piece_substring_end_idx += decode.inc;
|
||||
need_another_codepoint = 0;
|
||||
}break;
|
||||
}
|
||||
|
||||
//- rjf: need another codepoint? -> continue
|
||||
if(need_another_codepoint)
|
||||
//- rjf: need another codepoint, or have no substring? -> continue
|
||||
if(need_another_codepoint || piece_substring_end_idx == piece_substring_start_idx)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
//- rjf: do not need another codepoint? -> bump piece start idx
|
||||
{
|
||||
piece_substring_start_idx = idx;
|
||||
}
|
||||
//- rjf: do not need another codepoint? -> grab substring, bump piece start idx
|
||||
String8 piece_substring = str8_substr(string, r1u64(piece_substring_start_idx, piece_substring_end_idx));
|
||||
piece_substring_start_idx = idx;
|
||||
piece_substring_end_idx = idx;
|
||||
|
||||
//- rjf: determine if this piece is a tab - if so, use space info to draw
|
||||
B32 is_tab = (piece_substring.size == 1 && piece_substring.str[0] == '\t');
|
||||
|
||||
@@ -1,547 +0,0 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Helpers
|
||||
|
||||
internal U64
|
||||
fzy_hash_from_string(U64 seed, String8 string)
|
||||
{
|
||||
U64 result = seed;
|
||||
for(U64 i = 0; i < string.size; i += 1)
|
||||
{
|
||||
result = ((result << 5) + result) + string.str[i];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal U64
|
||||
fzy_hash_from_params(FZY_Params *params)
|
||||
{
|
||||
U64 hash = 5381;
|
||||
hash = fzy_hash_from_string(hash, str8_struct(¶ms->target));
|
||||
for(U64 idx = 0; idx < params->dbgi_keys.count; idx += 1)
|
||||
{
|
||||
hash = fzy_hash_from_string(hash, str8_struct(¶ms->dbgi_keys.v[idx].min_timestamp));
|
||||
hash = fzy_hash_from_string(hash, params->dbgi_keys.v[idx].path);
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
internal U64
|
||||
fzy_item_num_from_array_element_idx__linear_search(FZY_ItemArray *array, U64 element_idx)
|
||||
{
|
||||
U64 fuzzy_item_num = 0;
|
||||
for(U64 idx = 0; idx < array->count; idx += 1)
|
||||
{
|
||||
if(array->v[idx].idx == element_idx)
|
||||
{
|
||||
fuzzy_item_num = idx+1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return fuzzy_item_num;
|
||||
}
|
||||
|
||||
internal String8
|
||||
fzy_item_string_from_rdi_target_element_idx(RDI_Parsed *rdi, RDI_SectionKind target, U64 element_idx)
|
||||
{
|
||||
String8 result = {0};
|
||||
switch(target)
|
||||
{
|
||||
default:{}break;
|
||||
case RDI_SectionKind_Procedures:
|
||||
{
|
||||
RDI_Procedure *proc = rdi_element_from_name_idx(rdi, Procedures, element_idx);
|
||||
U64 name_size = 0;
|
||||
U8 *name_base = rdi_string_from_idx(rdi, proc->name_string_idx, &name_size);
|
||||
result = str8(name_base, name_size);
|
||||
}break;
|
||||
case RDI_SectionKind_GlobalVariables:
|
||||
{
|
||||
RDI_GlobalVariable *gvar = rdi_element_from_name_idx(rdi, GlobalVariables, element_idx);
|
||||
U64 name_size = 0;
|
||||
U8 *name_base = rdi_string_from_idx(rdi, gvar->name_string_idx, &name_size);
|
||||
result = str8(name_base, name_size);
|
||||
}break;
|
||||
case RDI_SectionKind_ThreadVariables:
|
||||
{
|
||||
RDI_ThreadVariable *tvar = rdi_element_from_name_idx(rdi, ThreadVariables, element_idx);
|
||||
U64 name_size = 0;
|
||||
U8 *name_base = rdi_string_from_idx(rdi, tvar->name_string_idx, &name_size);
|
||||
result = str8(name_base, name_size);
|
||||
}break;
|
||||
case RDI_SectionKind_UDTs:
|
||||
{
|
||||
RDI_UDT *udt = rdi_element_from_name_idx(rdi, UDTs, element_idx);
|
||||
RDI_TypeNode *type_node = rdi_element_from_name_idx(rdi, TypeNodes, udt->self_type_idx);
|
||||
U64 name_size = 0;
|
||||
U8 *name_base = rdi_string_from_idx(rdi, type_node->user_defined.name_string_idx, &name_size);
|
||||
result = str8(name_base, name_size);
|
||||
}break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal FZY_Params
|
||||
fzy_params_copy(Arena *arena, FZY_Params *src)
|
||||
{
|
||||
FZY_Params dst = zero_struct;
|
||||
MemoryCopyStruct(&dst, src);
|
||||
dst.dbgi_keys.v = push_array(arena, DI_Key, dst.dbgi_keys.count);
|
||||
MemoryCopy(dst.dbgi_keys.v, src->dbgi_keys.v, sizeof(DI_Key)*src->dbgi_keys.count);
|
||||
for(U64 idx = 0; idx < dst.dbgi_keys.count; idx += 1)
|
||||
{
|
||||
dst.dbgi_keys.v[idx].path = push_str8_copy(arena, dst.dbgi_keys.v[idx].path);
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Main Layer Initialization
|
||||
|
||||
internal void
|
||||
fzy_init(void)
|
||||
{
|
||||
Arena *arena = arena_alloc();
|
||||
fzy_shared = push_array(arena, FZY_Shared, 1);
|
||||
fzy_shared->arena = arena;
|
||||
fzy_shared->slots_count = 256;
|
||||
fzy_shared->stripes_count = os_get_system_info()->logical_processor_count;
|
||||
fzy_shared->slots = push_array(arena, FZY_Slot, fzy_shared->slots_count);
|
||||
fzy_shared->stripes = push_array(arena, FZY_Stripe, fzy_shared->stripes_count);
|
||||
for(U64 idx = 0; idx < fzy_shared->stripes_count; idx += 1)
|
||||
{
|
||||
fzy_shared->stripes[idx].arena = arena_alloc();
|
||||
fzy_shared->stripes[idx].rw_mutex = os_rw_mutex_alloc();
|
||||
fzy_shared->stripes[idx].cv = os_condition_variable_alloc();
|
||||
}
|
||||
fzy_shared->thread_count = Min(os_get_system_info()->logical_processor_count, 2);
|
||||
fzy_shared->threads = push_array(arena, FZY_Thread, fzy_shared->thread_count);
|
||||
for(U64 idx = 0; idx < fzy_shared->thread_count; idx += 1)
|
||||
{
|
||||
fzy_shared->threads[idx].u2f_ring_mutex = os_mutex_alloc();
|
||||
fzy_shared->threads[idx].u2f_ring_cv = os_condition_variable_alloc();
|
||||
fzy_shared->threads[idx].u2f_ring_size = KB(64);
|
||||
fzy_shared->threads[idx].u2f_ring_base = push_array_no_zero(arena, U8, fzy_shared->threads[idx].u2f_ring_size);
|
||||
fzy_shared->threads[idx].thread = os_thread_launch(fzy_search_thread__entry_point, (void *)idx, 0);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Scope Functions
|
||||
|
||||
internal FZY_Scope *
|
||||
fzy_scope_open(void)
|
||||
{
|
||||
if(fzy_tctx == 0)
|
||||
{
|
||||
Arena *arena = arena_alloc();
|
||||
fzy_tctx = push_array(arena, FZY_TCTX, 1);
|
||||
fzy_tctx->arena = arena;
|
||||
}
|
||||
FZY_Scope *scope = fzy_tctx->free_scope;
|
||||
if(scope != 0)
|
||||
{
|
||||
SLLStackPop(fzy_tctx->free_scope);
|
||||
}
|
||||
else
|
||||
{
|
||||
scope = push_array_no_zero(fzy_tctx->arena, FZY_Scope, 1);
|
||||
}
|
||||
MemoryZeroStruct(scope);
|
||||
return scope;
|
||||
}
|
||||
|
||||
internal void
|
||||
fzy_scope_close(FZY_Scope *scope)
|
||||
{
|
||||
for(FZY_Touch *t = scope->first_touch, *next = 0; t != 0; t = next)
|
||||
{
|
||||
next = t->next;
|
||||
SLLStackPush(fzy_tctx->free_touch, t);
|
||||
if(t->node != 0)
|
||||
{
|
||||
ins_atomic_u64_dec_eval(&t->node->touch_count);
|
||||
}
|
||||
}
|
||||
SLLStackPush(fzy_tctx->free_scope, scope);
|
||||
}
|
||||
|
||||
internal void
|
||||
fzy_scope_touch_node__stripe_mutex_r_guarded(FZY_Scope *scope, FZY_Node *node)
|
||||
{
|
||||
if(node != 0)
|
||||
{
|
||||
ins_atomic_u64_inc_eval(&node->touch_count);
|
||||
}
|
||||
FZY_Touch *touch = fzy_tctx->free_touch;
|
||||
if(touch != 0)
|
||||
{
|
||||
SLLStackPop(fzy_tctx->free_touch);
|
||||
}
|
||||
else
|
||||
{
|
||||
touch = push_array_no_zero(fzy_tctx->arena, FZY_Touch, 1);
|
||||
}
|
||||
MemoryZeroStruct(touch);
|
||||
SLLQueuePush(scope->first_touch, scope->last_touch, touch);
|
||||
touch->node = node;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cache Lookup Functions
|
||||
|
||||
internal FZY_ItemArray
|
||||
fzy_items_from_key_params_query(FZY_Scope *scope, U128 key, FZY_Params *params, String8 query, U64 endt_us, B32 *stale_out)
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
FZY_ItemArray items = {0};
|
||||
|
||||
//- rjf: hash parameters
|
||||
U64 params_hash = fzy_hash_from_params(params);
|
||||
|
||||
//- rjf: unpack key
|
||||
U64 slot_idx = key.u64[1]%fzy_shared->slots_count;
|
||||
U64 stripe_idx = slot_idx%fzy_shared->stripes_count;
|
||||
FZY_Slot *slot = &fzy_shared->slots[slot_idx];
|
||||
FZY_Stripe *stripe = &fzy_shared->stripes[stripe_idx];
|
||||
|
||||
//- rjf: query and/or request
|
||||
OS_MutexScopeR(stripe->rw_mutex) for(;;)
|
||||
{
|
||||
// rjf: map key -> node
|
||||
FZY_Node *node = 0;
|
||||
for(FZY_Node *n = slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(u128_match(n->key, key))
|
||||
{
|
||||
node = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: no node? -> allocate
|
||||
if(node == 0) OS_MutexScopeRWPromote(stripe->rw_mutex)
|
||||
{
|
||||
node = push_array(stripe->arena, FZY_Node, 1);
|
||||
SLLQueuePush(slot->first, slot->last, node);
|
||||
node->key = key;
|
||||
for(U64 idx = 0; idx < ArrayCount(node->buckets); idx += 1)
|
||||
{
|
||||
node->buckets[idx].arena = arena_alloc();
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: try to grab last valid results for this key/query; determine if stale
|
||||
B32 stale = 1;
|
||||
if(params_hash == node->buckets[node->gen%ArrayCount(node->buckets)].params_hash &&
|
||||
node->gen != 0)
|
||||
{
|
||||
fzy_scope_touch_node__stripe_mutex_r_guarded(scope, node);
|
||||
items = node->gen_items;
|
||||
stale = !str8_match(query, node->buckets[node->gen%ArrayCount(node->buckets)].query, 0);
|
||||
if(stale_out != 0)
|
||||
{
|
||||
*stale_out = stale;
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: if stale -> request again
|
||||
if(stale) OS_MutexScopeRWPromote(stripe->rw_mutex)
|
||||
{
|
||||
if(node->gen <= node->submit_gen && node->submit_gen < node->gen + ArrayCount(node->buckets)-1)
|
||||
{
|
||||
node->submit_gen += 1;
|
||||
arena_clear(node->buckets[node->submit_gen%ArrayCount(node->buckets)].arena);
|
||||
node->buckets[node->submit_gen%ArrayCount(node->buckets)].query = push_str8_copy(node->buckets[node->submit_gen%ArrayCount(node->buckets)].arena, query);
|
||||
node->buckets[node->submit_gen%ArrayCount(node->buckets)].params = fzy_params_copy(node->buckets[node->submit_gen%ArrayCount(node->buckets)].arena, params);
|
||||
node->buckets[node->submit_gen%ArrayCount(node->buckets)].params_hash = params_hash;
|
||||
}
|
||||
if((node->submit_gen > node->gen+1 || os_now_microseconds() >= node->last_time_submitted_us+100000) &&
|
||||
fzy_u2s_enqueue_req(key, endt_us))
|
||||
{
|
||||
node->last_time_submitted_us = os_now_microseconds();
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: not stale, or timeout -> break
|
||||
if(!stale || os_now_microseconds() >= endt_us)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// rjf: no results, but have time to wait -> wait
|
||||
os_condition_variable_wait_rw_r(stripe->cv, stripe->rw_mutex, endt_us);
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
return items;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Searcher Threads
|
||||
|
||||
internal B32
|
||||
fzy_u2s_enqueue_req(U128 key, U64 endt_us)
|
||||
{
|
||||
B32 sent = 0;
|
||||
FZY_Thread *thread = &fzy_shared->threads[key.u64[1]%fzy_shared->thread_count];
|
||||
OS_MutexScope(thread->u2f_ring_mutex) for(;;)
|
||||
{
|
||||
U64 unconsumed_size = thread->u2f_ring_write_pos - thread->u2f_ring_read_pos;
|
||||
U64 available_size = thread->u2f_ring_size - unconsumed_size;
|
||||
if(available_size >= sizeof(U128))
|
||||
{
|
||||
sent = 1;
|
||||
thread->u2f_ring_write_pos += ring_write_struct(thread->u2f_ring_base, thread->u2f_ring_size, thread->u2f_ring_write_pos, &key);
|
||||
break;
|
||||
}
|
||||
os_condition_variable_wait(thread->u2f_ring_cv, thread->u2f_ring_mutex, endt_us);
|
||||
}
|
||||
if(sent)
|
||||
{
|
||||
os_condition_variable_broadcast(thread->u2f_ring_cv);
|
||||
}
|
||||
return sent;
|
||||
}
|
||||
|
||||
internal void
|
||||
fzy_u2s_dequeue_req(Arena *arena, FZY_Thread *thread, U128 *key_out)
|
||||
{
|
||||
OS_MutexScope(thread->u2f_ring_mutex) for(;;)
|
||||
{
|
||||
U64 unconsumed_size = thread->u2f_ring_write_pos - thread->u2f_ring_read_pos;
|
||||
if(unconsumed_size >= sizeof(U128))
|
||||
{
|
||||
thread->u2f_ring_read_pos += ring_read_struct(thread->u2f_ring_base, thread->u2f_ring_size, thread->u2f_ring_read_pos, key_out);
|
||||
break;
|
||||
}
|
||||
os_condition_variable_wait(thread->u2f_ring_cv, thread->u2f_ring_mutex, max_U64);
|
||||
}
|
||||
os_condition_variable_broadcast(thread->u2f_ring_cv);
|
||||
}
|
||||
|
||||
internal int
|
||||
fzy_qsort_compare_items(FZY_Item *a, FZY_Item *b)
|
||||
{
|
||||
int result = 0;
|
||||
if(a->match_ranges.count > b->match_ranges.count)
|
||||
{
|
||||
result = -1;
|
||||
}
|
||||
else if(a->match_ranges.count < b->match_ranges.count)
|
||||
{
|
||||
result = +1;
|
||||
}
|
||||
else if(a->missed_size < b->missed_size)
|
||||
{
|
||||
result = -1;
|
||||
}
|
||||
else if(a->missed_size > b->missed_size)
|
||||
{
|
||||
result = +1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal void
|
||||
fzy_search_thread__entry_point(void *p)
|
||||
{
|
||||
ThreadNameF("[fzy] searcher #%I64u", (U64)p);
|
||||
FZY_Thread *thread = &fzy_shared->threads[(U64)p];
|
||||
for(;;)
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
DI_Scope *di_scope = di_scope_open();
|
||||
|
||||
////////////////////////////
|
||||
//- rjf: dequeue next request
|
||||
//
|
||||
U128 key = {0};
|
||||
fzy_u2s_dequeue_req(scratch.arena, thread, &key);
|
||||
U64 slot_idx = key.u64[1]%fzy_shared->slots_count;
|
||||
U64 stripe_idx = slot_idx%fzy_shared->stripes_count;
|
||||
FZY_Slot *slot = &fzy_shared->slots[slot_idx];
|
||||
FZY_Stripe *stripe = &fzy_shared->stripes[stripe_idx];
|
||||
|
||||
////////////////////////////
|
||||
//- rjf: grab next exe_path/query for this key
|
||||
//
|
||||
B32 task_is_good = 0;
|
||||
Arena *task_arena = 0;
|
||||
String8 query = {0};
|
||||
FZY_Params params = {RDI_SectionKind_Procedures};
|
||||
U64 initial_submit_gen = 0;
|
||||
OS_MutexScopeW(stripe->rw_mutex)
|
||||
{
|
||||
for(FZY_Node *n = slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(u128_match(n->key, key))
|
||||
{
|
||||
FZY_Bucket *bucket = &n->buckets[n->submit_gen%ArrayCount(n->buckets)];
|
||||
task_is_good = 1;
|
||||
initial_submit_gen = n->submit_gen;
|
||||
task_arena = bucket->arena;
|
||||
query = bucket->query;
|
||||
params = bucket->params;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////
|
||||
//- rjf: params -> look up all rdis
|
||||
//
|
||||
U64 rdis_count = params.dbgi_keys.count;
|
||||
RDI_Parsed **rdis = push_array(scratch.arena, RDI_Parsed *, rdis_count);
|
||||
if(task_is_good)
|
||||
{
|
||||
for(U64 idx = 0; idx < rdis_count; idx += 1)
|
||||
{
|
||||
rdis[idx] = di_rdi_from_key(di_scope, ¶ms.dbgi_keys.v[idx], max_U64);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////
|
||||
//- rjf: search target -> info about search space
|
||||
//
|
||||
U64 element_name_idx_off = 0;
|
||||
if(task_is_good)
|
||||
{
|
||||
switch(params.target)
|
||||
{
|
||||
default:{}break;
|
||||
case RDI_SectionKind_Procedures:
|
||||
{
|
||||
element_name_idx_off = OffsetOf(RDI_Procedure, name_string_idx);
|
||||
}break;
|
||||
case RDI_SectionKind_GlobalVariables:
|
||||
{
|
||||
element_name_idx_off = OffsetOf(RDI_GlobalVariable, name_string_idx);
|
||||
}break;
|
||||
case RDI_SectionKind_ThreadVariables:
|
||||
{
|
||||
element_name_idx_off = OffsetOf(RDI_ThreadVariable, name_string_idx);
|
||||
}break;
|
||||
case RDI_SectionKind_UDTs:
|
||||
{
|
||||
// NOTE(rjf): name must be determined from self_type_idx
|
||||
}break;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////
|
||||
//- rjf: rdis * query * params -> item list
|
||||
//
|
||||
FZY_ItemChunkList items_list = {0};
|
||||
if(task_is_good)
|
||||
{
|
||||
U64 base_idx = 0;
|
||||
for(U64 rdi_idx = 0; rdi_idx < rdis_count; rdi_idx += 1)
|
||||
{
|
||||
RDI_Parsed *rdi = rdis[rdi_idx];
|
||||
U64 element_count = 0;
|
||||
void *table_base = rdi_section_raw_table_from_kind(rdi, params.target, &element_count);
|
||||
U64 element_size = rdi_section_element_size_table[params.target];
|
||||
for(U64 idx = 1; task_is_good && idx < element_count; idx += 1)
|
||||
{
|
||||
void *element = (U8 *)table_base + element_size*idx;
|
||||
U32 *name_idx_ptr = (U32 *)((U8 *)element + element_name_idx_off);
|
||||
if(params.target == RDI_SectionKind_UDTs)
|
||||
{
|
||||
RDI_UDT *udt = (RDI_UDT *)element;
|
||||
RDI_TypeNode *type_node = rdi_element_from_name_idx(rdi, TypeNodes, udt->self_type_idx);
|
||||
name_idx_ptr = &type_node->user_defined.name_string_idx;
|
||||
}
|
||||
U32 name_idx = *name_idx_ptr;
|
||||
U64 name_size = 0;
|
||||
U8 *name_base = rdi_string_from_idx(rdi, name_idx, &name_size);
|
||||
String8 name = str8(name_base, name_size);
|
||||
if(name.size == 0) { continue; }
|
||||
FuzzyMatchRangeList matches = fuzzy_match_find(task_arena, query, name);
|
||||
if(matches.count == matches.needle_part_count)
|
||||
{
|
||||
FZY_ItemChunk *chunk = items_list.last;
|
||||
if(chunk == 0 || chunk->count >= chunk->cap)
|
||||
{
|
||||
chunk = push_array(scratch.arena, FZY_ItemChunk, 1);
|
||||
chunk->cap = 1024;
|
||||
chunk->count = 0;
|
||||
chunk->v = push_array_no_zero(scratch.arena, FZY_Item, chunk->cap);
|
||||
SLLQueuePush(items_list.first, items_list.last, chunk);
|
||||
items_list.chunk_count += 1;
|
||||
}
|
||||
chunk->v[chunk->count].idx = base_idx + 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->count += 1;
|
||||
items_list.total_count += 1;
|
||||
}
|
||||
if(idx%100 == 99) OS_MutexScopeR(stripe->rw_mutex)
|
||||
{
|
||||
for(FZY_Node *n = slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(u128_match(n->key, key) && n->submit_gen > initial_submit_gen)
|
||||
{
|
||||
task_is_good = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
base_idx += element_count;
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: item list -> item array
|
||||
FZY_ItemArray items = {0};
|
||||
if(task_is_good)
|
||||
{
|
||||
items.count = items_list.total_count;
|
||||
items.v = push_array_no_zero(task_arena, FZY_Item, items.count);
|
||||
U64 idx = 0;
|
||||
for(FZY_ItemChunk *chunk = items_list.first; chunk != 0; chunk = chunk->next)
|
||||
{
|
||||
MemoryCopy(items.v+idx, chunk->v, sizeof(FZY_Item)*chunk->count);
|
||||
idx += chunk->count;
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: sort item array
|
||||
if(items.count != 0 && query.size != 0)
|
||||
{
|
||||
quick_sort(items.v, items.count, sizeof(FZY_Item), fzy_qsort_compare_items);
|
||||
}
|
||||
|
||||
//- rjf: commit to cache - busyloop on scope touches
|
||||
if(task_is_good)
|
||||
{
|
||||
for(B32 done = 0; !done;)
|
||||
{
|
||||
B32 found = 0;
|
||||
OS_MutexScopeW(stripe->rw_mutex) for(FZY_Node *n = slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(u128_match(n->key, key))
|
||||
{
|
||||
if(n->touch_count == 0)
|
||||
{
|
||||
n->gen = initial_submit_gen;
|
||||
n->gen_items = items;
|
||||
done = 1;
|
||||
}
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!found)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
di_scope_close(di_scope);
|
||||
scratch_end(scratch);
|
||||
}
|
||||
}
|
||||
@@ -1,192 +0,0 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef FUZZY_SEARCH_H
|
||||
#define FUZZY_SEARCH_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Result Types
|
||||
|
||||
typedef struct FZY_Item FZY_Item;
|
||||
struct FZY_Item
|
||||
{
|
||||
U64 idx; // indexes into whole space of parameter tables. [rdis[0] element count) [rdis[1] element count) ... [rdis[n] element count)
|
||||
U64 missed_size;
|
||||
FuzzyMatchRangeList match_ranges;
|
||||
};
|
||||
|
||||
typedef struct FZY_ItemChunk FZY_ItemChunk;
|
||||
struct FZY_ItemChunk
|
||||
{
|
||||
FZY_ItemChunk *next;
|
||||
FZY_Item *v;
|
||||
U64 count;
|
||||
U64 cap;
|
||||
};
|
||||
|
||||
typedef struct FZY_ItemChunkList FZY_ItemChunkList;
|
||||
struct FZY_ItemChunkList
|
||||
{
|
||||
FZY_ItemChunk *first;
|
||||
FZY_ItemChunk *last;
|
||||
U64 chunk_count;
|
||||
U64 total_count;
|
||||
};
|
||||
|
||||
typedef struct FZY_ItemArray FZY_ItemArray;
|
||||
struct FZY_ItemArray
|
||||
{
|
||||
FZY_Item *v;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Search Parameter Types
|
||||
|
||||
typedef struct FZY_Params FZY_Params;
|
||||
struct FZY_Params
|
||||
{
|
||||
RDI_SectionKind target;
|
||||
DI_KeyArray dbgi_keys;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cache Types
|
||||
|
||||
typedef struct FZY_Bucket FZY_Bucket;
|
||||
struct FZY_Bucket
|
||||
{
|
||||
Arena *arena;
|
||||
String8 query;
|
||||
FZY_Params params;
|
||||
U64 params_hash;
|
||||
};
|
||||
|
||||
typedef struct FZY_Node FZY_Node;
|
||||
struct FZY_Node
|
||||
{
|
||||
FZY_Node *next;
|
||||
U128 key;
|
||||
U64 touch_count;
|
||||
U64 last_time_submitted_us;
|
||||
FZY_Bucket buckets[3];
|
||||
U64 gen;
|
||||
U64 submit_gen;
|
||||
FZY_ItemArray gen_items;
|
||||
};
|
||||
|
||||
typedef struct FZY_Slot FZY_Slot;
|
||||
struct FZY_Slot
|
||||
{
|
||||
FZY_Node *first;
|
||||
FZY_Node *last;
|
||||
};
|
||||
|
||||
typedef struct FZY_Stripe FZY_Stripe;
|
||||
struct FZY_Stripe
|
||||
{
|
||||
Arena *arena;
|
||||
OS_Handle rw_mutex;
|
||||
OS_Handle cv;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Scoped Access Types
|
||||
|
||||
typedef struct FZY_Touch FZY_Touch;
|
||||
struct FZY_Touch
|
||||
{
|
||||
FZY_Touch *next;
|
||||
FZY_Node *node;
|
||||
};
|
||||
|
||||
typedef struct FZY_Scope FZY_Scope;
|
||||
struct FZY_Scope
|
||||
{
|
||||
FZY_Scope *next;
|
||||
FZY_Touch *first_touch;
|
||||
FZY_Touch *last_touch;
|
||||
};
|
||||
|
||||
typedef struct FZY_TCTX FZY_TCTX;
|
||||
struct FZY_TCTX
|
||||
{
|
||||
Arena *arena;
|
||||
FZY_Scope *free_scope;
|
||||
FZY_Touch *free_touch;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Shared State Types
|
||||
|
||||
typedef struct FZY_Thread FZY_Thread;
|
||||
struct FZY_Thread
|
||||
{
|
||||
OS_Handle thread;
|
||||
OS_Handle u2f_ring_mutex;
|
||||
OS_Handle u2f_ring_cv;
|
||||
U64 u2f_ring_size;
|
||||
U8 *u2f_ring_base;
|
||||
U64 u2f_ring_write_pos;
|
||||
U64 u2f_ring_read_pos;
|
||||
};
|
||||
|
||||
typedef struct FZY_Shared FZY_Shared;
|
||||
struct FZY_Shared
|
||||
{
|
||||
Arena *arena;
|
||||
|
||||
// rjf: search artifact cache table
|
||||
U64 slots_count;
|
||||
U64 stripes_count;
|
||||
FZY_Slot *slots;
|
||||
FZY_Stripe *stripes;
|
||||
|
||||
// rjf: threads
|
||||
U64 thread_count;
|
||||
FZY_Thread *threads;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
global FZY_Shared *fzy_shared = 0;
|
||||
thread_static FZY_TCTX *fzy_tctx = 0;
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Helpers
|
||||
|
||||
internal U64 fzy_hash_from_string(U64 seed, String8 string);
|
||||
internal U64 fzy_hash_from_params(FZY_Params *params);
|
||||
internal U64 fzy_item_num_from_array_element_idx__linear_search(FZY_ItemArray *array, U64 element_idx);
|
||||
internal String8 fzy_item_string_from_rdi_target_element_idx(RDI_Parsed *rdi, RDI_SectionKind target, U64 element_idx);
|
||||
internal FZY_Params fzy_params_copy(Arena *arena, FZY_Params *src);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Main Layer Initialization
|
||||
|
||||
internal void fzy_init(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Scope Functions
|
||||
|
||||
internal FZY_Scope *fzy_scope_open(void);
|
||||
internal void fzy_scope_close(FZY_Scope *scope);
|
||||
internal void fzy_scope_touch_node__stripe_mutex_r_guarded(FZY_Scope *scope, FZY_Node *node);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cache Lookup Functions
|
||||
|
||||
internal FZY_ItemArray fzy_items_from_key_params_query(FZY_Scope *scope, U128 key, FZY_Params *params, String8 query, U64 endt_us, B32 *stale_out);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Searcher Threads
|
||||
|
||||
internal B32 fzy_u2s_enqueue_req(U128 key, U64 endt_us);
|
||||
internal void fzy_u2s_dequeue_req(Arena *arena, FZY_Thread *thread, U128 *key_out);
|
||||
|
||||
internal int fzy_qsort_compare_items(FZY_Item *a, FZY_Item *b);
|
||||
|
||||
internal void fzy_search_thread__entry_point(void *p);
|
||||
|
||||
#endif // FUZZY_SEARCH_H
|
||||
+58
-78
@@ -25,12 +25,6 @@ geo_init(void)
|
||||
geo_shared->u2x_ring_base = push_array_no_zero(arena, U8, geo_shared->u2x_ring_size);
|
||||
geo_shared->u2x_ring_cv = os_condition_variable_alloc();
|
||||
geo_shared->u2x_ring_mutex = os_mutex_alloc();
|
||||
geo_shared->xfer_thread_count = Clamp(1, os_get_system_info()->logical_processor_count-1, 4);
|
||||
geo_shared->xfer_threads = push_array(arena, OS_Handle, geo_shared->xfer_thread_count);
|
||||
for(U64 idx = 0; idx < geo_shared->xfer_thread_count; idx += 1)
|
||||
{
|
||||
geo_shared->xfer_threads[idx] = os_thread_launch(geo_xfer_thread__entry_point, (void *)idx, 0);
|
||||
}
|
||||
geo_shared->evictor_thread = os_thread_launch(geo_evictor_thread__entry_point, 0, 0);
|
||||
}
|
||||
|
||||
@@ -48,21 +42,6 @@ geo_tctx_ensure_inited(void)
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: User Clock
|
||||
|
||||
internal void
|
||||
geo_user_clock_tick(void)
|
||||
{
|
||||
ins_atomic_u64_inc_eval(&geo_shared->user_clock_idx);
|
||||
}
|
||||
|
||||
internal U64
|
||||
geo_user_clock_idx(void)
|
||||
{
|
||||
return ins_atomic_u64_eval(&geo_shared->user_clock_idx);
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Scoped Access
|
||||
|
||||
@@ -116,7 +95,7 @@ geo_scope_touch_node__stripe_r_guarded(GEO_Scope *scope, GEO_Node *node)
|
||||
GEO_Touch *touch = geo_tctx->free_touch;
|
||||
ins_atomic_u64_inc_eval(&node->scope_ref_count);
|
||||
ins_atomic_u64_eval_assign(&node->last_time_touched_us, os_now_microseconds());
|
||||
ins_atomic_u64_eval_assign(&node->last_user_clock_idx_touched, geo_user_clock_idx());
|
||||
ins_atomic_u64_eval_assign(&node->last_user_clock_idx_touched, update_tick_idx());
|
||||
if(touch != 0)
|
||||
{
|
||||
SLLStackPop(geo_tctx->free_touch);
|
||||
@@ -192,6 +171,7 @@ geo_buffer_from_hash(GEO_Scope *scope, U128 hash)
|
||||
if(node_is_new)
|
||||
{
|
||||
geo_u2x_enqueue_req(hash, max_U64);
|
||||
async_push_work(geo_xfer_work);
|
||||
}
|
||||
}
|
||||
return handle;
|
||||
@@ -259,68 +239,67 @@ geo_u2x_dequeue_req(U128 *hash_out)
|
||||
os_condition_variable_broadcast(geo_shared->u2x_ring_cv);
|
||||
}
|
||||
|
||||
internal void
|
||||
geo_xfer_thread__entry_point(void *p)
|
||||
ASYNC_WORK_DEF(geo_xfer_work)
|
||||
{
|
||||
for(;;)
|
||||
ProfBeginFunction();
|
||||
HS_Scope *scope = hs_scope_open();
|
||||
|
||||
//- rjf: decode
|
||||
U128 hash = {0};
|
||||
geo_u2x_dequeue_req(&hash);
|
||||
|
||||
//- rjf: unpack hash
|
||||
U64 slot_idx = hash.u64[1]%geo_shared->slots_count;
|
||||
U64 stripe_idx = slot_idx%geo_shared->stripes_count;
|
||||
GEO_Slot *slot = &geo_shared->slots[slot_idx];
|
||||
GEO_Stripe *stripe = &geo_shared->stripes[stripe_idx];
|
||||
|
||||
//- rjf: take task
|
||||
B32 got_task = 0;
|
||||
OS_MutexScopeR(stripe->rw_mutex)
|
||||
{
|
||||
HS_Scope *scope = hs_scope_open();
|
||||
|
||||
//- rjf: decode
|
||||
U128 hash = {0};
|
||||
geo_u2x_dequeue_req(&hash);
|
||||
|
||||
//- rjf: unpack hash
|
||||
U64 slot_idx = hash.u64[1]%geo_shared->slots_count;
|
||||
U64 stripe_idx = slot_idx%geo_shared->stripes_count;
|
||||
GEO_Slot *slot = &geo_shared->slots[slot_idx];
|
||||
GEO_Stripe *stripe = &geo_shared->stripes[stripe_idx];
|
||||
|
||||
//- rjf: take task
|
||||
B32 got_task = 0;
|
||||
OS_MutexScopeR(stripe->rw_mutex)
|
||||
for(GEO_Node *n = slot->first; n != 0; n = n->next)
|
||||
{
|
||||
for(GEO_Node *n = slot->first; n != 0; n = n->next)
|
||||
if(u128_match(n->hash, hash))
|
||||
{
|
||||
if(u128_match(n->hash, hash))
|
||||
{
|
||||
got_task = !ins_atomic_u32_eval_cond_assign(&n->is_working, 1, 0);
|
||||
break;
|
||||
}
|
||||
got_task = !ins_atomic_u32_eval_cond_assign(&n->is_working, 1, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: hash -> data
|
||||
String8 data = {0};
|
||||
if(got_task)
|
||||
{
|
||||
data = hs_data_from_hash(scope, hash);
|
||||
}
|
||||
|
||||
//- rjf: data -> buffer
|
||||
R_Handle buffer = {0};
|
||||
if(got_task && data.size != 0)
|
||||
{
|
||||
buffer = r_buffer_alloc(R_ResourceKind_Static, data.size, data.str);
|
||||
}
|
||||
|
||||
//- rjf: commit results to cache
|
||||
if(got_task) OS_MutexScopeW(stripe->rw_mutex)
|
||||
{
|
||||
for(GEO_Node *n = slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(u128_match(n->hash, hash))
|
||||
{
|
||||
n->buffer = buffer;
|
||||
ins_atomic_u32_eval_assign(&n->is_working, 0);
|
||||
ins_atomic_u64_inc_eval(&n->load_count);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hs_scope_close(scope);
|
||||
}
|
||||
|
||||
//- rjf: hash -> data
|
||||
String8 data = {0};
|
||||
if(got_task)
|
||||
{
|
||||
data = hs_data_from_hash(scope, hash);
|
||||
}
|
||||
|
||||
//- rjf: data -> buffer
|
||||
R_Handle buffer = {0};
|
||||
if(got_task && data.size != 0)
|
||||
{
|
||||
buffer = r_buffer_alloc(R_ResourceKind_Static, data.size, data.str);
|
||||
}
|
||||
|
||||
//- rjf: commit results to cache
|
||||
if(got_task) OS_MutexScopeW(stripe->rw_mutex)
|
||||
{
|
||||
for(GEO_Node *n = slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(u128_match(n->hash, hash))
|
||||
{
|
||||
n->buffer = buffer;
|
||||
ins_atomic_u32_eval_assign(&n->is_working, 0);
|
||||
ins_atomic_u64_inc_eval(&n->load_count);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hs_scope_close(scope);
|
||||
ProfEnd();
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
@@ -329,10 +308,11 @@ geo_xfer_thread__entry_point(void *p)
|
||||
internal void
|
||||
geo_evictor_thread__entry_point(void *p)
|
||||
{
|
||||
ThreadNameF("[geo] evictor thread");
|
||||
for(;;)
|
||||
{
|
||||
U64 check_time_us = os_now_microseconds();
|
||||
U64 check_time_user_clocks = geo_user_clock_idx();
|
||||
U64 check_time_user_clocks = update_tick_idx();
|
||||
U64 evict_threshold_us = 10*1000000;
|
||||
U64 evict_threshold_user_clocks = 10;
|
||||
for(U64 slot_idx = 0; slot_idx < geo_shared->slots_count; slot_idx += 1)
|
||||
|
||||
@@ -72,9 +72,6 @@ struct GEO_Shared
|
||||
{
|
||||
Arena *arena;
|
||||
|
||||
// rjf: user clock
|
||||
U64 user_clock_idx;
|
||||
|
||||
// rjf: cache
|
||||
U64 slots_count;
|
||||
U64 stripes_count;
|
||||
@@ -90,10 +87,6 @@ struct GEO_Shared
|
||||
OS_Handle u2x_ring_cv;
|
||||
OS_Handle u2x_ring_mutex;
|
||||
|
||||
// rjf: transfer threads
|
||||
U64 xfer_thread_count;
|
||||
OS_Handle *xfer_threads;
|
||||
|
||||
// rjf: evictor thread
|
||||
OS_Handle evictor_thread;
|
||||
};
|
||||
@@ -114,12 +107,6 @@ internal void geo_init(void);
|
||||
|
||||
internal void geo_tctx_ensure_inited(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: User Clock
|
||||
|
||||
internal void geo_user_clock_tick(void);
|
||||
internal U64 geo_user_clock_idx(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Scoped Access
|
||||
|
||||
@@ -138,7 +125,7 @@ internal R_Handle geo_buffer_from_key(GEO_Scope *scope, U128 key);
|
||||
|
||||
internal B32 geo_u2x_enqueue_req(U128 hash, U64 endt_us);
|
||||
internal void geo_u2x_dequeue_req(U128 *hash_out);
|
||||
internal void geo_xfer_thread__entry_point(void *p);
|
||||
ASYNC_WORK_DEF(geo_xfer_work);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Evictor Threads
|
||||
|
||||
@@ -14,10 +14,7 @@ internal U128
|
||||
hs_hash_from_data(String8 data)
|
||||
{
|
||||
U128 u128 = {0};
|
||||
if(data.size != 0)
|
||||
{
|
||||
blake2b((U8 *)&u128.u64[0], sizeof(u128), data.str, data.size, 0, 0);
|
||||
}
|
||||
blake2b((U8 *)&u128.u64[0], sizeof(u128), data.str, data.size, 0, 0);
|
||||
return u128;
|
||||
}
|
||||
|
||||
@@ -299,6 +296,7 @@ hs_data_from_hash(HS_Scope *scope, U128 hash)
|
||||
internal void
|
||||
hs_evictor_thread__entry_point(void *p)
|
||||
{
|
||||
ThreadNameF("[hs] evictor thread");
|
||||
for(;;)
|
||||
{
|
||||
for(U64 slot_idx = 0; slot_idx < hs_shared->slots_count; slot_idx += 1)
|
||||
|
||||
@@ -589,6 +589,172 @@ X(NULL)\
|
||||
X(X86)\
|
||||
X(X64)\
|
||||
|
||||
#define RDI_RegCodeX86_XList \
|
||||
X(nil, 0)\
|
||||
X(eax, 1)\
|
||||
X(ecx, 2)\
|
||||
X(edx, 3)\
|
||||
X(ebx, 4)\
|
||||
X(esp, 5)\
|
||||
X(ebp, 6)\
|
||||
X(esi, 7)\
|
||||
X(edi, 8)\
|
||||
X(fsbase, 9)\
|
||||
X(gsbase, 10)\
|
||||
X(eflags, 11)\
|
||||
X(eip, 12)\
|
||||
X(dr0, 13)\
|
||||
X(dr1, 14)\
|
||||
X(dr2, 15)\
|
||||
X(dr3, 16)\
|
||||
X(dr4, 17)\
|
||||
X(dr5, 18)\
|
||||
X(dr6, 19)\
|
||||
X(dr7, 20)\
|
||||
X(fpr0, 21)\
|
||||
X(fpr1, 22)\
|
||||
X(fpr2, 23)\
|
||||
X(fpr3, 24)\
|
||||
X(fpr4, 25)\
|
||||
X(fpr5, 26)\
|
||||
X(fpr6, 27)\
|
||||
X(fpr7, 28)\
|
||||
X(st0, 29)\
|
||||
X(st1, 30)\
|
||||
X(st2, 31)\
|
||||
X(st3, 32)\
|
||||
X(st4, 33)\
|
||||
X(st5, 34)\
|
||||
X(st6, 35)\
|
||||
X(st7, 36)\
|
||||
X(fcw, 37)\
|
||||
X(fsw, 38)\
|
||||
X(ftw, 39)\
|
||||
X(fop, 40)\
|
||||
X(fcs, 41)\
|
||||
X(fds, 42)\
|
||||
X(fip, 43)\
|
||||
X(fdp, 44)\
|
||||
X(mxcsr, 45)\
|
||||
X(mxcsr_mask, 46)\
|
||||
X(ss, 47)\
|
||||
X(cs, 48)\
|
||||
X(ds, 49)\
|
||||
X(es, 50)\
|
||||
X(fs, 51)\
|
||||
X(gs, 52)\
|
||||
X(ymm0, 53)\
|
||||
X(ymm1, 54)\
|
||||
X(ymm2, 55)\
|
||||
X(ymm3, 56)\
|
||||
X(ymm4, 57)\
|
||||
X(ymm5, 58)\
|
||||
X(ymm6, 59)\
|
||||
X(ymm7, 60)\
|
||||
|
||||
#define RDI_RegCodeX64_XList \
|
||||
X(nil, 0)\
|
||||
X(rax, 1)\
|
||||
X(rcx, 2)\
|
||||
X(rdx, 3)\
|
||||
X(rbx, 4)\
|
||||
X(rsp, 5)\
|
||||
X(rbp, 6)\
|
||||
X(rsi, 7)\
|
||||
X(rdi, 8)\
|
||||
X(r8, 9)\
|
||||
X(r9, 10)\
|
||||
X(r10, 11)\
|
||||
X(r11, 12)\
|
||||
X(r12, 13)\
|
||||
X(r13, 14)\
|
||||
X(r14, 15)\
|
||||
X(r15, 16)\
|
||||
X(es, 17)\
|
||||
X(cs, 18)\
|
||||
X(ss, 19)\
|
||||
X(ds, 20)\
|
||||
X(fs, 21)\
|
||||
X(gs, 22)\
|
||||
X(rip, 23)\
|
||||
X(rflags, 24)\
|
||||
X(dr0, 25)\
|
||||
X(dr1, 26)\
|
||||
X(dr2, 27)\
|
||||
X(dr3, 28)\
|
||||
X(dr4, 29)\
|
||||
X(dr5, 30)\
|
||||
X(dr6, 31)\
|
||||
X(dr7, 32)\
|
||||
X(st0, 33)\
|
||||
X(st1, 34)\
|
||||
X(st2, 35)\
|
||||
X(st3, 36)\
|
||||
X(st4, 37)\
|
||||
X(st5, 38)\
|
||||
X(st6, 39)\
|
||||
X(st7, 40)\
|
||||
X(fpr0, 41)\
|
||||
X(fpr1, 42)\
|
||||
X(fpr2, 43)\
|
||||
X(fpr3, 44)\
|
||||
X(fpr4, 45)\
|
||||
X(fpr5, 46)\
|
||||
X(fpr6, 47)\
|
||||
X(fpr7, 48)\
|
||||
X(zmm0, 49)\
|
||||
X(zmm1, 50)\
|
||||
X(zmm2, 51)\
|
||||
X(zmm3, 52)\
|
||||
X(zmm4, 53)\
|
||||
X(zmm5, 54)\
|
||||
X(zmm6, 55)\
|
||||
X(zmm7, 56)\
|
||||
X(zmm8, 57)\
|
||||
X(zmm9, 58)\
|
||||
X(zmm10, 59)\
|
||||
X(zmm11, 60)\
|
||||
X(zmm12, 61)\
|
||||
X(zmm13, 62)\
|
||||
X(zmm14, 63)\
|
||||
X(zmm15, 64)\
|
||||
X(zmm16, 65)\
|
||||
X(zmm17, 66)\
|
||||
X(zmm18, 67)\
|
||||
X(zmm19, 68)\
|
||||
X(zmm20, 69)\
|
||||
X(zmm21, 70)\
|
||||
X(zmm22, 71)\
|
||||
X(zmm23, 72)\
|
||||
X(zmm24, 73)\
|
||||
X(zmm25, 74)\
|
||||
X(zmm26, 75)\
|
||||
X(zmm27, 76)\
|
||||
X(zmm28, 77)\
|
||||
X(zmm29, 78)\
|
||||
X(zmm30, 79)\
|
||||
X(zmm31, 80)\
|
||||
X(k0, 81)\
|
||||
X(k1, 82)\
|
||||
X(k2, 83)\
|
||||
X(k3, 84)\
|
||||
X(k4, 85)\
|
||||
X(k5, 86)\
|
||||
X(k6, 87)\
|
||||
X(k7, 88)\
|
||||
X(mxcsr, 89)\
|
||||
X(fsbase, 90)\
|
||||
X(gsbase, 91)\
|
||||
X(fcw, 92)\
|
||||
X(fsw, 93)\
|
||||
X(ftw, 94)\
|
||||
X(fop, 95)\
|
||||
X(fcs, 96)\
|
||||
X(fds, 97)\
|
||||
X(fip, 98)\
|
||||
X(fdp, 99)\
|
||||
X(mxcsr_mask, 100)\
|
||||
|
||||
#define RDI_TopLevelInfo_XList \
|
||||
X(RDI_Arch, arch)\
|
||||
X(RDI_U32, exe_name_string_idx)\
|
||||
|
||||
@@ -303,9 +303,9 @@ 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_U64 idx = 0; idx < count && result+idx < line_info->count; idx += 1)
|
||||
for(RDI_S64 idx = count-1; idx >= 0; idx -= 1)
|
||||
{
|
||||
if(line_info->lines[result+idx].file_idx != 0)
|
||||
if(result + idx < line_info->count && line_info->lines[result+idx].file_idx != 0)
|
||||
{
|
||||
result += idx;
|
||||
break;
|
||||
|
||||
@@ -23,16 +23,6 @@
|
||||
|
||||
#define BitExtract(x, count, shift) (((x) >> (shift)) & ((1 << (count)) - 1))
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
#if OS_WINDOWS
|
||||
# define ins_atomic_ptr_eval_cond_assign(x,k,c) InterlockedCompareExchangePointer((volatile PVOID *)(x),(k),(c))
|
||||
# define ins_atomic_u32_add_eval(x,c) InterlockedAdd((volatile LONG *)(x), c)
|
||||
# define ins_atomic_u32_inc_eval(x) InterlockedIncrement((volatile LONG *)x)
|
||||
#else
|
||||
# error "atomics are not defined for this system"
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
// Linked List Helpers
|
||||
|
||||
|
||||
@@ -1,33 +1,6 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
global read_only String8 g_null_string;
|
||||
|
||||
internal String8
|
||||
str8_cstring_capped_reverse(void *start, void *cap)
|
||||
{
|
||||
char *ptr = cap;
|
||||
while (ptr > (char *)start) {
|
||||
--ptr;
|
||||
if (*ptr == '\0') break;
|
||||
}
|
||||
U64 null_offset = (U64)(ptr - (char *) start);
|
||||
String8 result = str8((U8 *) start, null_offset);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal U64
|
||||
str8_find_needle_reverse(String8 string, U64 start_pos, String8 needle, StringMatchFlags flags)
|
||||
{
|
||||
for (S64 i = string.size - start_pos - needle.size; i >= 0; --i) {
|
||||
String8 haystack = str8_substr(string, rng_1u64(i, i + needle.size));
|
||||
if (str8_match(haystack, needle, flags)) {
|
||||
return (U64)i + needle.size;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
internal int
|
||||
str8_compar(String8 a, String8 b, B32 ignore_case)
|
||||
{
|
||||
@@ -76,15 +49,15 @@ str8_compar_ignore_case(const void *a, const void *b)
|
||||
}
|
||||
|
||||
internal int
|
||||
str8_compar_case_sensetive(const void *a, const void *b)
|
||||
str8_compar_case_sensitive(const void *a, const void *b)
|
||||
{
|
||||
return str8_compar(*(String8*)a, *(String8*)b, 0);
|
||||
}
|
||||
|
||||
internal int
|
||||
str8_is_before_case_sensetive(const void *a, const void *b)
|
||||
str8_is_before_case_sensitive(const void *a, const void *b)
|
||||
{
|
||||
int cmp = str8_compar_case_sensetive(a, b);
|
||||
int cmp = str8_compar_case_sensitive(a, b);
|
||||
return cmp < 0;
|
||||
}
|
||||
|
||||
@@ -136,46 +109,6 @@ str8_list_push_many(Arena *arena, String8List *list, U64 count)
|
||||
return arr;
|
||||
}
|
||||
|
||||
internal String8
|
||||
str8_from_bits_u32(Arena *arena, U32 x)
|
||||
{
|
||||
U8 c0 = 'a' + ((x >> 28) & 0xf);
|
||||
U8 c1 = 'a' + ((x >> 24) & 0xf);
|
||||
U8 c2 = 'a' + ((x >> 20) & 0xf);
|
||||
U8 c3 = 'a' + ((x >> 16) & 0xf);
|
||||
U8 c4 = 'a' + ((x >> 12) & 0xf);
|
||||
U8 c5 = 'a' + ((x >> 8) & 0xf);
|
||||
U8 c6 = 'a' + ((x >> 4) & 0xf);
|
||||
U8 c7 = 'a' + ((x >> 0) & 0xf);
|
||||
String8 result = push_str8f(arena, "%c%c%c%c%c%c%c%c", c0, c1, c2, c3, c4, c5, c6, c7);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String8
|
||||
str8_from_bits_u64(Arena *arena, U64 x)
|
||||
{
|
||||
U8 c0 = 'a' + ((x >> 60) & 0xf);
|
||||
U8 c1 = 'a' + ((x >> 56) & 0xf);
|
||||
U8 c2 = 'a' + ((x >> 52) & 0xf);
|
||||
U8 c3 = 'a' + ((x >> 48) & 0xf);
|
||||
U8 c4 = 'a' + ((x >> 44) & 0xf);
|
||||
U8 c5 = 'a' + ((x >> 40) & 0xf);
|
||||
U8 c6 = 'a' + ((x >> 36) & 0xf);
|
||||
U8 c7 = 'a' + ((x >> 32) & 0xf);
|
||||
U8 c8 = 'a' + ((x >> 28) & 0xf);
|
||||
U8 c9 = 'a' + ((x >> 24) & 0xf);
|
||||
U8 ca = 'a' + ((x >> 20) & 0xf);
|
||||
U8 cb = 'a' + ((x >> 16) & 0xf);
|
||||
U8 cc = 'a' + ((x >> 12) & 0xf);
|
||||
U8 cd = 'a' + ((x >> 8) & 0xf);
|
||||
U8 ce = 'a' + ((x >> 4) & 0xf);
|
||||
U8 cf = 'a' + ((x >> 0) & 0xf);
|
||||
String8 result = push_str8f(arena,
|
||||
"%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c",
|
||||
c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, ca, cb, cc, cd, ce, cf);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String8Node *
|
||||
str8_list_pop_front(String8List *list)
|
||||
{
|
||||
@@ -190,55 +123,6 @@ str8_list_pop_front(String8List *list)
|
||||
return node;
|
||||
}
|
||||
|
||||
internal String8
|
||||
str8_from_memory_size2(Arena *arena, U64 size)
|
||||
{
|
||||
String8 result;
|
||||
if (size < KB(1)) {
|
||||
result = push_str8f(arena, "%llu Bytes", size);
|
||||
} else if (size < MB(1)) {
|
||||
result = push_str8f(arena, "%llu.%02llu KiB", size / KB(1), ((size * 100) / KB(1)) % 100);
|
||||
} else if (size < GB(1)) {
|
||||
result = push_str8f(arena, "%llu.%02llu MiB", size / MB(1), ((size * 100) / MB(1)) % 100);
|
||||
} else if (size < TB(1)) {
|
||||
result = push_str8f(arena, "%llu.%02llu GiB", size / GB(1), ((size * 100) / GB(1)) % 100);
|
||||
} else {
|
||||
result = push_str8f(arena, "%llu.%02llu TiB", size / TB(1), ((size * 100) / TB(1)) % 100);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String8
|
||||
str8_from_count(Arena *arena, U64 count)
|
||||
{
|
||||
String8 result;
|
||||
if (count < 1000) {
|
||||
result = push_str8f(arena, "%llu", count);
|
||||
} else if (count < 1000000) {
|
||||
U64 frac = ((count * 100) / 1000) % 100;
|
||||
if (frac) {
|
||||
result = push_str8f(arena, "%llu.%02lluK", count / 1000, frac);
|
||||
} else {
|
||||
result = push_str8f(arena, "%lluK", count / 1000);
|
||||
}
|
||||
} else if (count < 1000000000) {
|
||||
U64 frac = ((count * 100) / 1000000) % 100;
|
||||
if (frac) {
|
||||
result = push_str8f(arena, "%llu.%02lluM", count / 1000000, frac);
|
||||
} else {
|
||||
result = push_str8f(arena, "%lluM", count / 1000000);
|
||||
}
|
||||
} else {
|
||||
U64 frac = ((count * 100) * 1000000000) % 100;
|
||||
if (frac) {
|
||||
result = push_str8f(arena, "%llu.%02lluB", count / 1000000000, frac);
|
||||
} else {
|
||||
result = push_str8f(arena, "%lluB", count / 1000000000, frac);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal U64
|
||||
hash_from_str8(String8 string)
|
||||
{
|
||||
|
||||
@@ -5,13 +5,9 @@
|
||||
|
||||
#define MemoryCopyStr8(dst, s) MemoryCopy(dst, (s).str, (s).size)
|
||||
|
||||
internal String8 str8_cstring_capped_reverse(void *start, void *cap);
|
||||
|
||||
internal U64 str8_find_needle_reverse(String8 string, U64 start_pos, String8 needle, StringMatchFlags flags);
|
||||
|
||||
internal int str8_compar(String8 a, String8 b, B32 ignore_case);
|
||||
internal int str8_compar_ignore_case(const void *a, const void *b);
|
||||
internal int str8_compar_case_sensetive(const void *a, const void *b);
|
||||
internal int str8_compar_case_sensitive(const void *a, const void *b);
|
||||
|
||||
#define str8_list_push_struct(a,l,d) str8_list_push_raw(a, l, d, sizeof(*d))
|
||||
internal String8Node * str8_list_push_raw(Arena *arena, String8List *list, void *data_ptr, U64 data_size);
|
||||
@@ -20,14 +16,8 @@ internal U64 str8_list_push_pad_front(Arena *arena, String8List *list,
|
||||
internal String8List str8_list_arr_concat(String8List *v, U64 count);
|
||||
internal String8Node * str8_list_push_many(Arena *arena, String8List *list, U64 count);
|
||||
|
||||
internal String8 str8_from_bits_u32(Arena *arena, U32 x);
|
||||
internal String8 str8_from_bits_u64(Arena *arena, U64 x);
|
||||
|
||||
// TODO: remove
|
||||
internal String8Node * str8_list_pop_front(String8List *list);
|
||||
|
||||
internal String8 str8_from_memory_size2(Arena *arena, U64 size);
|
||||
internal String8 str8_from_count(Arena *arena, U64 count);
|
||||
|
||||
internal U64 hash_from_str8(String8 string);
|
||||
|
||||
|
||||
@@ -1628,7 +1628,7 @@ cv_string_hash_table_lookup(CV_StringHashTable ht, String8 string)
|
||||
return ht.buckets[idx];
|
||||
}
|
||||
|
||||
idx = (idx + 1 % ht.bucket_cap);
|
||||
idx = (idx + 1) % ht.bucket_cap;
|
||||
} while (idx != best_idx);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -208,7 +208,7 @@ typedef struct CV_UDTInfo
|
||||
typedef struct CV_TypeServerInfo
|
||||
{
|
||||
String8 name;
|
||||
OS_Guid sig;
|
||||
Guid sig;
|
||||
U32 age;
|
||||
} CV_TypeServerInfo;
|
||||
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||
<Type Name="LNK_Section">
|
||||
<DisplayString>{{ name={name} flags={flags} id={id} sort_index={sort_index} }}</DisplayString>
|
||||
</Type>
|
||||
|
||||
<Type Name="U32Array">
|
||||
<AlternativeType Name="U64Array"/>
|
||||
<Expand>
|
||||
<Item Name="[count]">count</Item>
|
||||
<ArrayItems>
|
||||
<Size>count</Size>
|
||||
<ValuePointer>v</ValuePointer>
|
||||
</ArrayItems>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="LNK_SymbolList">
|
||||
<AlternativeType Name="LNK_SectionList"/>
|
||||
<AlternativeType Name="LNK_ChunkList"/>
|
||||
<AlternativeType Name="CV_SymbolList"/>
|
||||
<DisplayString>{{count={count} first={first} last={last} }}</DisplayString>
|
||||
<Expand>
|
||||
<LinkedListItems>
|
||||
<Size>count</Size>
|
||||
<HeadPointer>first</HeadPointer>
|
||||
<NextPointer>next</NextPointer>
|
||||
<ValueNode>data</ValueNode>
|
||||
</LinkedListItems>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="Rng1U64List">
|
||||
<DisplayString>{{count={count} first={first} last={last} }}</DisplayString>
|
||||
<Expand>
|
||||
<LinkedListItems>
|
||||
<Size>count</Size>
|
||||
<HeadPointer>first</HeadPointer>
|
||||
<NextPointer>next</NextPointer>
|
||||
<ValueNode>v</ValueNode>
|
||||
</LinkedListItems>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="RDIB_LineTable">
|
||||
<DisplayString>{{count={count} first={first} last={last} }}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[count]">count</Item>
|
||||
<LinkedListItems>
|
||||
<Size>count</Size>
|
||||
<HeadPointer>first</HeadPointer>
|
||||
<NextPointer>next_line_table</NextPointer>
|
||||
<ValueNode>this</ValueNode>
|
||||
</LinkedListItems>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="RDIB_VariableChunkList">
|
||||
<AlternativeType Name="RDIB_UnitChunkList"/>
|
||||
<AlternativeType Name="RDIB_LineTableChunkList"/>
|
||||
<AlternativeType Name="RDIB_SourceFileChunkList"/>
|
||||
<AlternativeType Name="RDIB_ProcedureChunkList"/>
|
||||
<AlternativeType Name="RDIB_ScopeChunkList"/>
|
||||
<AlternativeType Name="RDIB_InlineSiteChunkList"/>
|
||||
<AlternativeType Name="RDIB_UDTMemberChunkList"/>
|
||||
<AlternativeType Name="RDIB_TypeChunkList"/>
|
||||
<Expand>
|
||||
<Item Name="[chunk count]">count</Item>
|
||||
<CustomListItems MaxItemsPerView="5000">
|
||||
<Variable Name="node" InitialValue="first"/>
|
||||
<Variable Name="idx" InitialValue="0"/>
|
||||
<Loop>
|
||||
<Break Condition="node == 0"/>
|
||||
<Exec>idx = 0</Exec>
|
||||
<Loop>
|
||||
<Break Condition="idx >= node->count"/>
|
||||
<Item>node->v[idx]</Item>
|
||||
<Exec>idx += 1</Exec>
|
||||
</Loop>
|
||||
<Exec>node = node->next</Exec>
|
||||
</Loop>
|
||||
</CustomListItems>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="RDIB_VariableChunk">
|
||||
<AlternativeType Name="RDIB_UnitChunk"/>
|
||||
<AlternativeType Name="RDIB_LineTableChunk"/>
|
||||
<AlternativeType Name="RDIB_SourceFileChunk"/>
|
||||
<AlternativeType Name="RDIB_ProcedureChunk"/>
|
||||
<AlternativeType Name="RDIB_ScopeChunk"/>
|
||||
<AlternativeType Name="RDIB_InlineSiteChunk"/>
|
||||
<AlternativeType Name="RDIB_UDTMemberChunk"/>
|
||||
<AlternativeType Name="RDIB_TypeChunk"/>
|
||||
<DisplayString>{count,cap,v}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[base]">base</Item>
|
||||
<Item Name="[count]">count</Item>
|
||||
<Item Name="[cap]">cap</Item>
|
||||
<ArrayItems>
|
||||
<Size>count</Size>
|
||||
<ValuePointer>v</ValuePointer>
|
||||
</ArrayItems>
|
||||
</Expand>
|
||||
</Type>
|
||||
</AutoVisualizer>
|
||||
|
||||
+1435
-1705
File diff suppressed because it is too large
Load Diff
+25
-19
@@ -172,13 +172,6 @@ typedef struct
|
||||
HashTable **page_ht_arr;
|
||||
} LNK_ObjBaseRelocTask;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Rng1U64 *range_arr;
|
||||
LNK_LibNode *lib_arr;
|
||||
LNK_Symbol **symbol_arr_arr;
|
||||
} LNK_LazyIniter;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
LNK_InputObjList input_obj_list;
|
||||
@@ -197,6 +190,16 @@ typedef struct
|
||||
|
||||
typedef struct
|
||||
{
|
||||
LNK_SymbolTable *symtab;
|
||||
union {
|
||||
LNK_ObjNodeArray objs;
|
||||
LNK_LibNodeArray libs;
|
||||
} u;
|
||||
} LNK_SymbolPusher;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
String8 image_data;
|
||||
LNK_SymbolTable *symtab;
|
||||
LNK_SectionTable *st;
|
||||
LNK_Section **sect_id_map;
|
||||
@@ -207,6 +210,7 @@ typedef struct
|
||||
|
||||
typedef struct
|
||||
{
|
||||
String8 image_data;
|
||||
LNK_SymbolTable *symtab;
|
||||
LNK_SectionTable *st;
|
||||
LNK_Section **sect_id_map;
|
||||
@@ -214,7 +218,6 @@ typedef struct
|
||||
LNK_Obj **obj_arr;
|
||||
} LNK_ObjRelocPatcher;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
String8 path;
|
||||
@@ -238,23 +241,19 @@ internal LNK_InputImportList lnk_list_from_input_import_arr(LNK_InputImport **ar
|
||||
////////////////////////////////
|
||||
// Helpers
|
||||
|
||||
internal void lnk_write_data_list_to_file_path(String8 path, String8List list);
|
||||
internal void lnk_write_data_to_file_path(String8 path, String8 data);
|
||||
|
||||
internal String8 lnk_make_full_path(Arena *arena, String8 work_dir, PathStyle system_path_style, String8 path);
|
||||
|
||||
internal String8 lnk_get_lib_name(String8 path);
|
||||
internal B32 lnk_is_lib_disallowed(HashTable *disallow_lib_ht, String8 path);
|
||||
internal B32 lnk_is_lib_loaded(HashTable *default_lib_ht, HashTable *loaded_lib_ht, LNK_InputSourceType input_source, String8 lib_path);
|
||||
internal B32 lnk_is_lib_loaded(HashTable *loaded_lib_ht, String8 lib_path);
|
||||
internal void lnk_push_disallow_lib(Arena *arena, HashTable *disallow_lib_ht, String8 path);
|
||||
internal void lnk_push_loaded_lib(Arena *arena, HashTable *default_lib_ht, HashTable *loaded_lib_ht, String8 path);
|
||||
internal void lnk_push_loaded_lib(Arena *arena, HashTable *loaded_lib_ht, String8 path);
|
||||
|
||||
////////////////////////////////
|
||||
// Manifest
|
||||
|
||||
internal String8List lnk_make_linker_manifest(Arena *arena, B32 manifest_uac, String8 manifest_level, String8 manifest_ui_access, String8List manifest_dependency_list);
|
||||
internal void lnk_merge_manifest_files(Arena *arena, String8 mt_path, String8 manifest_name, String8List manifest_path_list);
|
||||
internal String8 lnk_res_from_data(Arena *arena, String8 data);
|
||||
internal String8 lnk_make_linker_manifest(Arena *arena, B32 manifest_uac, String8 manifest_level, String8 manifest_ui_access, String8List manifest_dependency_list);
|
||||
internal void lnk_merge_manifest_files(String8 mt_path, String8 out_name, String8List manifest_path_list);
|
||||
|
||||
////////////////////////////////
|
||||
// Resources
|
||||
@@ -272,8 +271,8 @@ internal String8 lnk_make_linker_coff_obj(TP_Context *tp, Arena *arena, COFF_Tim
|
||||
////////////////////////////////
|
||||
// Win32 Image Helpers
|
||||
|
||||
internal void lnk_build_debug_pdb(LNK_SectionTable *st, LNK_SymbolTable *symtab, LNK_Section *debug_sect, LNK_Chunk *debug_dir_array_chunk, COFF_TimeStamp time_stamp, OS_Guid guid, U32 age, String8 pdb_path);
|
||||
internal void lnk_build_debug_rdi(LNK_SectionTable *st, LNK_SymbolTable *symtab, LNK_Section *debug_sect, LNK_Chunk *debug_dir_array_chunk, COFF_TimeStamp time_stamp, OS_Guid guid, String8 rdi_path);
|
||||
internal void lnk_build_debug_pdb(LNK_SectionTable *st, LNK_SymbolTable *symtab, LNK_Section *debug_sect, LNK_Chunk *debug_dir_array_chunk, COFF_TimeStamp time_stamp, Guid guid, U32 age, String8 pdb_path);
|
||||
internal void lnk_build_debug_rdi(LNK_SectionTable *st, LNK_SymbolTable *symtab, LNK_Section *debug_sect, LNK_Chunk *debug_dir_array_chunk, COFF_TimeStamp time_stamp, Guid guid, String8 rdi_path);
|
||||
internal void lnk_build_guard_tables(TP_Context *tp, LNK_SectionTable *st, LNK_SymbolTable *symtab, LNK_ExportTable *exptab, LNK_ObjList obj_list, COFF_MachineType machine, String8 entry_point_name, LNK_GuardFlags guard_flags, B32 emit_suppress_flag);
|
||||
internal void lnk_build_base_relocs(TP_Context *tp, TP_Arena *tp_arena, LNK_SectionTable *st, LNK_SymbolTable *symtab, COFF_MachineType machine, U64 page_size, LNK_ObjList obj_list);
|
||||
internal LNK_Chunk * lnk_build_dos_header(LNK_SymbolTable *symtab, LNK_Section *header_sect, LNK_Chunk *parent_chunk);
|
||||
@@ -287,7 +286,9 @@ internal LNK_Chunk * lnk_build_win32_image_header(LNK_SymbolTable *symtab, LNK_S
|
||||
////////////////////////////////
|
||||
// Relocs
|
||||
|
||||
internal void lnk_patch_relocs(TP_Context *tp, LNK_SymbolTable *symtab, LNK_SectionTable *st, U64 base_addr);
|
||||
internal void lnk_patch_relocs_linker(TP_Context *tp, LNK_SymbolTable *symtab, LNK_SectionTable *st, LNK_Section **sect_id_map, String8 image_data, U64 base_addr);
|
||||
internal void lnk_patch_relocs_obj(TP_Context *tp, LNK_ObjList obj_list, LNK_SymbolTable *symtab, LNK_SectionTable *st, LNK_Section **sect_id_map, String8 image_data, U64 base_addr);
|
||||
|
||||
internal void lnk_apply_reloc(U64 base_addr, U64 virt_align, U64 file_align, LNK_Section **sect_id_map, LNK_SymbolTable *symtab, String8 chunk_data, LNK_Reloc *reloc);
|
||||
|
||||
////////////////////////////////
|
||||
@@ -296,3 +297,8 @@ internal void lnk_log_size_breakdown(LNK_SectionTable *st, LNK_SymbolTable *symt
|
||||
internal void lnk_log_link_stats(LNK_ObjList obj_list, LNK_LibList *lib_index, LNK_SectionTable *st);
|
||||
internal void lnk_log_timers(void);
|
||||
|
||||
////////////////////////////////
|
||||
// Enum <-> String
|
||||
|
||||
internal String8 lnk_string_from_input_source(LNK_InputSourceType input_source);
|
||||
|
||||
|
||||
+206
-235
@@ -1,9 +1,6 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
global read_only LNK_Chunk g_null_chunk = { 0, 0, /* is_discarded: */ 1 };
|
||||
global read_only LNK_Chunk *g_null_chunk_ptr = &g_null_chunk;
|
||||
|
||||
internal LNK_ChunkRef
|
||||
lnk_chunk_ref(U64 sect_id, U64 chunk_id)
|
||||
{
|
||||
@@ -65,7 +62,7 @@ lnk_chunk_sort_index_is_before(void *raw_a, void *raw_b)
|
||||
LNK_ChunkPtr *b = raw_b;
|
||||
|
||||
// sort on section postfix
|
||||
int cmp = str8_compar_case_sensetive(&(*a)->sort_idx, &(*b)->sort_idx);
|
||||
int cmp = str8_compar_case_sensitive(&(*a)->sort_idx, &(*b)->sort_idx);
|
||||
|
||||
// sort on obj position on command line
|
||||
if (cmp == 0) {
|
||||
@@ -346,307 +343,286 @@ lnk_chunk_list_get_node_count(LNK_Chunk *chunk)
|
||||
}
|
||||
|
||||
internal void
|
||||
lnk_chunk_op_list_push_node(LNK_ChunkOpList *list, LNK_ChunkOp *op)
|
||||
lnk_chunk_align_array_list_push(Arena *arena, Arena *scratch, LNK_ChunkAlignArrayList *list, U64 cap, U64 align_off, U64 align_size)
|
||||
{
|
||||
SLLQueuePush(list->first, list->last, op);
|
||||
if (align_size > 0) {
|
||||
if (list->last == 0 || list->last->data.count >= list->last->cap) {
|
||||
LNK_ChunkAlignArrayNode *node = push_array(scratch, LNK_ChunkAlignArrayNode, 1);
|
||||
node->cap = cap;
|
||||
node->data.v = push_array_no_zero(arena, LNK_ChunkAlign, cap);
|
||||
|
||||
SLLQueuePush(list->first, list->last, node);
|
||||
++list->count;
|
||||
}
|
||||
|
||||
LNK_ChunkAlignArray *last_array = &list->last->data;
|
||||
LNK_ChunkAlign *align = &last_array->v[last_array->count++];
|
||||
align->off = align_off;
|
||||
align->size = align_size;
|
||||
}
|
||||
}
|
||||
|
||||
internal LNK_ChunkOp *
|
||||
lnk_push_chunk_op_begin(Arena *arena, U64 chunk_id)
|
||||
internal LNK_ChunkLayout
|
||||
lnk_layout_from_chunk(Arena *arena, LNK_Chunk *root, U64 total_chunk_count)
|
||||
{
|
||||
LNK_ChunkOp *begin_op = push_array_no_zero(arena, LNK_ChunkOp, 1);
|
||||
begin_op->next = 0;
|
||||
begin_op->type = LNK_ChunkOp_Begin;
|
||||
begin_op->u.chunk_id = chunk_id;
|
||||
return begin_op;
|
||||
}
|
||||
ProfBeginV("lnk_layout_from_chunk [total_chunk_count = %llu]", total_chunk_count);
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
|
||||
LNK_ChunkLayout layout = {0};
|
||||
layout.total_count = total_chunk_count;
|
||||
layout.chunk_ptr_array = push_array_no_zero(arena, LNK_ChunkPtr, total_chunk_count);
|
||||
layout.chunk_off_array = push_array_no_zero(arena, U64, total_chunk_count);
|
||||
layout.chunk_file_size_array = push_array_no_zero(arena, U64, total_chunk_count);
|
||||
layout.chunk_virt_size_array = push_array_no_zero(arena, U64, total_chunk_count);
|
||||
|
||||
internal LNK_ChunkOp *
|
||||
lnk_push_chunk_op_end_virt(Arena *arena)
|
||||
{
|
||||
LNK_ChunkOp *end_virt_op = push_array_no_zero(arena, LNK_ChunkOp, 1);
|
||||
end_virt_op->next = 0;
|
||||
end_virt_op->type = LNK_ChunkOp_EndVirt;
|
||||
return end_virt_op;
|
||||
}
|
||||
ProfBegin("Init Arrays");
|
||||
for (U64 i = 0; i < total_chunk_count; ++i) {
|
||||
layout.chunk_ptr_array[i] = &g_null_chunk;
|
||||
}
|
||||
#if BUILD_DEBUG
|
||||
MemorySet(layout.chunk_off_array, 0xff, total_chunk_count * sizeof(layout.chunk_off_array));
|
||||
MemorySet(layout.chunk_file_size_array, 0xff, total_chunk_count * sizeof(layout.chunk_file_size_array));
|
||||
MemorySet(layout.chunk_virt_size_array, 0xff, total_chunk_count * sizeof(layout.chunk_virt_size_array));
|
||||
#endif
|
||||
ProfEnd();
|
||||
|
||||
internal LNK_ChunkOp *
|
||||
lnk_push_chunk_op_end_file(Arena *arena)
|
||||
{
|
||||
LNK_ChunkOp *end_op = push_array_no_zero(arena, LNK_ChunkOp, 1);
|
||||
end_op->next = 0;
|
||||
end_op->type = LNK_ChunkOp_End;
|
||||
return end_op;
|
||||
}
|
||||
// handle null chunk
|
||||
layout.chunk_off_array[0] = 0;
|
||||
layout.chunk_file_size_array[0] = 0;
|
||||
layout.chunk_virt_size_array[0] = 0;
|
||||
|
||||
internal LNK_ChunkOp *
|
||||
lnk_push_chunk_op_align(Arena *arena, U64 align, U64 val)
|
||||
{
|
||||
LNK_ChunkOp *align_op = push_array_no_zero(arena, LNK_ChunkOp, 1);
|
||||
align_op->next = 0;
|
||||
align_op->type = LNK_ChunkOp_Align;
|
||||
align_op->u.align.x = align;
|
||||
align_op->u.align.val = val;
|
||||
return align_op;
|
||||
}
|
||||
|
||||
internal LNK_ChunkOp *
|
||||
lnk_push_chunk_op_write(Arena *arena, String8 string)
|
||||
{
|
||||
LNK_ChunkOp *write_op = push_array_no_zero(arena, LNK_ChunkOp, 1);
|
||||
write_op->next = 0;
|
||||
write_op->type = LNK_ChunkOp_WriteString;
|
||||
write_op->u.string = string;
|
||||
return write_op;
|
||||
}
|
||||
|
||||
internal LNK_ChunkOpList
|
||||
lnk_op_list_from_chunk(Arena *arena, LNK_Chunk *root, U64 total_chunk_count, U8 align_byte)
|
||||
{
|
||||
// setup stack
|
||||
struct Stack {
|
||||
struct Stack *next;
|
||||
LNK_ChunkArray chunk_array;
|
||||
U64 ichunk;
|
||||
};
|
||||
|
||||
ProfBeginFunction();
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
|
||||
// setup stack
|
||||
struct Stack *stack = push_array(scratch.arena, struct Stack, 1);
|
||||
stack->chunk_array.count = 1;
|
||||
stack->chunk_array.v = &root;
|
||||
|
||||
// setup output list
|
||||
LNK_ChunkOpList list = {0};
|
||||
list.total_chunk_count = total_chunk_count;
|
||||
list.first = list.last = 0;
|
||||
|
||||
// write null
|
||||
LNK_ChunkOp *null_begin_op = lnk_push_chunk_op_begin(arena, 0);
|
||||
LNK_ChunkOp *null_end_virt_op = lnk_push_chunk_op_end_virt(arena);
|
||||
LNK_ChunkOp *null_end_file_op = lnk_push_chunk_op_end_file(arena);;
|
||||
lnk_chunk_op_list_push_node(&list, null_begin_op);
|
||||
lnk_chunk_op_list_push_node(&list, null_end_virt_op);
|
||||
lnk_chunk_op_list_push_node(&list, null_end_file_op);
|
||||
|
||||
// traverse chunks from root
|
||||
while (stack) {
|
||||
while (stack->ichunk < stack->chunk_array.count) {
|
||||
|
||||
U64 align_cap = 4096;
|
||||
LNK_ChunkAlignArrayList align_list = {0};
|
||||
|
||||
U64 cursor = 0;
|
||||
|
||||
ProfBegin("Traverse chunks from root");
|
||||
for (; stack != 0; ) {
|
||||
for (; stack->ichunk < stack->chunk_array.count; ) {
|
||||
LNK_Chunk *chunk = stack->chunk_array.v[stack->ichunk++];
|
||||
|
||||
// skip unused chunks
|
||||
// skip discarded chunk
|
||||
if (lnk_chunk_is_discarded(chunk)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// push align
|
||||
U64 align_size = AlignPadPow2(cursor, chunk->align);
|
||||
lnk_chunk_align_array_list_push(arena, scratch.arena, &align_list, align_cap, cursor, align_size);
|
||||
cursor += align_size;
|
||||
|
||||
// store id -> chunk
|
||||
Assert(chunk->ref.chunk_id < total_chunk_count);
|
||||
Assert(layout.chunk_ptr_array[chunk->ref.chunk_id] == &g_null_chunk);
|
||||
layout.chunk_ptr_array[chunk->ref.chunk_id] = chunk;
|
||||
|
||||
// store id -> offset
|
||||
Assert(layout.chunk_off_array[chunk->ref.chunk_id] == max_U64);
|
||||
layout.chunk_off_array[chunk->ref.chunk_id] = cursor;
|
||||
|
||||
switch (chunk->type) {
|
||||
case LNK_Chunk_Leaf: {
|
||||
// align start in its own begin/end block so align bytes don't contribute to chunk size
|
||||
LNK_ChunkOp *pad_begin_op = lnk_push_chunk_op_begin(arena, list.total_chunk_count++);
|
||||
LNK_ChunkOp *pad_align_op = lnk_push_chunk_op_align(arena, chunk->align, align_byte);
|
||||
LNK_ChunkOp *pad_end_file_op = lnk_push_chunk_op_end_file(arena);
|
||||
lnk_chunk_op_list_push_node(&list, pad_begin_op);
|
||||
lnk_chunk_op_list_push_node(&list, pad_align_op);
|
||||
lnk_chunk_op_list_push_node(&list, pad_end_file_op);
|
||||
|
||||
// write leaf
|
||||
LNK_ChunkOp *leaf_begin_op = lnk_push_chunk_op_begin(arena, chunk->ref.chunk_id);
|
||||
LNK_ChunkOp *leaf_write_op = lnk_push_chunk_op_write(arena, chunk->u.leaf);
|
||||
LNK_ChunkOp *leaf_align_op = lnk_push_chunk_op_align(arena, chunk->align, align_byte);
|
||||
LNK_ChunkOp *leaf_end_virt_op = lnk_push_chunk_op_end_virt(arena);
|
||||
LNK_ChunkOp *leaf_end_file_op = lnk_push_chunk_op_end_file(arena);
|
||||
#if LNK_DUMP_CHUNK_LAYOUT
|
||||
leaf_write_op->chunk = chunk;
|
||||
#endif
|
||||
lnk_chunk_op_list_push_node(&list, leaf_begin_op);
|
||||
lnk_chunk_op_list_push_node(&list, leaf_write_op);
|
||||
lnk_chunk_op_list_push_node(&list, leaf_align_op);
|
||||
lnk_chunk_op_list_push_node(&list, leaf_end_virt_op);
|
||||
lnk_chunk_op_list_push_node(&list, leaf_end_file_op);
|
||||
// store id -> file size
|
||||
Assert(layout.chunk_file_size_array[chunk->ref.chunk_id] == max_U64);
|
||||
layout.chunk_file_size_array[chunk->ref.chunk_id] = chunk->u.leaf.size;
|
||||
|
||||
// store id -> virt size
|
||||
Assert(layout.chunk_virt_size_array[chunk->ref.chunk_id] == max_U64);
|
||||
layout.chunk_virt_size_array[chunk->ref.chunk_id] = chunk->u.leaf.size;
|
||||
|
||||
// advance
|
||||
cursor += chunk->u.leaf.size;
|
||||
} break;
|
||||
|
||||
case LNK_Chunk_LeafArray: {
|
||||
LNK_ChunkOp *begin_op = lnk_push_chunk_op_begin(arena, chunk->ref.chunk_id);
|
||||
LNK_ChunkOp *align_op = lnk_push_chunk_op_align(arena, chunk->align, align_byte);
|
||||
lnk_chunk_op_list_push_node(&list, begin_op);
|
||||
lnk_chunk_op_list_push_node(&list, align_op);
|
||||
|
||||
#if BUILD_DEBUG
|
||||
for (U64 i = 0; i < chunk->u.arr->count; ++i) {
|
||||
Assert(chunk->u.arr->v[i]->type == LNK_Chunk_Leaf);
|
||||
}
|
||||
#endif
|
||||
// apply sort
|
||||
if (chunk->sort_chunk) {
|
||||
lnk_chunk_array_sort(*chunk->u.arr);
|
||||
}
|
||||
|
||||
struct Stack *frame = push_array_no_zero(scratch.arena, struct Stack, 1);
|
||||
frame->next = 0;
|
||||
// recurse into sub chunks
|
||||
struct Stack *frame = push_array(scratch.arena, struct Stack, 1);
|
||||
frame->chunk_array = *chunk->u.arr;
|
||||
frame->ichunk = 0;
|
||||
SLLStackPush(stack, frame);
|
||||
} goto yeild;
|
||||
} goto _continue;
|
||||
|
||||
case LNK_Chunk_List: {
|
||||
// balance ops at :end_chunk_series
|
||||
LNK_ChunkOp *begin_op = lnk_push_chunk_op_begin(arena, chunk->ref.chunk_id);
|
||||
LNK_ChunkOp *align_op = lnk_push_chunk_op_align(arena, chunk->align, align_byte);
|
||||
lnk_chunk_op_list_push_node(&list, begin_op);
|
||||
lnk_chunk_op_list_push_node(&list, align_op);
|
||||
|
||||
// chunk list -> chunk array
|
||||
case LNK_Chunk_List: {
|
||||
// list -> array
|
||||
LNK_ChunkArray chunk_array = {0};
|
||||
chunk_array.v = push_array_no_zero(scratch.arena, LNK_ChunkPtr, chunk->u.list->count);
|
||||
for (LNK_ChunkNode *cptr = chunk->u.list->first; cptr != 0; cptr = cptr->next) {
|
||||
chunk_array.v[chunk_array.count++] = cptr->data;
|
||||
}
|
||||
|
||||
// apply sort
|
||||
if (chunk->sort_chunk) {
|
||||
lnk_chunk_array_sort(chunk_array);
|
||||
}
|
||||
|
||||
// recurse into list chunk
|
||||
struct Stack *frame = push_array_no_zero(scratch.arena, struct Stack, 1);
|
||||
frame->next = 0;
|
||||
// recurse into sub chunks
|
||||
struct Stack *frame = push_array(scratch.arena, struct Stack, 1);
|
||||
frame->chunk_array = chunk_array;
|
||||
frame->ichunk = 0;
|
||||
SLLStackPush(stack, frame);
|
||||
} goto yeild;
|
||||
} goto _continue;
|
||||
|
||||
case LNK_Chunk_Null: { /* ignore */ } break;
|
||||
case LNK_Chunk_Null: break;
|
||||
}
|
||||
}
|
||||
|
||||
// terminate series
|
||||
if (stack->next) {
|
||||
// pop node chunk from stack
|
||||
struct Stack *prev = stack->next;
|
||||
Assert(prev->ichunk > 0);
|
||||
|
||||
// :end_chunk_series
|
||||
LNK_ChunkOp *end_virt_op = lnk_push_chunk_op_end_virt(arena);
|
||||
LNK_ChunkOp *align_op = lnk_push_chunk_op_align(arena, prev->chunk_array.v[prev->ichunk - 1]->align, align_byte);
|
||||
LNK_ChunkOp *end_op = lnk_push_chunk_op_end_file(arena);
|
||||
lnk_chunk_op_list_push_node(&list, end_virt_op);
|
||||
lnk_chunk_op_list_push_node(&list, align_op);
|
||||
lnk_chunk_op_list_push_node(&list, end_op);
|
||||
// align chunk end
|
||||
LNK_Chunk *chunk = prev->chunk_array.v[prev->ichunk-1];
|
||||
U64 align_size = AlignPadPow2(cursor, chunk->align);
|
||||
lnk_chunk_align_array_list_push(arena, scratch.arena, &align_list, align_cap, cursor, align_size);
|
||||
|
||||
U64 chunk_start_off = layout.chunk_off_array[chunk->ref.chunk_id];
|
||||
Assert(chunk_start_off != max_U64);
|
||||
Assert(chunk_start_off <= cursor);
|
||||
|
||||
// store id -> virt size
|
||||
Assert(layout.chunk_virt_size_array[chunk->ref.chunk_id] == max_U64);
|
||||
U64 virt_chunk_size = cursor - chunk_start_off;
|
||||
layout.chunk_virt_size_array[chunk->ref.chunk_id] = virt_chunk_size;
|
||||
|
||||
// advance cursor
|
||||
cursor += align_size;
|
||||
|
||||
// store id -> file size
|
||||
Assert(layout.chunk_file_size_array[chunk->ref.chunk_id] == max_U64);
|
||||
U64 file_chunk_size = cursor - chunk_start_off;
|
||||
layout.chunk_file_size_array[chunk->ref.chunk_id] = file_chunk_size;
|
||||
}
|
||||
|
||||
// move to next frame
|
||||
SLLStackPop(stack);
|
||||
|
||||
yeild:;
|
||||
_continue:;
|
||||
}
|
||||
|
||||
ProfEnd();
|
||||
|
||||
ProfBegin("Build Aligns Array");
|
||||
layout.align_array_count = 0;
|
||||
layout.align_array = push_array(arena, LNK_ChunkAlignArray, align_list.count);
|
||||
for (LNK_ChunkAlignArrayNode *node = align_list.first; node != 0; node = node->next) {
|
||||
layout.align_array[layout.align_array_count++] = node->data;
|
||||
}
|
||||
ProfEnd();
|
||||
|
||||
scratch_end(scratch);
|
||||
ProfEnd();
|
||||
return list;
|
||||
return layout;
|
||||
}
|
||||
|
||||
internal LNK_ChunkLayout
|
||||
lnk_chunk_layout_from_op_list(Arena *arena, LNK_ChunkOpList op_list, B32 is_data_inited)
|
||||
lnk_build_chunk_layout(Arena *arena, LNK_ChunkManager *cman)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
|
||||
// setup stack
|
||||
struct Stack {
|
||||
struct Stack *next;
|
||||
U64 chunk_id;
|
||||
U64 cursor;
|
||||
} *stack = 0;
|
||||
|
||||
// setup state
|
||||
U64 cursor = 0;
|
||||
String8List data_list = {0};
|
||||
|
||||
// setup output
|
||||
U64 *chunk_off_array = push_array_no_zero(arena, U64, op_list.total_chunk_count);
|
||||
U64 *chunk_file_size_array = push_array_no_zero(arena, U64, op_list.total_chunk_count);
|
||||
U64 *chunk_virt_size_array = push_array_no_zero(arena, U64, op_list.total_chunk_count);
|
||||
|
||||
// debug stomp so discarded chunks map to invalid offset
|
||||
#if LNK_PARANOID
|
||||
MemorySet(chunk_off_array, 0xFF, sizeof(*chunk_off_array) * op_list.total_chunk_count);
|
||||
MemorySet(chunk_file_size_array, 0xFF, sizeof(*chunk_file_size_array) * op_list.total_chunk_count);
|
||||
MemorySet(chunk_virt_size_array, 0xFF, sizeof(*chunk_virt_size_array) * op_list.total_chunk_count);
|
||||
#endif
|
||||
|
||||
// execute opcodes
|
||||
for (LNK_ChunkOp *op = op_list.first; op != NULL; op = op->next) {
|
||||
switch (op->type) {
|
||||
case LNK_ChunkOp_Null: break;
|
||||
case LNK_ChunkOp_Begin: {
|
||||
struct Stack *frame = push_array(scratch.arena, struct Stack, 1);
|
||||
frame->chunk_id = op->u.chunk_id;
|
||||
frame->cursor = cursor;
|
||||
SLLStackPush(stack, frame);
|
||||
chunk_off_array[stack->chunk_id] = stack->cursor;
|
||||
} break;
|
||||
case LNK_ChunkOp_End: {
|
||||
chunk_file_size_array[stack->chunk_id] = cursor - stack->cursor;
|
||||
SLLStackPop(stack);
|
||||
} break;
|
||||
case LNK_ChunkOp_EndVirt: {
|
||||
chunk_virt_size_array[stack->chunk_id] = cursor - stack->cursor;
|
||||
} break;
|
||||
case LNK_ChunkOp_Align: {
|
||||
Assert(IsPow2(op->u.align.x));
|
||||
U64 size = AlignPow2(cursor, op->u.align.x) - cursor;
|
||||
|
||||
String8 string;
|
||||
string.size = size;
|
||||
string.str = push_array_no_zero(arena, U8, string.size);
|
||||
MemorySet(string.str, op->u.align.val, string.size);
|
||||
|
||||
op->type = LNK_ChunkOp_WriteString;
|
||||
op->u.string = string;
|
||||
} // fall-through
|
||||
case LNK_ChunkOp_WriteString: {
|
||||
if (is_data_inited) {
|
||||
// we allow chunks to have null for str for regions in the image that are zeroed out.
|
||||
if (op->u.string.str == 0) {
|
||||
op->u.string.str = push_array(arena, U8, op->u.string.size);
|
||||
}
|
||||
str8_list_push(scratch.arena, &data_list, op->u.string);
|
||||
LNK_ChunkLayout layout = lnk_layout_from_chunk(arena, cman->root, cman->total_chunk_count);
|
||||
ProfEnd();
|
||||
return layout;
|
||||
}
|
||||
|
||||
internal
|
||||
THREAD_POOL_TASK_FUNC(lnk_fill_chunks_task)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
|
||||
LNK_ChunkLayoutSerializer *task = raw_task;
|
||||
Rng1U64 range = task->ranges[task_id];
|
||||
LNK_ChunkLayout layout = task->layout;
|
||||
String8 buffer = task->buffer;
|
||||
|
||||
for (U64 chunk_idx = range.min; chunk_idx < range.max; ++chunk_idx) {
|
||||
LNK_Chunk *chunk = layout.chunk_ptr_array[chunk_idx];
|
||||
|
||||
if (lnk_chunk_is_discarded(chunk)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (chunk->type == LNK_Chunk_Leaf) {
|
||||
U64 off = layout.chunk_off_array[chunk->ref.chunk_id];
|
||||
Assert(off + chunk->u.leaf.size <= buffer.size);
|
||||
U8 *buffer_ptr = buffer.str + off;
|
||||
|
||||
if (chunk->u.leaf.str == 0) {
|
||||
// zero out chunk bytes
|
||||
MemorySet(buffer_ptr, 0, chunk->u.leaf.size);
|
||||
} else {
|
||||
// copy chunk bytes
|
||||
MemoryCopy(buffer_ptr, chunk->u.leaf.str, chunk->u.leaf.size);
|
||||
}
|
||||
#if LNK_DUMP_CHUNK_LAYOUT
|
||||
if (op->chunk) {
|
||||
fprintf(g_layout_file, "[%.*s] %llX %.*s\n", str8_varg(op->chunk->sort_idx), op->chunk->input_idx, str8_varg(op->chunk->debug));
|
||||
}
|
||||
#endif
|
||||
// advance
|
||||
cursor += op->u.string.size;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
// are begin/end series opcodes balanced?
|
||||
Assert(stack == 0);
|
||||
|
||||
// fill out result
|
||||
LNK_ChunkLayout layout = {0};
|
||||
layout.data = str8_list_join(arena, &data_list, 0);
|
||||
layout.chunk_off_array = chunk_off_array;
|
||||
layout.chunk_file_size_array = chunk_file_size_array;
|
||||
layout.chunk_virt_size_array = chunk_virt_size_array;
|
||||
|
||||
scratch_end(scratch);
|
||||
ProfEnd();
|
||||
return layout;
|
||||
}
|
||||
|
||||
internal LNK_ChunkLayout
|
||||
lnk_build_chunk_layout(Arena *arena, LNK_ChunkManager *cman, COFF_SectionFlags flags, U8 align_byte)
|
||||
internal
|
||||
THREAD_POOL_TASK_FUNC(lnk_fill_aligns_task)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
|
||||
// should we write data for chunks?
|
||||
B32 is_data_inited = !!(~flags & COFF_SectionFlag_CNT_UNINITIALIZED_DATA);
|
||||
|
||||
// build layout
|
||||
LNK_ChunkOpList op_list = lnk_op_list_from_chunk(scratch.arena, cman->root, cman->total_chunk_count, align_byte);
|
||||
LNK_ChunkLayout layout = lnk_chunk_layout_from_op_list(arena, op_list, is_data_inited);
|
||||
|
||||
LNK_ChunkLayoutSerializer *task = raw_task;
|
||||
Rng1U64 range = task->ranges[task_id];
|
||||
LNK_ChunkLayout layout = task->layout;
|
||||
String8 buffer = task->buffer;
|
||||
U8 fill_byte = task->fill_byte;
|
||||
|
||||
for (U64 align_array_idx = range.min; align_array_idx < range.max; ++align_array_idx) {
|
||||
LNK_ChunkAlignArray align_array = layout.align_array[align_array_idx];
|
||||
for (U64 align_idx = 0; align_idx < align_array.count; ++align_idx) {
|
||||
LNK_ChunkAlign align = align_array.v[align_idx];
|
||||
Assert(align.off + align.size <= buffer.size);
|
||||
MemorySet(buffer.str + align.off, fill_byte, align.size);
|
||||
}
|
||||
}
|
||||
|
||||
ProfEnd();
|
||||
}
|
||||
|
||||
internal void
|
||||
lnk_serialize_chunk_layout(TP_Context *tp, LNK_ChunkLayout layout, String8 buffer, U8 fill_byte)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
Temp scratch = scratch_begin(0,0);
|
||||
|
||||
LNK_ChunkLayoutSerializer task;
|
||||
task.layout = layout;
|
||||
task.buffer = buffer;
|
||||
task.fill_byte = fill_byte;
|
||||
|
||||
ProfBeginV("Fill Chunks [Chunk Count %llu]", layout.total_count);
|
||||
task.ranges = tp_divide_work(scratch.arena, layout.total_count, tp->worker_count);
|
||||
tp_for_parallel(tp, 0, tp->worker_count, lnk_fill_chunks_task, &task);
|
||||
ProfEnd();
|
||||
|
||||
ProfBeginV("Fill Aligns [Array Count %llu]", layout.align_array_count);
|
||||
task.ranges = tp_divide_work(scratch.arena, layout.align_array_count, tp->worker_count);
|
||||
tp_for_parallel(tp, 0, tp->worker_count, lnk_fill_aligns_task, &task);
|
||||
ProfEnd();
|
||||
|
||||
scratch_end(scratch);
|
||||
ProfEnd();
|
||||
return layout;
|
||||
}
|
||||
|
||||
internal B32
|
||||
@@ -702,15 +678,10 @@ LNK_CHUNK_VISITOR_SIG(lnk_save_chunk_ptr)
|
||||
internal LNK_ChunkPtr *
|
||||
lnk_make_chunk_id_map(Arena *arena, LNK_ChunkManager *cman)
|
||||
{
|
||||
LNK_ChunkPtr *chunk_id_map = push_array_no_zero(arena, LNK_ChunkPtr, cman->total_chunk_count + 1);
|
||||
lnk_visit_chunks(0, cman->root, lnk_save_chunk_ptr, chunk_id_map);
|
||||
|
||||
LNK_Chunk *null_chunk = push_array(arena, LNK_Chunk, 1);
|
||||
null_chunk->is_discarded = 1;
|
||||
|
||||
chunk_id_map[0] = null_chunk;
|
||||
|
||||
return chunk_id_map;
|
||||
LNK_ChunkPtr *map = push_array_no_zero(arena, LNK_ChunkPtr, cman->total_chunk_count);
|
||||
lnk_visit_chunks(0, cman->root, lnk_save_chunk_ptr, map);
|
||||
map[0] = &g_null_chunk;
|
||||
return map;
|
||||
}
|
||||
|
||||
internal LNK_ChunkNode *
|
||||
|
||||
+50
-16
@@ -5,8 +5,7 @@
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
#define LNK_DEBUG_CHUNKS 0
|
||||
#define LNK_DUMP_CHUNK_LAYOUT 0
|
||||
#define LNK_DEBUG_CHUNKS 0
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
@@ -79,17 +78,14 @@ typedef struct LNK_ChunkOp
|
||||
struct LNK_ChunkOp *next;
|
||||
LNK_ChunkOpType type;
|
||||
union {
|
||||
String8 string;
|
||||
U64 chunk_id;
|
||||
String8 string;
|
||||
LNK_Chunk *chunk;
|
||||
struct {
|
||||
U64 val;
|
||||
U64 x;
|
||||
} align;
|
||||
LNK_Chunk *leaf;
|
||||
} u;
|
||||
#if LNK_DUMP_CHUNK_LAYOUT
|
||||
LNK_Chunk *chunk;
|
||||
#endif
|
||||
} LNK_ChunkOp;
|
||||
|
||||
typedef struct LNK_ChunkOpList
|
||||
@@ -99,12 +95,39 @@ typedef struct LNK_ChunkOpList
|
||||
LNK_ChunkOp *last;
|
||||
} LNK_ChunkOpList;
|
||||
|
||||
typedef struct LNK_ChunkAlign
|
||||
{
|
||||
U64 off;
|
||||
U64 size;
|
||||
} LNK_ChunkAlign;
|
||||
|
||||
typedef struct LNK_ChunkAlignArray
|
||||
{
|
||||
U64 count;
|
||||
LNK_ChunkAlign *v;
|
||||
} LNK_ChunkAlignArray;
|
||||
typedef struct LNK_ChunkAlignArrayNode
|
||||
{
|
||||
struct LNK_ChunkAlignArrayNode *next;
|
||||
U64 cap;
|
||||
LNK_ChunkAlignArray data;
|
||||
} LNK_ChunkAlignArrayNode;
|
||||
typedef struct LNK_ChunkAlignArrayList
|
||||
{
|
||||
U64 count;
|
||||
LNK_ChunkAlignArrayNode *first;
|
||||
LNK_ChunkAlignArrayNode *last;
|
||||
} LNK_ChunkAlignArrayList;
|
||||
|
||||
typedef struct LNK_ChunkLayout
|
||||
{
|
||||
String8 data;
|
||||
U64 *chunk_off_array;
|
||||
U64 *chunk_file_size_array;
|
||||
U64 *chunk_virt_size_array;
|
||||
U64 total_count;
|
||||
LNK_Chunk **chunk_ptr_array; // discarded chunks point to g_null_chunk
|
||||
U64 *chunk_off_array; // discarded chunks have offset set to max_U64
|
||||
U64 *chunk_file_size_array; // discarded chunks have offset set to max_U64
|
||||
U64 *chunk_virt_size_array; // discarded chunks have offset set to max_U64
|
||||
U64 align_array_count;
|
||||
LNK_ChunkAlignArray *align_array;
|
||||
} LNK_ChunkLayout;
|
||||
|
||||
typedef struct LNK_ChunkManager
|
||||
@@ -113,8 +136,20 @@ typedef struct LNK_ChunkManager
|
||||
U64 total_chunk_count;
|
||||
} LNK_ChunkManager;
|
||||
|
||||
extern LNK_Chunk g_null_chunk;
|
||||
extern LNK_Chunk *g_null_chunk_ptr;
|
||||
typedef struct
|
||||
{
|
||||
LNK_ChunkLayout layout;
|
||||
String8 buffer;
|
||||
U8 fill_byte;
|
||||
Rng1U64 *ranges;
|
||||
} LNK_ChunkLayoutSerializer;
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
read_only global LNK_Chunk g_null_chunk = { 0, 0, /* is_discarded: */ 1 };
|
||||
read_only global LNK_Chunk *g_null_chunk_ptr = &g_null_chunk;
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal LNK_ChunkRef lnk_chunk_ref(U64 sect_id, U64 chunk_id);
|
||||
internal B32 lnk_chunk_ref_is_equal(LNK_ChunkRef a, LNK_ChunkRef b);
|
||||
@@ -144,9 +179,8 @@ internal LNK_ChunkOp * lnk_push_chunk_op_end_file(Arena *arena);
|
||||
internal LNK_ChunkOp * lnk_push_chunk_op_align(Arena *arena, U64 align, U64 val);
|
||||
internal LNK_ChunkOp * lnk_push_chunk_op_write(Arena *arena, String8 string);
|
||||
|
||||
internal LNK_ChunkOpList lnk_op_list_from_chunk(Arena *arena, LNK_Chunk *root, U64 total_chunk_count, U8 align_byte);
|
||||
internal LNK_ChunkLayout lnk_chunk_layout_from_op_list(Arena *arena, LNK_ChunkOpList op_list, B32 is_data_inited);
|
||||
internal LNK_ChunkLayout lnk_build_chunk_layout(Arena *arena, LNK_ChunkManager *cman, COFF_SectionFlags flags, U8 align_byte);
|
||||
internal LNK_ChunkLayout lnk_layout_from_chunk(Arena *arena, LNK_Chunk *root, U64 total_chunk_count);
|
||||
internal LNK_ChunkLayout lnk_build_chunk_layout(Arena *arena, LNK_ChunkManager *cman);
|
||||
|
||||
#define LNK_CHUNK_VISITOR_SIG(name) B32 name(U64 sect_id, LNK_Chunk *chunk, void *ud)
|
||||
typedef LNK_CHUNK_VISITOR_SIG(LNK_ChunkVisitorSig);
|
||||
|
||||
@@ -202,7 +202,7 @@ lnk_unwrap_rsp(Arena *arena, String8List arg_list)
|
||||
|
||||
if (os_file_path_exists(name)) {
|
||||
// read rsp from disk
|
||||
String8 file = os_data_from_file_path(scratch.arena, name);
|
||||
String8 file = lnk_read_data_from_file_path(scratch.arena, name);
|
||||
|
||||
// parse rsp
|
||||
String8List rsp_args = lnk_arg_list_parse_windows_rules(scratch.arena, file);
|
||||
|
||||
+273
-115
@@ -84,15 +84,17 @@ read_only struct
|
||||
{ LNK_CmdSwitch_Natvis, "NATVIS", ":FILENAME", "" },
|
||||
{ LNK_CmdSwitch_NotImplemented, "NOASSEMBLY", "", "" },
|
||||
{ LNK_CmdSwitch_NoDefaultLib, "NODEFAULTLIB", ":LIBNAME", "" },
|
||||
{ LNK_CmdSwitch_NoDefaultLib, "NOD", ":LIBNAME", "" },
|
||||
{ LNK_CmdSwitch_NotImplemented, "NOENTRY", "", "" },
|
||||
{ LNK_CmdSwitch_NotImplemented, "NOEXP", "", "" },
|
||||
{ LNK_CmdSwitch_NotImplemented, "NOIMPLIB", "", "" },
|
||||
{ LNK_CmdSwitch_NoExp, "NOEXP", "", ".exp is not supported." },
|
||||
{ LNK_CmdSwitch_NoImpLib, "NOIMPLIB", "", "" },
|
||||
{ LNK_CmdSwitch_NoLogo, "NOLOGO", "", "" },
|
||||
{ LNK_CmdSwitch_NxCompat, "NXCOMPAT", "[:NO]", "" },
|
||||
{ LNK_CmdSwitch_Opt, "OPT", "", "" },
|
||||
{ LNK_CmdSwitch_NotImplemented, "ORDER", "", "" },
|
||||
{ LNK_CmdSwitch_Out, "OUT", ":FILENAME", "" },
|
||||
{ LNK_CmdSwitch_Pdb, "PDB", ":FILENAME", "" },
|
||||
{ LNK_CmdSwitch_PdbAltPath, "PDBALTPATH", "", "" },
|
||||
{ LNK_CmdSwitch_NotImplemented, "PDBSTRIPPED", "", "" },
|
||||
{ LNK_CmdSwitch_PdbPageSize, "PDBPAGESIZE", ":#", "Page size must be power of two" },
|
||||
{ LNK_CmdSwitch_NotImplemented, "PROFILE", "", "" },
|
||||
@@ -119,34 +121,38 @@ read_only struct
|
||||
{ LNK_CmdSwitch_NotImplemented, "WX", "", "" },
|
||||
|
||||
//- internal switches
|
||||
{ LNK_CmdSwitch_Rad_Age, "RAD_AGE", ":#", "Age embeded in EXE and PDB, used to validate incremental build. Default is 1." },
|
||||
{ LNK_CmdSwitch_Rad_BuildInfo, "RAD_BUILD_INFO", "", "Print build info and exit." },
|
||||
{ LNK_CmdSwitch_Rad_CheckUnusedDelayLoadDll, "RAD_CHECK_UNUSED_DELAY_LOAD_DLL", "[:NO]", "" },
|
||||
{ LNK_CmdSwitch_Rad_Debug, "RAD_DEBUG", "[:NO]", "Emit RAD debug info file." },
|
||||
{ LNK_CmdSwitch_Rad_DebugName, "RAD_DEBUG_NAME", ":FILENAME", "Sets file name for RAD debug info file." },
|
||||
{ LNK_CmdSwitch_Rad_DelayBind, "RAD_DELAY_BIND", "[:NO]", "" },
|
||||
{ LNK_CmdSwitch_Rad_DeleteManifest, "RAD_DELETE_MANIFEST", "[:NO]", "" },
|
||||
{ LNK_CmdSwitch_Rad_DoMerge, "RAD_DO_MERGE", "[:NO]", "" },
|
||||
{ LNK_CmdSwitch_Rad_EnvLib, "RAD_ENV_LIB", "[:NO]", "" },
|
||||
{ LNK_CmdSwitch_Rad_Exe, "RAD_EXE", "[:NO]", "" },
|
||||
{ LNK_CmdSwitch_Rad_Guid, "RAD_GUID", ":{IMAGEBLAKE3|XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXXXXXX}", "" },
|
||||
{ LNK_CmdSwitch_Rad_LargePages, "RAD_LARGE_PAGES", "[:NO]", "Disabled by default on Windows." },
|
||||
{ LNK_CmdSwitch_Rad_LinkVer, "RAD_LINK_VER", ":##,##", "" },
|
||||
{ LNK_CmdSwitch_Rad_Log, "RAD_LOG", ":{ALL,INPUT_OBJ,INPUT_LIB,IO,LINK_STATS,TIMERS}", "" },
|
||||
{ LNK_CmdSwitch_Rad_MtPath, "RAD_MT_PATH", ":EXEPATH", "Path to manifest tool." },
|
||||
{ LNK_CmdSwitch_Rad_OsVer, "RAD_OS_VER", ":##,##", "" },
|
||||
{ LNK_CmdSwitch_Rad_PageSize, "RAD_PAGE_SIZE", ":#", "Must be power of two." },
|
||||
{ LNK_CmdSwitch_Rad_PathStyle, "RAD_PATH_STYLE", ":{WindowsAbsolute|UnixAbsolute}", "" },
|
||||
{ LNK_CmdSwitch_Rad_SectVirtOff, "RAD_SECT_VIRT_OFF", ":#", "Set RVA where section data is placed in memory. For internal use only." },
|
||||
{ LNK_CmdSwitch_Rad_SuppressError, "RAD_SUPPRESS_ERROR", ":#", "" },
|
||||
{ LNK_CmdSwitch_Rad_SymbolTableCapDefined, "RAD_SYMBOL_TABLE_CAP_DEFINED", ":#", "Number of buckets allocated in the symbol table for defined symbols." },
|
||||
{ LNK_CmdSwitch_Rad_SymbolTableCapInternal, "RAD_SYMBOL_TABLE_CAP_INTERNAL", ":#", "Number of buckets allocated in the symbol table for internal symbols." },
|
||||
{ LNK_CmdSwitch_Rad_SymbolTableCapWeak, "RAD_SYMBOL_TABLE_CAP_WEAK", ":#", "Number of buckets allocated in the symbol table for weak symbols." },
|
||||
{ LNK_CmdSwitch_Rad_SymbolTableCapLib, "RAD_SYMBOL_TABLE_CAP_LIB", ":#", "Number of buckets allocated in the symbol table for library symbols." },
|
||||
{ LNK_CmdSwitch_Rad_TargetOs, "RAD_TARGET_OS", ":{WINDOWS,LINUX,MAC}" },
|
||||
{ LNK_CmdSwitch_Rad_TimeStamp, "RAD_TIME_STAMP", ":#", "Time stamp embeded in EXE and PDB." },
|
||||
{ LNK_CmdSwitch_Rad_Version, "RAD_VERSION", "", "Print version and exit." },
|
||||
{ LNK_CmdSwitch_Rad_Workers, "RAD_WORKERS", ":#", "Sets number of workers created in the pool. Number is capped at 1024." },
|
||||
{ LNK_CmdSwitch_Rad_Age, "RAD_AGE", ":#", "Age embeded in EXE and PDB, used to validate incremental build. Default is 1." },
|
||||
{ LNK_CmdSwitch_Rad_BuildInfo, "RAD_BUILD_INFO", "", "Print build info and exit." },
|
||||
{ LNK_CmdSwitch_Rad_CheckUnusedDelayLoadDll, "RAD_CHECK_UNUSED_DELAY_LOAD_DLL", "[:NO]", "" },
|
||||
{ LNK_CmdSwitch_Rad_Debug, "RAD_DEBUG", "[:NO]", "Emit RAD debug info file." },
|
||||
{ LNK_CmdSwitch_Rad_DebugAltPath, "RAD_DEBUGALTPATH", "", "" },
|
||||
{ LNK_CmdSwitch_Rad_DebugName, "RAD_DEBUG_NAME", ":FILENAME", "Sets file name for RAD debug info file." },
|
||||
{ LNK_CmdSwitch_Rad_DelayBind, "RAD_DELAY_BIND", "[:NO]", "" },
|
||||
{ LNK_CmdSwitch_Rad_DoMerge, "RAD_DO_MERGE", "[:NO]", "" },
|
||||
{ LNK_CmdSwitch_Rad_EnvLib, "RAD_ENV_LIB", "[:NO]", "" },
|
||||
{ LNK_CmdSwitch_Rad_Exe, "RAD_EXE", "[:NO]", "" },
|
||||
{ LNK_CmdSwitch_Rad_Guid, "RAD_GUID", ":{IMAGEBLAKE3|XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXXXXXX}", "" },
|
||||
{ LNK_CmdSwitch_Rad_IdleWorkers, "RAD_IDLE_WORKERS", ":#", "Number of workers to leave idle." },
|
||||
{ LNK_CmdSwitch_Rad_LargePages, "RAD_LARGE_PAGES", "[:NO]", "Disabled by default on Windows." },
|
||||
{ LNK_CmdSwitch_Rad_LinkVer, "RAD_LINK_VER", ":##,##", "" },
|
||||
{ LNK_CmdSwitch_Rad_Log, "RAD_LOG", ":{ALL,INPUT_OBJ,INPUT_LIB,IO,LINK_STATS,TIMERS}", "" },
|
||||
{ LNK_CmdSwitch_Rad_MtPath, "RAD_MT_PATH", ":EXEPATH", "Path to manifest tool." },
|
||||
{ LNK_CmdSwitch_Rad_OsVer, "RAD_OS_VER", ":##,##", "" },
|
||||
{ LNK_CmdSwitch_Rad_PageSize, "RAD_PAGE_SIZE", ":#", "Must be power of two." },
|
||||
{ LNK_CmdSwitch_Rad_PathStyle, "RAD_PATH_STYLE", ":{WindowsAbsolute|UnixAbsolute}", "" },
|
||||
{ LNK_CmdSwitch_Rad_PdbHashTypeNameLength, "RAD_PDB_HASH_TYPE_NAME_LENGTH", ":#", "Number of hash bytes to use to replace type name. Default 8 bytes (Max 16)." },
|
||||
{ LNK_CmdSwitch_Rad_PdbHashTypeNameMap, "RAD_PDB_HASH_TYPE_NAME_MAP", ":FILENAME", "Produce map file with hash -> type name mappings." },
|
||||
{ LNK_CmdSwitch_Rad_PdbHashTypeNames, "RAD_PDB_HASH_TYPE_NAMES", ":{NONE|LENIENT|FULL}", "Replace type names in LF_STRUCTURE and LF_CLASS with hashes." },
|
||||
{ LNK_CmdSwitch_Rad_SectVirtOff, "RAD_SECT_VIRT_OFF", ":#", "Set RVA where section data is placed in memory. For internal use only." },
|
||||
{ LNK_CmdSwitch_Rad_SuppressError, "RAD_SUPPRESS_ERROR", ":#", "" },
|
||||
{ LNK_CmdSwitch_Rad_SymbolTableCapDefined, "RAD_SYMBOL_TABLE_CAP_DEFINED", ":#", "Number of buckets allocated in the symbol table for defined symbols." },
|
||||
{ LNK_CmdSwitch_Rad_SymbolTableCapInternal, "RAD_SYMBOL_TABLE_CAP_INTERNAL", ":#", "Number of buckets allocated in the symbol table for internal symbols." },
|
||||
{ LNK_CmdSwitch_Rad_SymbolTableCapLib, "RAD_SYMBOL_TABLE_CAP_LIB", ":#", "Number of buckets allocated in the symbol table for library symbols." },
|
||||
{ LNK_CmdSwitch_Rad_SymbolTableCapWeak, "RAD_SYMBOL_TABLE_CAP_WEAK", ":#", "Number of buckets allocated in the symbol table for weak symbols." },
|
||||
{ LNK_CmdSwitch_Rad_TargetOs, "RAD_TARGET_OS", ":{WINDOWS,LINUX,MAC}" },
|
||||
{ LNK_CmdSwitch_Rad_TimeStamp, "RAD_TIME_STAMP", ":#", "Time stamp embeded in EXE and PDB." },
|
||||
{ LNK_CmdSwitch_Rad_Version, "RAD_VERSION", "", "Print version and exit." },
|
||||
{ LNK_CmdSwitch_Rad_Workers, "RAD_WORKERS", ":#", "Sets number of workers created in the pool. Number is capped at 1024." },
|
||||
|
||||
{ LNK_CmdSwitch_Help, "HELP", "", "" },
|
||||
{ LNK_CmdSwitch_Help, "?", "", "" },
|
||||
@@ -223,6 +229,27 @@ lnk_debug_mode_from_string(String8 string)
|
||||
return LNK_DebugMode_Null;
|
||||
}
|
||||
|
||||
read_only struct
|
||||
{
|
||||
char *name;
|
||||
LNK_TypeNameHashMode mode;
|
||||
} g_type_name_hash_mode_map[] = {
|
||||
{ "none", LNK_TypeNameHashMode_None },
|
||||
{ "lenient", LNK_TypeNameHashMode_Lenient },
|
||||
{ "full", LNK_TypeNameHashMode_Full }
|
||||
};
|
||||
|
||||
internal LNK_TypeNameHashMode
|
||||
lnk_type_name_hash_mode_from_string(String8 string)
|
||||
{
|
||||
for (U64 i = 0; i < ArrayCount(g_type_name_hash_mode_map); ++i) {
|
||||
if (str8_match(str8_cstring(g_type_name_hash_mode_map[i].name), string, StringMatchFlag_CaseInsensitive)) {
|
||||
return g_type_name_hash_mode_map[i].mode;
|
||||
}
|
||||
}
|
||||
return LNK_TypeNameHashMode_Null;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal LNK_CmdOption *
|
||||
@@ -471,22 +498,17 @@ lnk_get_mt_path(Arena *arena)
|
||||
#undef OS_WINDOWS
|
||||
#pragma comment(lib, "shlwapi.lib")
|
||||
#include <shlwapi.h>
|
||||
local_persist wchar_t raw_mt_path[MAX_PATH*2] = L"mt.exe";
|
||||
PathFindOnPathW(&raw_mt_path[0], 0);
|
||||
|
||||
String8 mt_path = str8(0,0);
|
||||
local_persist wchar_t raw_mt_path[MAX_PATH + 1] = L"mt.exe";
|
||||
B32 is_mt_found = PathFindOnPathW(&raw_mt_path[0], 0);
|
||||
if (is_mt_found) {
|
||||
String16 mt_path_16 = str16_cstring(&raw_mt_path[0]);
|
||||
mt_path = str8_from_16(arena, mt_path_16);
|
||||
mt_path = path_convert_slashes(arena, mt_path, PathStyle_WindowsAbsolute);
|
||||
} else {
|
||||
lnk_error(LNK_Error_Cmdl, "mt.exe not found, please specify path with /RAD_MT_PATH or run vcvarsall.bat");
|
||||
}
|
||||
|
||||
String16 mt_path_16 = str16_cstring_capped(&raw_mt_path[0], raw_mt_path + sizeof(raw_mt_path));
|
||||
String8 mt_path = str8_from_16(arena, mt_path_16);
|
||||
|
||||
mt_path = path_convert_slashes(arena, mt_path, PathStyle_WindowsAbsolute);
|
||||
#undef OS_WINDOWS
|
||||
#define OS_WINDOWS 1
|
||||
#else
|
||||
#error "TODO: find llvm-mt"
|
||||
String8 mt_path = str8_lit("llvm-mt.exe");
|
||||
#endif
|
||||
return mt_path;
|
||||
}
|
||||
@@ -791,7 +813,7 @@ lnk_print_help(void)
|
||||
Temp scratch = scratch_begin(0,0);
|
||||
|
||||
fprintf(stdout, "--- Help -------------------------------------------------------\n");
|
||||
fprintf(stdout, " %s\n", BUILD_VERSION_STRING);
|
||||
fprintf(stdout, " %s\n", BUILD_TITLE);
|
||||
fprintf(stdout, "\n");
|
||||
fprintf(stdout, " Usage: rad-link.exe [Options] [Files] [@rsp]\n");
|
||||
fprintf(stdout, "\n");
|
||||
@@ -828,6 +850,39 @@ lnk_print_help(void)
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal String8
|
||||
lnk_expand_env_vars_windows(Arena *arena, HashTable *env_vars, String8 string)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
|
||||
String8List list = {0};
|
||||
for (U64 i = 0; i < string.size; ) {
|
||||
U64 open = str8_find_needle(string, i, str8_lit("%"), 0);
|
||||
U64 close = str8_find_needle(string, open+1, str8_lit("%"), 0);
|
||||
|
||||
String8 text = str8_substr(string, rng_1u64(i, open));
|
||||
str8_list_push(scratch.arena, &list, text);
|
||||
i += text.size;
|
||||
|
||||
if (open < close) {
|
||||
String8 env_var_name = str8_substr(string, rng_1u64(open+1, close));
|
||||
KeyValuePair *match = hash_table_search_path(env_vars, env_var_name);
|
||||
if (match) {
|
||||
str8_list_push(scratch.arena, &list, match->value_string);
|
||||
i = close+1;
|
||||
} else {
|
||||
str8_list_pushf(scratch.arena, &list, "%%%S", env_var_name);
|
||||
i = close;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String8 result = str8_list_join(arena, &list, 0);
|
||||
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal LNK_Config *
|
||||
lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line)
|
||||
{
|
||||
@@ -836,25 +891,21 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line)
|
||||
|
||||
// parse command line
|
||||
String8List unwrapped_cmd_line = lnk_unwrap_rsp(scratch.arena, raw_cmd_line);
|
||||
LNK_CmdLine cmd_line = lnk_cmd_line_parse_windows_rules(scratch.arena, unwrapped_cmd_line);
|
||||
LNK_CmdLine cmd_line = lnk_cmd_line_parse_windows_rules(scratch.arena, unwrapped_cmd_line);
|
||||
|
||||
// setup default flags
|
||||
lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Align, "%u", KB(4));
|
||||
lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Debug, "none");
|
||||
lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_FileAlign, "%u", 512);
|
||||
if (!lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_Fixed)) {
|
||||
lnk_cmd_line_push_optionf(scratch.arena, &cmd_line, LNK_CmdSwitch_DynamicBase, "");
|
||||
}
|
||||
if (lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_Dll)) {
|
||||
lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_SubSystem, "%S", pe_string_from_subsystem(PE_WindowsSubsystem_WINDOWS_GUI));
|
||||
}
|
||||
lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Heap, "%u,%u", MB(1), KB(4));
|
||||
lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_HighEntropyVa, "");
|
||||
lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_ManifestUac, "\"level='asInvoker' uiAccess='false'\"");
|
||||
lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_NxCompat, "");
|
||||
lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_LargeAddressAware, "");
|
||||
lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_PdbAltPath, "%%_RAD_PDB_PATH%%");
|
||||
lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_PdbPageSize, "%u", KB(4));
|
||||
lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Stack, "%u,%u", MB(1), KB(1));
|
||||
lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_TimeStamp, "%u", os_get_process_start_time_unix());
|
||||
lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_Age, "%u", 1);
|
||||
lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_CheckUnusedDelayLoadDll, "");
|
||||
@@ -870,17 +921,18 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line)
|
||||
lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_PathStyle, "system");
|
||||
lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_SectVirtOff, "0x1000");
|
||||
lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_Workers, "%u", os_get_system_info()->logical_processor_count);
|
||||
lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Manifest, "embed");
|
||||
lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_TargetOs, "windows");
|
||||
//lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_Log, "debug");
|
||||
lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_SymbolTableCapDefined, "0x3ffff");
|
||||
lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_SymbolTableCapInternal, "0x1000");
|
||||
lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_SymbolTableCapWeak, "0x3ffff");
|
||||
lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_SymbolTableCapLib, "0x3ffff");
|
||||
lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_DeleteManifest, "");
|
||||
lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_DebugAltPath, "%%_RAD_RDI_PATH%%");
|
||||
|
||||
#if !BUILD_DEBUG
|
||||
//lnk_cmd_line_push_optionf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_SuppressError, "37");
|
||||
#if BUILD_DEBUG
|
||||
lnk_cmd_line_push_optionf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_Log, "debug");
|
||||
lnk_cmd_line_push_optionf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_Log, "io_write");
|
||||
#else
|
||||
lnk_cmd_line_push_optionf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_SuppressError, "%u", LNK_Error_InvalidTypeIndex);
|
||||
#endif
|
||||
|
||||
if (!lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_Rad_MtPath)) {
|
||||
@@ -888,9 +940,17 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line)
|
||||
lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_MtPath, "%S", mt_path);
|
||||
}
|
||||
|
||||
LNK_Config *config = push_array(arena, LNK_Config, 1);
|
||||
config->raw_cmd_line = raw_cmd_line;
|
||||
config->work_dir = os_get_current_path(scratch.arena);
|
||||
LNK_Config *config = push_array(arena, LNK_Config, 1);
|
||||
config->raw_cmd_line = raw_cmd_line;
|
||||
config->work_dir = os_get_current_path(arena);
|
||||
config->build_imp_lib = 1;
|
||||
config->build_exp = 1;
|
||||
config->heap_reserve = MB(1);
|
||||
config->heap_commit = KB(1);
|
||||
config->stack_reserve = MB(1);
|
||||
config->stack_commit = KB(1);
|
||||
config->pdb_hash_type_names = LNK_TypeNameHashMode_None;
|
||||
config->pdb_hash_type_name_length = 8;
|
||||
|
||||
// process command line switches
|
||||
for (LNK_CmdOption *cmd = cmd_line.first_option; cmd != 0; cmd = cmd->next) {
|
||||
@@ -967,6 +1027,9 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line)
|
||||
if (debug_mode == LNK_DebugMode_GHash) {
|
||||
config->debug_mode = LNK_DebugMode_Full;
|
||||
lnk_error_cmd_switch(LNK_Warning_Cmdl, cmd_switch, "GHASH is not supported, switching to FULL");
|
||||
} else if (debug_mode == LNK_DebugMode_FastLink) {
|
||||
config->debug_mode = LNK_DebugMode_Full;
|
||||
lnk_error_cmd_switch(LNK_Warning_Cmdl, cmd_switch, "FASTLINK is not supported, switching to FULL");
|
||||
} else if (debug_mode != LNK_DebugMode_Null) {
|
||||
config->debug_mode = debug_mode;
|
||||
} else {
|
||||
@@ -1135,30 +1198,23 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line)
|
||||
if (param_arr.count > 0) {
|
||||
if (str8_match(param_arr.v[0], str8_lit("embed"), StringMatchFlag_CaseInsensitive)) {
|
||||
config->manifest_opt = LNK_ManifestOpt_Embed;
|
||||
if (config->delete_manifest == LNK_SwitchState_Null) {
|
||||
config->delete_manifest = 1;
|
||||
}
|
||||
|
||||
if (param_arr.count == 1) {
|
||||
if (lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_Dll)) {
|
||||
config->manifest_resource_id = 2;
|
||||
} else {
|
||||
config->manifest_resource_id = 1;
|
||||
}
|
||||
config->manifest_resource_id = 0;
|
||||
} else if (param_arr.count > 1) {
|
||||
// parse resource id
|
||||
if (str8_match(param_arr.v[1], str8_lit("id="), StringMatchFlag_RightSideSloppy|StringMatchFlag_CaseInsensitive)) {
|
||||
String8List res_id_list = str8_split_by_string_chars(scratch.arena, param_arr.v[1], str8_lit("="), 0);
|
||||
String8Array res_id_arr = str8_array_from_list(scratch.arena, &res_id_list);
|
||||
String8List res_id_list = str8_split_by_string_chars(scratch.arena, param_arr.v[1], str8_lit("="), 0);
|
||||
String8Array res_id_arr = str8_array_from_list(scratch.arena, &res_id_list);
|
||||
if (res_id_arr.count == 2) {
|
||||
U64 resource_id;
|
||||
if (try_u64_from_str8_c_rules(res_id_arr.v[1], &resource_id)) {
|
||||
config->manifest_resource_id = resource_id;
|
||||
config->manifest_resource_id = push_u64(arena, resource_id);
|
||||
} else {
|
||||
lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "unable to parse resource_id \"%S\"", res_id_arr.v[1]);
|
||||
}
|
||||
} else {
|
||||
lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "invalid syntax expected form ID=resource_id but got \"%S\"", param_arr.v[1]);
|
||||
lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "invalid syntax expected form ID=# but got \"%S\"", param_arr.v[1]);
|
||||
}
|
||||
} else {
|
||||
lnk_error_cmd_switch_invalid_param(LNK_Error_Cmdl, cmd_switch, param_arr.v[0]);
|
||||
@@ -1175,13 +1231,19 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line)
|
||||
lnk_error_cmd_switch_invalid_param_count(LNK_Error_Cmdl, cmd_switch);
|
||||
}
|
||||
} else if (cmd->value_strings.node_count == 0) {
|
||||
config->manifest_opt = LNK_ManifestOpt_Embed;
|
||||
config->manifest_opt = LNK_ManifestOpt_WriteToFile;
|
||||
} else {
|
||||
lnk_error_cmd_switch_invalid_param_count(LNK_Error_Cmdl, cmd_switch);
|
||||
}
|
||||
} break;
|
||||
|
||||
case LNK_CmdSwitch_ManifestDependency: {
|
||||
String8List manifest_dependency_list = str8_list_copy(arena, &cmd->value_strings);
|
||||
str8_list_concat_in_place(&config->manifest_dependency_list, &manifest_dependency_list);
|
||||
|
||||
if (config->manifest_opt == LNK_ManifestOpt_Null) {
|
||||
config->manifest_opt = LNK_ManifestOpt_WriteToFile;
|
||||
}
|
||||
} break;
|
||||
|
||||
case LNK_CmdSwitch_ManifestFile: {
|
||||
@@ -1262,8 +1324,20 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line)
|
||||
} break;
|
||||
|
||||
case LNK_CmdSwitch_NoDefaultLib: {
|
||||
String8List no_default_lib_list = str8_list_copy(arena, &cmd->value_strings);
|
||||
str8_list_concat_in_place(&config->disallow_lib_list, &no_default_lib_list);
|
||||
if (cmd->value_strings.node_count == 0) {
|
||||
config->no_default_libs = 1;
|
||||
} else {
|
||||
String8List no_default_lib_list = str8_list_copy(arena, &cmd->value_strings);
|
||||
str8_list_concat_in_place(&config->disallow_lib_list, &no_default_lib_list);
|
||||
}
|
||||
} break;
|
||||
|
||||
case LNK_CmdSwitch_NoExp: {
|
||||
config->build_exp = 0;
|
||||
} break;
|
||||
|
||||
case LNK_CmdSwitch_NoImpLib: {
|
||||
config->build_imp_lib = 0;
|
||||
} break;
|
||||
|
||||
case LNK_CmdSwitch_NoLogo: {
|
||||
@@ -1316,6 +1390,11 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line)
|
||||
lnk_cmd_switch_parse_string_copy(arena, cmd->value_strings, cmd_switch, &config->pdb_name);
|
||||
} break;
|
||||
|
||||
case LNK_CmdSwitch_PdbAltPath: {
|
||||
// see :PdbAltPath
|
||||
lnk_cmd_switch_parse_string_copy(arena, cmd->value_strings, cmd_switch, &config->pdb_alt_path);
|
||||
} break;
|
||||
|
||||
case LNK_CmdSwitch_PdbPageSize: {
|
||||
U64 page_size;
|
||||
if (lnk_cmd_switch_parse_u64(cmd->value_strings, cmd_switch, &page_size, LNK_ParseU64Flag_CheckPow2)) {
|
||||
@@ -1412,17 +1491,18 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line)
|
||||
lnk_cmd_switch_parse_flag(cmd->value_strings, cmd_switch, &config->rad_debug);
|
||||
} break;
|
||||
case LNK_CmdSwitch_Rad_DebugName: {
|
||||
// :Rad_DebugAltPath
|
||||
lnk_cmd_switch_parse_string_copy(arena, cmd->value_strings, cmd_switch, &config->rad_debug_name);
|
||||
} break;
|
||||
|
||||
case LNK_CmdSwitch_Rad_DebugAltPath: {
|
||||
lnk_cmd_switch_parse_string_copy(arena, cmd->value_strings, cmd_switch, &config->rad_debug_alt_path);
|
||||
} break;
|
||||
|
||||
case LNK_CmdSwitch_Rad_DelayBind: {
|
||||
lnk_cmd_switch_set_flag_64(cmd->value_strings, cmd_switch, &config->flags, LNK_ConfigFlag_DelayBind);
|
||||
} break;
|
||||
|
||||
case LNK_CmdSwitch_Rad_DeleteManifest: {
|
||||
lnk_cmd_switch_parse_flag(cmd->value_strings, cmd_switch, &config->delete_manifest);
|
||||
} break;
|
||||
|
||||
case LNK_CmdSwitch_Rad_DoMerge: {
|
||||
lnk_cmd_switch_set_flag_64(cmd->value_strings, cmd_switch, &config->flags, LNK_ConfigFlag_Merge);
|
||||
} break;
|
||||
@@ -1442,8 +1522,8 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line)
|
||||
} else if (str8_match(cmd->value_strings.first->string, str8_lit("random"), StringMatchFlag_CaseInsensitive)) {
|
||||
config->guid = os_make_guid();
|
||||
} else {
|
||||
OS_Guid guid;
|
||||
if (os_try_guid_from_string(cmd->value_strings.first->string, &guid)) {
|
||||
Guid guid;
|
||||
if (try_guid_from_string(cmd->value_strings.first->string, &guid)) {
|
||||
config->guid = guid;
|
||||
} else {
|
||||
lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "unable to parse \"%S\"", cmd->value_strings.first->string);
|
||||
@@ -1454,6 +1534,10 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line)
|
||||
}
|
||||
} break;
|
||||
|
||||
case LNK_CmdSwitch_Rad_IdleWorkers: {
|
||||
lnk_cmd_switch_parse_u64(cmd->value_strings, cmd_switch, &config->idle_worker_count, 0);
|
||||
} break;
|
||||
|
||||
case LNK_CmdSwitch_Rad_LargePages: {
|
||||
if (cmd->value_strings.node_count == 0) {
|
||||
OS_ProcessInfo *process_info = os_get_process_info();
|
||||
@@ -1497,6 +1581,9 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line)
|
||||
for (U64 ilog = 0; ilog < LNK_Log_Count; ilog += 1) {
|
||||
lnk_set_log_status((LNK_LogType)ilog, 1);
|
||||
}
|
||||
} else if (str8_match(cmd->value_strings.first->string, str8_lit("io"), StringMatchFlag_CaseInsensitive)) {
|
||||
lnk_set_log_status(LNK_Log_IO_Read, 1);
|
||||
lnk_set_log_status(LNK_Log_IO_Write, 1);
|
||||
} else {
|
||||
LNK_LogType log_type = lnk_log_type_from_string(cmd->value_strings.first->string);
|
||||
if (log_type == LNK_Log_Null) {
|
||||
@@ -1535,6 +1622,30 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line)
|
||||
}
|
||||
} break;
|
||||
|
||||
case LNK_CmdSwitch_Rad_PdbHashTypeNames: {
|
||||
String8 mode_string = str8_list_first(&cmd->value_strings);
|
||||
|
||||
LNK_TypeNameHashMode mode;
|
||||
if (mode_string.size == 0) {
|
||||
config->pdb_hash_type_names = LNK_TypeNameHashMode_Lenient;
|
||||
} else {
|
||||
mode = lnk_type_name_hash_mode_from_string(mode_string);
|
||||
if (mode == LNK_TypeNameHashMode_Null) {
|
||||
lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "unknown parameter: \"%S\"", mode_string);
|
||||
} else {
|
||||
config->pdb_hash_type_names = mode;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
case LNK_CmdSwitch_Rad_PdbHashTypeNameMap: {
|
||||
lnk_cmd_switch_parse_string_copy(arena, cmd->value_strings, cmd_switch, &config->pdb_hash_type_name_map);
|
||||
} break;
|
||||
|
||||
case LNK_CmdSwitch_Rad_PdbHashTypeNameLength: {
|
||||
lnk_cmd_switch_parse_u64(cmd->value_strings, cmd_switch, &config->pdb_hash_type_name_length, 0);
|
||||
} break;
|
||||
|
||||
case LNK_CmdSwitch_Rad_SectVirtOff: {
|
||||
U64 sect_virt_off;
|
||||
if (lnk_cmd_switch_parse_u64(cmd->value_strings, cmd_switch, §_virt_off, LNK_ParseU64Flag_CheckUnder32bit)) {
|
||||
@@ -1609,16 +1720,19 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line)
|
||||
}
|
||||
}
|
||||
|
||||
// apply idle workers switch
|
||||
if (config->idle_worker_count > 0) {
|
||||
if (config->idle_worker_count < config->worker_count) {
|
||||
U64 final_worker_count = config->worker_count - config->idle_worker_count;
|
||||
config->worker_count = final_worker_count;
|
||||
} else {
|
||||
lnk_error_cmd_switch(LNK_Warning_Cmdl, LNK_CmdSwitch_Rad_IdleWorkers, "idle worker count %u exceeds total worker count %u", config->idle_worker_count, config->worker_count);
|
||||
}
|
||||
}
|
||||
|
||||
// :manifest_input
|
||||
if (lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_ManifestInput)) {
|
||||
switch (config->manifest_opt) {
|
||||
case LNK_ManifestOpt_Null: {
|
||||
lnk_error_cmd_switch(LNK_Error_Cmdl, LNK_CmdSwitch_ManifestInput, "missing /MANIFEST:EMBED");
|
||||
} break;
|
||||
case LNK_ManifestOpt_No: {
|
||||
lnk_error_cmd_switch(LNK_Warning_Cmdl, LNK_CmdSwitch_ManifestInput, "missing /MANIFEST:EMBED, ignoring inputs");
|
||||
} break;
|
||||
case LNK_ManifestOpt_Embed: {
|
||||
if (config->manifest_opt == LNK_ManifestOpt_Embed) {
|
||||
for (LNK_CmdOption *cmd = cmd_line.first_option; cmd != 0; cmd = cmd->next) {
|
||||
LNK_CmdSwitchType cmd_switch = lnk_cmd_switch_type_from_string(cmd->string);
|
||||
if (cmd_switch == LNK_CmdSwitch_ManifestInput) {
|
||||
@@ -1626,7 +1740,17 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line)
|
||||
str8_list_concat_in_place(&config->input_list[LNK_Input_Manifest], &manifest_list);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
} else {
|
||||
lnk_error_cmd_switch(LNK_Error_Cmdl, LNK_CmdSwitch_ManifestInput, "missing /MANIFEST:EMBED");
|
||||
}
|
||||
}
|
||||
|
||||
// set default manifest resource id
|
||||
if (config->manifest_resource_id == 0) {
|
||||
if (config->file_characteristics & PE_ImageFileCharacteristic_FILE_DLL) {
|
||||
config->manifest_resource_id = push_u64(arena, 2);
|
||||
} else {
|
||||
config->manifest_resource_id = push_u64(arena, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1658,27 +1782,6 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line)
|
||||
config->flags &= ~LNK_ConfigFlag_DelayBind;
|
||||
}
|
||||
|
||||
// gather lib paths from enviroment string
|
||||
if (config->flags & LNK_ConfigFlag_EnvLib) {
|
||||
#if OS_WINDOWS
|
||||
OS_ProcessInfo *process_info = os_get_process_info();
|
||||
for (String8Node *node = process_info->environment.first; node != 0; node = node->next) {
|
||||
String8List var_list = str8_split_by_string_chars(scratch.arena, node->string, str8_lit("="), 0);
|
||||
if (var_list.node_count != 2) {
|
||||
continue;
|
||||
}
|
||||
String8 key = var_list.first->string;
|
||||
String8 val = var_list.last->string;
|
||||
if (str8_match(key, str8_lit("Lib"), StringMatchFlag_CaseInsensitive) ||
|
||||
str8_match(key, str8_lit("LibPath"), StringMatchFlag_CaseInsensitive)) {
|
||||
String8List val_list = str8_split_by_string_chars(scratch.arena, val, str8_lit(";"), 0);
|
||||
String8List val_list_copy = str8_list_copy(arena, &val_list);
|
||||
str8_list_concat_in_place(&config->lib_dir_list, &val_list_copy);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// set flags for /OPT
|
||||
{
|
||||
// these flags remove and merge inline functions and methods defined in class,
|
||||
@@ -1720,6 +1823,11 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line)
|
||||
config->file_characteristics |= PE_ImageFileCharacteristic_STRIPPED;
|
||||
config->dll_characteristics &= ~PE_DllCharacteristic_DYNAMIC_BASE;
|
||||
}
|
||||
// if we don't have a fixed image and dynamic base switch
|
||||
// was omitted we make image with dynamic base
|
||||
else if (!lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_DynamicBase)) {
|
||||
config->dll_characteristics |= PE_DllCharacteristic_DYNAMIC_BASE;
|
||||
}
|
||||
|
||||
// set flag for /guard
|
||||
if (config->guard_flags != LNK_Guard_None) {
|
||||
@@ -1732,31 +1840,83 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line)
|
||||
String8 ext = (config->file_characteristics & PE_ImageFileCharacteristic_FILE_DLL) ? str8_lit("dll") : str8_lit("exe");
|
||||
config->image_name = make_file_path_with_ext(scratch.arena, name, ext);
|
||||
}
|
||||
config->image_name = os_make_full_path(arena, config->image_name);
|
||||
config->image_name = os_full_path_from_path(arena, config->image_name);
|
||||
|
||||
// handle empty /PDB
|
||||
if (!lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_Pdb)) {
|
||||
config->pdb_name = make_file_path_with_ext(arena, config->image_name, str8_lit("pdb"));
|
||||
}
|
||||
config->pdb_name = os_make_full_path(arena, config->pdb_name);
|
||||
config->pdb_name = os_full_path_from_path(arena, config->pdb_name);
|
||||
|
||||
// handle empty /RAD_DEBUG_NAME
|
||||
if (!lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_Rad_DebugName)) {
|
||||
config->rad_debug_name = make_file_name_with_ext(arena, config->image_name, str8_lit("rdi"));
|
||||
}
|
||||
config->rad_debug_name = os_make_full_path(arena, config->rad_debug_name);
|
||||
config->rad_debug_name = os_full_path_from_path(arena, config->rad_debug_name);
|
||||
|
||||
// handle empty /IMPLIB
|
||||
if (!lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_ImpLib)) {
|
||||
config->imp_lib_name = make_file_name_with_ext(arena, config->image_name, str8_lit("lib"));
|
||||
}
|
||||
config->imp_lib_name = os_make_full_path(arena, config->imp_lib_name);
|
||||
config->imp_lib_name = os_full_path_from_path(arena, config->imp_lib_name);
|
||||
|
||||
// handle empty /MANIFESTFILE
|
||||
if (!lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_ManifestFile)) {
|
||||
config->manifest_name = make_file_path_with_ext(arena, config->image_name, str8_lit("manifest"));
|
||||
config->manifest_name = push_str8f(arena, "%S.manifest", config->image_name);
|
||||
}
|
||||
|
||||
// collect env vars
|
||||
HashTable *env_vars = hash_table_init(scratch.arena, 512);
|
||||
{
|
||||
#if OS_WINDOWS
|
||||
OS_ProcessInfo *process_info = os_get_process_info();
|
||||
for (String8Node *node = process_info->environment.first; node != 0; node = node->next) {
|
||||
String8List list = str8_split_by_string_chars(scratch.arena, node->string, str8_lit("="), 0);
|
||||
|
||||
String8 key = list.first->string;
|
||||
String8 val = str8_zero();
|
||||
if (list.node_count == 2) {
|
||||
val = list.last->string;
|
||||
} else if (list.node_count > 2) {
|
||||
U64 sep_idx = str8_find_needle(node->string, node->string.size, str8_lit("="), 0);
|
||||
val = str8_skip(node->string, sep_idx+1);
|
||||
}
|
||||
|
||||
hash_table_push_path_string(scratch.arena, env_vars, key, val);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// define linker env vars
|
||||
hash_table_push_path_string(scratch.arena, env_vars, str8_lit("_pdb"), str8_skip_last_slash(config->pdb_name));
|
||||
hash_table_push_path_string(scratch.arena, env_vars, str8_lit("_ext"), str8_skip_last_dot(config->image_name));
|
||||
hash_table_push_path_string(scratch.arena, env_vars, str8_lit("_rad_pdb_path"), config->pdb_name);
|
||||
hash_table_push_path_string(scratch.arena, env_vars, str8_lit("_rad_rdi"), str8_skip_last_slash(config->rad_debug_name));
|
||||
hash_table_push_path_string(scratch.arena, env_vars, str8_lit("_rad_rdi_path"), config->rad_debug_name);
|
||||
|
||||
// collect LIB and LIBPATH
|
||||
if (config->flags & LNK_ConfigFlag_EnvLib) {
|
||||
KeyValuePair *lib = hash_table_search_path(env_vars, str8_lit("lib"));
|
||||
if (lib) {
|
||||
String8List val_list = str8_split_by_string_chars(scratch.arena, lib->value_string, str8_lit(";"), 0);
|
||||
String8List val_list_copy = str8_list_copy(arena, &val_list);
|
||||
str8_list_concat_in_place(&config->lib_dir_list, &val_list_copy);
|
||||
}
|
||||
|
||||
KeyValuePair *lib_path = hash_table_search_path(env_vars, str8_lit("libpath"));
|
||||
if (lib_path) {
|
||||
String8List val_list = str8_split_by_string_chars(scratch.arena, lib->value_string, str8_lit(";"), 0);
|
||||
String8List val_list_copy = str8_list_copy(arena, &val_list);
|
||||
str8_list_concat_in_place(&config->lib_dir_list, &val_list_copy);
|
||||
}
|
||||
}
|
||||
|
||||
// :PdbAltPath
|
||||
config->pdb_alt_path = lnk_expand_env_vars_windows(arena, env_vars, config->pdb_alt_path);
|
||||
|
||||
// :Rad_DebugAltPath
|
||||
config->rad_debug_alt_path = lnk_expand_env_vars_windows(arena, env_vars, config->rad_debug_alt_path);
|
||||
|
||||
if (lnk_get_log_status(LNK_Log_Debug)) {
|
||||
String8 full_cmd_line = str8_list_join(scratch.arena, &raw_cmd_line, &(StringJoin){ .sep = str8_lit_comp(" ") });
|
||||
lnk_log(LNK_Log_Debug, "--------------------------------------------------------------------------------");
|
||||
@@ -1777,10 +1937,8 @@ lnk_build_config(Arena *arena, int argc, char **argv)
|
||||
|
||||
String8List raw_cmd_line = os_string_list_from_argcv(arena, argc, argv);
|
||||
|
||||
#if OS_WINDOWS
|
||||
// remove exe name first argument
|
||||
str8_list_pop_front(&raw_cmd_line);
|
||||
#endif
|
||||
|
||||
// init config
|
||||
LNK_Config *config = lnk_config_from_cmd_line(arena, raw_cmd_line);
|
||||
|
||||
+34
-11
@@ -42,11 +42,14 @@ typedef enum
|
||||
LNK_CmdSwitch_ManifestUac,
|
||||
LNK_CmdSwitch_Natvis,
|
||||
LNK_CmdSwitch_NoDefaultLib,
|
||||
LNK_CmdSwitch_NoExp,
|
||||
LNK_CmdSwitch_NoImpLib,
|
||||
LNK_CmdSwitch_NoLogo,
|
||||
LNK_CmdSwitch_NxCompat,
|
||||
LNK_CmdSwitch_Opt,
|
||||
LNK_CmdSwitch_Out,
|
||||
LNK_CmdSwitch_Pdb,
|
||||
LNK_CmdSwitch_PdbAltPath,
|
||||
LNK_CmdSwitch_PdbPageSize,
|
||||
LNK_CmdSwitch_Stack,
|
||||
LNK_CmdSwitch_SubSystem,
|
||||
@@ -95,8 +98,6 @@ typedef enum
|
||||
LNK_CmdSwitch_Midl,
|
||||
LNK_CmdSwitch_NoAssembly,
|
||||
LNK_CmdSwitch_NoEntry,
|
||||
LNK_CmdSwitch_NoExp,
|
||||
LNK_CmdSwitch_NoImpLib,
|
||||
LNK_CmdSwitch_Order,
|
||||
LNK_CmdSwitch_PdbStripped,
|
||||
LNK_CmdSwitch_Profile,
|
||||
@@ -122,12 +123,13 @@ typedef enum
|
||||
LNK_CmdSwitch_Rad_CheckUnusedDelayLoadDll,
|
||||
LNK_CmdSwitch_Rad_Debug,
|
||||
LNK_CmdSwitch_Rad_DebugName,
|
||||
LNK_CmdSwitch_Rad_DebugAltPath,
|
||||
LNK_CmdSwitch_Rad_DelayBind,
|
||||
LNK_CmdSwitch_Rad_DeleteManifest,
|
||||
LNK_CmdSwitch_Rad_DoMerge,
|
||||
LNK_CmdSwitch_Rad_EnvLib,
|
||||
LNK_CmdSwitch_Rad_Exe,
|
||||
LNK_CmdSwitch_Rad_Guid,
|
||||
LNK_CmdSwitch_Rad_IdleWorkers,
|
||||
LNK_CmdSwitch_Rad_LargePages,
|
||||
LNK_CmdSwitch_Rad_LinkVer,
|
||||
LNK_CmdSwitch_Rad_Log,
|
||||
@@ -136,6 +138,9 @@ typedef enum
|
||||
LNK_CmdSwitch_Rad_OsVer,
|
||||
LNK_CmdSwitch_Rad_PageSize,
|
||||
LNK_CmdSwitch_Rad_PathStyle,
|
||||
LNK_CmdSwitch_Rad_PdbHashTypeNames,
|
||||
LNK_CmdSwitch_Rad_PdbHashTypeNameMap,
|
||||
LNK_CmdSwitch_Rad_PdbHashTypeNameLength,
|
||||
LNK_CmdSwitch_Rad_SectVirtOff,
|
||||
LNK_CmdSwitch_Rad_SuppressError,
|
||||
LNK_CmdSwitch_Rad_SymbolTableCapDefined,
|
||||
@@ -205,8 +210,9 @@ typedef U32 LNK_GuardFlags;
|
||||
typedef enum
|
||||
{
|
||||
LNK_ManifestOpt_Null,
|
||||
LNK_ManifestOpt_WriteToFile,
|
||||
LNK_ManifestOpt_Embed,
|
||||
LNK_ManifestOpt_No
|
||||
LNK_ManifestOpt_No,
|
||||
} LNK_ManifestOpt;
|
||||
|
||||
typedef struct LNK_AltNameList
|
||||
@@ -221,6 +227,14 @@ typedef enum
|
||||
Lnk_DebugInfoGuid_ImageBlake3,
|
||||
} LNK_DebugInfoGuidType;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LNK_TypeNameHashMode_Null,
|
||||
LNK_TypeNameHashMode_None,
|
||||
LNK_TypeNameHashMode_Lenient,
|
||||
LNK_TypeNameHashMode_Full,
|
||||
} LNK_TypeNameHashMode;
|
||||
|
||||
typedef struct LNK_Config
|
||||
{
|
||||
LNK_ConfigFlags flags;
|
||||
@@ -231,7 +245,7 @@ typedef struct LNK_Config
|
||||
U64 opt_iter_count;
|
||||
LNK_GuardFlags guard_flags;
|
||||
LNK_DebugInfoGuidType guid_type;
|
||||
OS_Guid guid;
|
||||
Guid guid;
|
||||
COFF_TimeStamp time_stamp;
|
||||
U32 age;
|
||||
U64 section_virt_off;
|
||||
@@ -246,8 +260,10 @@ typedef struct LNK_Config
|
||||
U64 page_size;
|
||||
U64 pdb_page_size;
|
||||
U64 worker_count;
|
||||
U64 idle_worker_count;
|
||||
U64 function_pad_min;
|
||||
U64 manifest_resource_id;
|
||||
U64 *manifest_resource_id;
|
||||
B32 no_default_libs;
|
||||
Version link_ver;
|
||||
Version os_ver;
|
||||
Version image_ver;
|
||||
@@ -267,13 +283,16 @@ typedef struct LNK_Config
|
||||
String8 imp_lib_name;
|
||||
String8List raw_cmd_line;
|
||||
String8 pdb_name;
|
||||
String8 pdb_alt_path;
|
||||
String8 mt_path;
|
||||
LNK_TypeNameHashMode pdb_hash_type_names;
|
||||
String8 pdb_hash_type_name_map;
|
||||
U64 pdb_hash_type_name_length;
|
||||
String8List input_list[LNK_Input_Count];
|
||||
String8List input_default_lib_list;
|
||||
String8List disallow_lib_list;
|
||||
String8List delay_load_dll_list;
|
||||
String8List natvis_list;
|
||||
LNK_SwitchState delete_manifest;
|
||||
String8 manifest_name;
|
||||
B32 manifest_uac;
|
||||
String8 manifest_level;
|
||||
@@ -281,12 +300,15 @@ typedef struct LNK_Config
|
||||
String8List manifest_dependency_list;
|
||||
LNK_SwitchState rad_debug;
|
||||
String8 rad_debug_name;
|
||||
String8 rad_debug_alt_path;
|
||||
String8List include_symbol_list;
|
||||
LNK_AltNameList alt_name_list;
|
||||
U64 symbol_table_cap_defined;
|
||||
U64 symbol_table_cap_internal;
|
||||
U64 symbol_table_cap_weak;
|
||||
U64 symbol_table_cap_lib;
|
||||
B32 build_imp_lib;
|
||||
B32 build_exp;
|
||||
} LNK_Config;
|
||||
|
||||
typedef enum
|
||||
@@ -425,10 +447,11 @@ typedef enum
|
||||
////////////////////////////////
|
||||
// Enum <-> String
|
||||
|
||||
internal String8 lnk_string_cmd_switch_type(LNK_CmdSwitchType type);
|
||||
internal LNK_CmdSwitchType lnk_cmd_switch_from_string(String8 string);
|
||||
internal LNK_InputType lnk_input_type_from_string(String8 string);
|
||||
internal LNK_DebugMode lnk_debug_mode_from_string(String8 string);
|
||||
internal String8 lnk_string_cmd_switch_type(LNK_CmdSwitchType type);
|
||||
internal LNK_CmdSwitchType lnk_cmd_switch_from_string(String8 string);
|
||||
internal LNK_InputType lnk_input_type_from_string(String8 string);
|
||||
internal LNK_DebugMode lnk_debug_mode_from_string(String8 string);
|
||||
internal LNK_TypeNameHashMode lnk_type_name_hash_mode_from_string(String8 string);
|
||||
|
||||
////////////////////////////////
|
||||
// Command Line Helpers
|
||||
|
||||
+257
-49
@@ -382,9 +382,7 @@ lnk_make_code_view_input(TP_Context *tp, TP_Arena *tp_arena, String8List lib_dir
|
||||
ProfEnd();
|
||||
|
||||
if (lnk_get_log_status(LNK_Log_Debug) || PROFILE_TELEMETRY) {
|
||||
U64 total_debug_s_size = 0;
|
||||
U64 total_debug_t_size = 0;
|
||||
U64 total_debug_p_size = 0;
|
||||
U64 total_debug_s_size = 0, total_debug_t_size = 0, total_debug_p_size = 0;
|
||||
for (U64 obj_idx = 0; obj_idx < obj_count; ++obj_idx) {
|
||||
for (LNK_ChunkNode *chunk = debug_s_list_arr[obj_idx].first; chunk != 0; chunk = chunk->next) {
|
||||
total_debug_s_size += chunk->data->u.leaf.size;
|
||||
@@ -396,19 +394,16 @@ lnk_make_code_view_input(TP_Context *tp, TP_Arena *tp_arena, String8List lib_dir
|
||||
total_debug_p_size += chunk->data->u.leaf.size;
|
||||
}
|
||||
}
|
||||
String8 total_debug_s_size_string = str8_from_memory_size2(scratch.arena, total_debug_s_size);
|
||||
String8 total_debug_t_size_string = str8_from_memory_size2(scratch.arena, total_debug_t_size);
|
||||
String8 total_debug_p_size_string = str8_from_memory_size2(scratch.arena, total_debug_p_size);
|
||||
|
||||
ProfNoteV("Total .debug$S Input Size: %M", total_debug_s_size);
|
||||
ProfNoteV("Total .debug$T Input Size: %M", total_debug_t_size);
|
||||
ProfNoteV("Total .debug$P Input Size: %M", total_debug_p_size);
|
||||
|
||||
if (lnk_get_log_status(LNK_Log_Debug)) {
|
||||
lnk_log(LNK_Log_Debug, "[Total .debug$S Input Size %S]", total_debug_s_size_string);
|
||||
lnk_log(LNK_Log_Debug, "[Total .debug$T Input Size %S]", total_debug_t_size_string);
|
||||
lnk_log(LNK_Log_Debug, "[Total .debug$P Input Size %S]", total_debug_p_size_string);
|
||||
lnk_log(LNK_Log_Debug, "[Total .debug$S Input Size %M]", total_debug_s_size);
|
||||
lnk_log(LNK_Log_Debug, "[Total .debug$T Input Size %M]", total_debug_t_size);
|
||||
lnk_log(LNK_Log_Debug, "[Total .debug$P Input Size %M]", total_debug_p_size);
|
||||
}
|
||||
#if PROFILE_TELEMETRY
|
||||
tmMessage(0, TMMF_ICON_NOTE, "Total .debug$S Input Size: %.*s", str8_varg(total_debug_s_size_string));
|
||||
tmMessage(0, TMMF_ICON_NOTE, "Total .debug$T Input Size: %.*s", str8_varg(total_debug_t_size_string));
|
||||
tmMessage(0, TMMF_ICON_NOTE, "Total .debug$P Input Size: %.*s", str8_varg(total_debug_p_size_string));
|
||||
#endif
|
||||
}
|
||||
|
||||
// TODO: temp hack, remove when we have null obj with .debug$T
|
||||
@@ -579,14 +574,14 @@ lnk_make_code_view_input(TP_Context *tp, TP_Arena *tp_arena, String8List lib_dir
|
||||
CV_TypeServerInfo ts = cv_type_server_info_from_leaf(leaf);
|
||||
|
||||
// search disk for type server
|
||||
String8List match_list = os_file_search(scratch.arena, lib_dir_list, ts.name);
|
||||
String8List match_list = lnk_file_search(scratch.arena, lib_dir_list, ts.name);
|
||||
|
||||
// chop file name from path and search on it
|
||||
//
|
||||
// TODO: check if ts.name is a path and in that case do file search
|
||||
if (match_list.node_count == 0) {
|
||||
String8 file_name = str8_skip_last_slash(ts.name);
|
||||
match_list = os_file_search(scratch.arena, lib_dir_list, file_name);
|
||||
match_list = lnk_file_search(scratch.arena, lib_dir_list, file_name);
|
||||
}
|
||||
|
||||
B32 do_debug_info_discard = 0;
|
||||
@@ -690,7 +685,7 @@ lnk_make_code_view_input(TP_Context *tp, TP_Arena *tp_arena, String8List lib_dir
|
||||
// read type servers from disk in parallel
|
||||
{
|
||||
ProfBegin("Read External Type Servers");
|
||||
String8Array msf_data_arr = os_data_from_file_path_parallel(tp, scratch.arena, ts_path_arr);
|
||||
String8Array msf_data_arr = lnk_read_data_from_file_path_parallel(tp, scratch.arena, ts_path_arr);
|
||||
ProfEnd();
|
||||
|
||||
MSF_Parsed **msf_parse_arr = lnk_msf_parsed_from_data_parallel(tp_arena, tp, msf_data_arr);
|
||||
@@ -708,8 +703,8 @@ lnk_make_code_view_input(TP_Context *tp, TP_Arena *tp_arena, String8List lib_dir
|
||||
pdb_info_parse_from_data(msf_parse->streams[PDB_FixedStream_Info], &info_parse);
|
||||
if (!MemoryMatchStruct(&info_parse.guid, &ts_info_arr[ts_idx].sig)) {
|
||||
Temp scratch = scratch_begin(0,0);
|
||||
String8 expected_sig_str = os_string_from_guid(scratch.arena, ts_info_arr[ts_idx].sig);
|
||||
String8 on_disk_sig_str = os_string_from_guid(scratch.arena, info_parse.guid);
|
||||
String8 expected_sig_str = string_from_guid(scratch.arena, ts_info_arr[ts_idx].sig);
|
||||
String8 on_disk_sig_str = string_from_guid(scratch.arena, info_parse.guid);
|
||||
lnk_error(LNK_Warning_MismatchedTypeServerSignature, "%S: signature mismatch in type server read from disk, expected %S, got %S",
|
||||
ts_info_arr[ts_idx].name, expected_sig_str, on_disk_sig_str);
|
||||
scratch_end(scratch);
|
||||
@@ -2476,6 +2471,211 @@ lnk_import_types(TP_Context *tp, TP_Arena *tp_temp, LNK_CodeViewInput *input)
|
||||
return types;
|
||||
}
|
||||
|
||||
internal U64
|
||||
lnk_format_u128(U8 *buf, U64 buf_max, U64 length, U128 v)
|
||||
{
|
||||
U64 size = 0;
|
||||
if (length > 0 && buf_max > 0) {
|
||||
if (length <= 8) {
|
||||
U64 mask = length == 8 ? max_U64 : (1ull << (length*8)) - 1;
|
||||
size = raddbg_snprintf((char*)buf, buf_max - 1, "%llX", (long long)(v.u64[0] & mask));
|
||||
} else {
|
||||
U64 mask1 = length == 16 ? max_U64 : (1ull << ((length-8)*8)) - 1;
|
||||
size = raddbg_snprintf((char*)buf, buf_max, "%llX%llX", (long long)(v.u64[1] & mask1), (long long)v.u64[0]);
|
||||
}
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
internal
|
||||
THREAD_POOL_TASK_FUNC(lnk_replace_type_names_with_hashes_lenient_task)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
|
||||
LNK_TypeNameReplacer *task = raw_task;
|
||||
Rng1U64 range = task->ranges[task_id];
|
||||
CV_DebugT debug_t = task->debug_t;
|
||||
U64 hash_length = task->hash_length;
|
||||
|
||||
B32 make_map = task->make_map;
|
||||
Arena *map_arena = 0;
|
||||
String8List *map = 0;
|
||||
if (make_map) {
|
||||
map_arena = task->map_arena->v[task_id];
|
||||
map = &task->maps[task_id];
|
||||
}
|
||||
|
||||
U64 hash_max_chars = hash_length;
|
||||
U8 temp[128];
|
||||
|
||||
for (U64 leaf_idx = range.min; leaf_idx < range.max; ++leaf_idx) {
|
||||
CV_Leaf leaf = cv_debug_t_get_leaf(debug_t, leaf_idx);
|
||||
if (leaf.kind == CV_LeafKind_STRUCTURE || leaf.kind == CV_LeafKind_CLASS) {
|
||||
CV_UDTInfo udt_info = cv_get_udt_info(leaf.kind, leaf.data);
|
||||
|
||||
if (udt_info.props & CV_TypeProp_HasUniqueName && udt_info.unique_name.size > hash_max_chars) {
|
||||
// hash unique name
|
||||
U128 name_hash;
|
||||
blake3_hasher hasher; blake3_hasher_init(&hasher);
|
||||
blake3_hasher_update(&hasher, udt_info.unique_name.str, udt_info.unique_name.size);
|
||||
blake3_hasher_finalize(&hasher, (U8*)&name_hash, sizeof(name_hash));
|
||||
|
||||
// emit hash -> unique name map
|
||||
if (make_map) {
|
||||
lnk_format_u128(temp, sizeof(temp), hash_length, name_hash);
|
||||
str8_list_pushf(map_arena, map, "%s %.*s\n", temp, str8_varg(udt_info.unique_name));
|
||||
}
|
||||
|
||||
// parse leaf size
|
||||
CV_NumericParsed dummy;
|
||||
U64 numeric_size = cv_read_numeric(leaf.data, sizeof(CV_LeafStruct), &dummy);
|
||||
|
||||
U64 colon_pos = str8_find_needle_reverse(udt_info.name, 0, str8_lit("<lambda_"), 0);
|
||||
B32 is_lambda = colon_pos != 0;
|
||||
|
||||
if (is_lambda) {
|
||||
// replace display type string with unique type name hash
|
||||
udt_info.name.size = lnk_format_u128(udt_info.name.str, udt_info.name.size, hash_length, name_hash);
|
||||
|
||||
// update leaf header
|
||||
CV_LeafHeader *header = cv_debug_t_get_leaf_header(debug_t, leaf_idx);
|
||||
header->size = sizeof(CV_LeafKind) + sizeof(CV_LeafStruct) + numeric_size + udt_info.name.size + 1;
|
||||
|
||||
// discard unique name
|
||||
CV_LeafStruct *lf = (CV_LeafStruct *)(header + 1);
|
||||
lf->props &= ~CV_TypeProp_HasUniqueName;
|
||||
} else {
|
||||
// replace uniuqe type name with hash
|
||||
udt_info.unique_name.str = udt_info.name.str + udt_info.name.size + 1;
|
||||
udt_info.unique_name.size = lnk_format_u128(udt_info.unique_name.str, udt_info.unique_name.size, hash_length, name_hash);
|
||||
|
||||
// update leaf header
|
||||
CV_LeafHeader *header = cv_debug_t_get_leaf_header(debug_t, leaf_idx);
|
||||
header->size = sizeof(CV_LeafKind) +
|
||||
sizeof(CV_LeafStruct) +
|
||||
numeric_size +
|
||||
udt_info.name.size + 1 +
|
||||
udt_info.unique_name.size + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ProfEnd();
|
||||
}
|
||||
|
||||
internal
|
||||
THREAD_POOL_TASK_FUNC(lnk_replace_type_names_with_hashes_full_task)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
|
||||
LNK_TypeNameReplacer *task = raw_task;
|
||||
Rng1U64 range = task->ranges[task_id];
|
||||
CV_DebugT debug_t = task->debug_t;
|
||||
U64 hash_length = task->hash_length;
|
||||
|
||||
B32 make_map = task->make_map;
|
||||
Arena *map_arena = 0;
|
||||
String8List *map = 0;
|
||||
if (make_map) {
|
||||
map_arena = task->map_arena->v[task_id];
|
||||
map = &task->maps[task_id];
|
||||
}
|
||||
|
||||
U64 hash_max_chars = hash_length*2;
|
||||
U8 temp[128];
|
||||
|
||||
for (U64 leaf_idx = range.min; leaf_idx < range.max; ++leaf_idx) {
|
||||
CV_Leaf leaf = cv_debug_t_get_leaf(debug_t, leaf_idx);
|
||||
if (leaf.kind == CV_LeafKind_STRUCTURE || leaf.kind == CV_LeafKind_CLASS) {
|
||||
CV_UDTInfo udt_info = cv_get_udt_info(leaf.kind, leaf.data);
|
||||
|
||||
if (udt_info.name.size > hash_max_chars) {
|
||||
// pick name to hash
|
||||
String8 name;
|
||||
if (udt_info.props & CV_TypeProp_HasUniqueName) {
|
||||
name = udt_info.unique_name;
|
||||
} else {
|
||||
name = udt_info.name;
|
||||
}
|
||||
|
||||
// hash name
|
||||
U128 name_hash;
|
||||
blake3_hasher hasher; blake3_hasher_init(&hasher);
|
||||
blake3_hasher_update(&hasher, udt_info.name.str, udt_info.name.size);
|
||||
blake3_hasher_finalize(&hasher, (U8*)&name_hash, sizeof(name_hash));
|
||||
|
||||
// emit hash -> name map
|
||||
if (make_map) {
|
||||
lnk_format_u128(temp, sizeof(temp), hash_length, name_hash);
|
||||
str8_list_pushf(map_arena, map, "%s %.*s\n", temp, str8_varg(name));
|
||||
}
|
||||
|
||||
// replace name with hash
|
||||
udt_info.name.size = lnk_format_u128(udt_info.name.str, udt_info.name.size, hash_length, name_hash);
|
||||
|
||||
// parse struct size
|
||||
CV_NumericParsed dummy;
|
||||
U64 numeric_size = cv_read_numeric(leaf.data, sizeof(CV_LeafStruct), &dummy);
|
||||
|
||||
// update header
|
||||
CV_LeafHeader *header = cv_debug_t_get_leaf_header(debug_t, leaf_idx);
|
||||
header->size = sizeof(CV_LeafKind) + sizeof(CV_LeafStruct) + numeric_size + udt_info.name.size + 1;
|
||||
|
||||
// discard unique name
|
||||
CV_LeafStruct *lf = (CV_LeafStruct *)(header + 1);
|
||||
lf->props &= ~CV_TypeProp_HasUniqueName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ProfEnd();
|
||||
}
|
||||
|
||||
internal void
|
||||
lnk_replace_type_names_with_hashes(TP_Context *tp, TP_Arena *arena, CV_DebugT debug_t, LNK_TypeNameHashMode mode, U64 hash_length, String8 map_name)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
Temp scratch = scratch_begin(arena->v, arena->count);
|
||||
|
||||
// init task context
|
||||
LNK_TypeNameReplacer task = {0};
|
||||
task.debug_t = debug_t;
|
||||
task.ranges = tp_divide_work(scratch.arena, debug_t.count, tp->worker_count);
|
||||
task.hash_length = Clamp(1, hash_length, 16);
|
||||
|
||||
if (map_name.size > 0) {
|
||||
task.make_map = 1;
|
||||
task.map_arena = tp_arena_alloc(tp);
|
||||
task.maps = push_array(scratch.arena, String8List, tp->worker_count);
|
||||
}
|
||||
|
||||
// pick task function
|
||||
TP_TaskFunc *func = 0;
|
||||
switch (mode) {
|
||||
case LNK_TypeNameHashMode_Null:
|
||||
case LNK_TypeNameHashMode_None:
|
||||
break;
|
||||
|
||||
case LNK_TypeNameHashMode_Lenient: func = lnk_replace_type_names_with_hashes_lenient_task; break;
|
||||
case LNK_TypeNameHashMode_Full: func = lnk_replace_type_names_with_hashes_full_task; break;
|
||||
}
|
||||
|
||||
// run task
|
||||
tp_for_parallel(tp, arena, tp->worker_count, func, &task);
|
||||
|
||||
// optionally write out map file
|
||||
if (task.make_map) {
|
||||
String8List map = {0};
|
||||
str8_list_concat_in_place_array(&map, task.maps, tp->worker_count);
|
||||
lnk_write_data_list_to_file_path(map_name, map);
|
||||
tp_arena_release(&task.map_arena);
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
ProfEnd();
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
// PDB Builder
|
||||
|
||||
@@ -2769,6 +2969,7 @@ THREAD_POOL_TASK_FUNC(lnk_push_dbi_sec_contrib_task)
|
||||
PDB_DbiModule *mod = task->mod_arr[obj_idx];
|
||||
LNK_Obj *obj = &task->obj_arr[obj_idx];
|
||||
PDB_DbiSectionContribList *dst_list = &task->sc_list[obj_idx];
|
||||
String8 image_data = task->image_data;
|
||||
|
||||
// TODO: use chunked lists for SC
|
||||
|
||||
@@ -2790,7 +2991,7 @@ THREAD_POOL_TASK_FUNC(lnk_push_dbi_sec_contrib_task)
|
||||
|
||||
// query chunk info
|
||||
ISectOff chunk_sc = lnk_sc_from_chunk_ref (sect_id_map, chunk->ref);
|
||||
String8 chunk_data = lnk_data_from_chunk_ref (sect_id_map, chunk->ref);
|
||||
String8 chunk_data = lnk_data_from_chunk_ref (sect_id_map, image_data, chunk->ref);
|
||||
LNK_Section *chunk_sect = lnk_sect_from_chunk_ref (sect_id_map, chunk->ref);
|
||||
U64 chunk_size = lnk_file_size_from_chunk_ref(sect_id_map, chunk->ref);
|
||||
|
||||
@@ -2827,20 +3028,23 @@ THREAD_POOL_TASK_FUNC(lnk_push_dbi_sec_contrib_task)
|
||||
////////////////////////////////
|
||||
|
||||
internal
|
||||
THREAD_POOL_TASK_FUNC(lnk_build_pdb_public_symbols_task)
|
||||
THREAD_POOL_TASK_FUNC(lnk_build_pdb_public_symbols_defined_task)
|
||||
{
|
||||
U64 bucket_idx = task_id;
|
||||
LNK_BuildPublicSymbolsTaskData *task = raw_task;
|
||||
ProfBeginFunction();
|
||||
|
||||
LNK_Section **sect_id_map = task->sect_id_map;
|
||||
LNK_SymbolScopeIndex scope_idx = task->scope_idx;
|
||||
LNK_SymbolList bucket = task->bucket_arr[scope_idx][bucket_idx];
|
||||
CV_SymbolList *pub_list = &task->pub_list_arr[bucket_idx];
|
||||
LNK_BuildPublicSymbolsTask *task = raw_task;
|
||||
LNK_Section **sect_id_map = task->sect_id_map;
|
||||
CV_SymbolList *pub_list = &task->pub_list_arr[task_id];
|
||||
LNK_SymbolHashTrieChunkList chunk_list = task->chunk_lists[task_id];
|
||||
|
||||
for (LNK_SymbolNode *symbol_node = bucket.first; symbol_node != 0; symbol_node = symbol_node->next) {
|
||||
LNK_Symbol *symbol = symbol_node->data;
|
||||
for (LNK_SymbolHashTrieChunk *chunk = chunk_list.first; chunk != 0; chunk = chunk->next) {
|
||||
CV_SymbolNode *nodes = push_array_no_zero(arena, CV_SymbolNode, chunk->count);
|
||||
|
||||
for (U64 i = 0, node_idx = 0; i < chunk->count; ++i) {
|
||||
LNK_Symbol *symbol = chunk->v[i].symbol;
|
||||
|
||||
Assert(LNK_Symbol_IsDefined(symbol->type));
|
||||
|
||||
if (LNK_Symbol_IsDefined(symbol->type)) {
|
||||
LNK_DefinedSymbol *defined_symbol = &symbol->u.defined;
|
||||
if (defined_symbol->value_type == LNK_DefinedSymbolValue_Chunk) {
|
||||
CV_Pub32Flags flags = 0;
|
||||
@@ -2854,11 +3058,15 @@ THREAD_POOL_TASK_FUNC(lnk_build_pdb_public_symbols_task)
|
||||
U32 symbol_off32 = safe_cast_u32(symbol_off);
|
||||
U16 symbol_isect16 = safe_cast_u16(symbol_isect);
|
||||
|
||||
CV_SymbolNode *pub_node = cv_symbol_list_push(arena, pub_list);
|
||||
pub_node->data = cv_make_pub32(arena, flags, symbol_off32, symbol_isect16, symbol->name);
|
||||
nodes[node_idx].data = cv_make_pub32(arena, flags, symbol_off32, symbol_isect16, symbol->name);
|
||||
cv_symbol_list_push_node(pub_list, &nodes[node_idx]);
|
||||
|
||||
++node_idx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ProfEnd();
|
||||
}
|
||||
|
||||
internal
|
||||
@@ -2866,8 +3074,8 @@ THREAD_POOL_TASK_FUNC(lnk_gsi_hash_cv_list_task)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
|
||||
LNK_BuildPublicSymbolsTaskData *task = raw_task;
|
||||
Rng1U64 range = task->symbol_ranges[task_id];
|
||||
LNK_BuildPublicSymbolsTask *task = raw_task;
|
||||
Rng1U64 range = task->symbol_ranges[task_id];
|
||||
|
||||
for (U64 symbol_idx = range.min; symbol_idx < range.max; ++symbol_idx) {
|
||||
CV_Symbol *symbol = &task->symbols.v[symbol_idx]->data;
|
||||
@@ -2883,22 +3091,20 @@ lnk_build_pdb_public_symbols(TP_Context *tp,
|
||||
TP_Arena *arena,
|
||||
LNK_SymbolTable *symtab,
|
||||
LNK_Section **sect_id_map,
|
||||
PDB_PsiContext *psi,
|
||||
LNK_SymbolScopeIndex scope_idx)
|
||||
PDB_PsiContext *psi)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
Temp scratch = scratch_begin(arena->v, arena->count);
|
||||
|
||||
ProfBegin("Make Public Symbols");
|
||||
LNK_BuildPublicSymbolsTaskData task = {0};
|
||||
task.sect_id_map = sect_id_map;
|
||||
task.scope_idx = scope_idx;
|
||||
task.bucket_arr = symtab->buckets;
|
||||
task.pub_list_arr = push_array(scratch.arena, CV_SymbolList, symtab->bucket_count[scope_idx]);
|
||||
tp_for_parallel(tp, arena, symtab->bucket_count[scope_idx], lnk_build_pdb_public_symbols_task, &task);
|
||||
ProfBegin("Defined");
|
||||
LNK_BuildPublicSymbolsTask task = {0};
|
||||
task.sect_id_map = sect_id_map;
|
||||
task.pub_list_arr = push_array(scratch.arena, CV_SymbolList, tp->worker_count);
|
||||
task.chunk_lists = symtab->chunk_lists[LNK_SymbolScopeIndex_Defined];
|
||||
tp_for_parallel(tp, arena, tp->worker_count, lnk_build_pdb_public_symbols_defined_task, &task);
|
||||
ProfEnd();
|
||||
|
||||
CV_SymbolPtrArray symbols = cv_symbol_ptr_array_from_list(scratch.arena, tp, symtab->bucket_count[scope_idx], task.pub_list_arr);
|
||||
CV_SymbolPtrArray symbols = cv_symbol_ptr_array_from_list(scratch.arena, tp, tp->worker_count, task.pub_list_arr);
|
||||
|
||||
ProfBegin("GSI Push");
|
||||
gsi_push_many_arr(tp, psi->gsi, symbols.count, symbols.v);
|
||||
@@ -2911,7 +3117,8 @@ lnk_build_pdb_public_symbols(TP_Context *tp,
|
||||
internal String8List
|
||||
lnk_build_pdb(TP_Context *tp,
|
||||
TP_Arena *tp_arena,
|
||||
OS_Guid guid,
|
||||
String8 image_data,
|
||||
Guid guid,
|
||||
COFF_MachineType machine,
|
||||
COFF_TimeStamp time_stamp,
|
||||
U32 age,
|
||||
@@ -3070,8 +3277,8 @@ lnk_build_pdb(TP_Context *tp,
|
||||
ProfBegin("Build DBI Section Headers");
|
||||
{
|
||||
LNK_Symbol *coff_sect_array_symbol = lnk_symbol_table_searchf(symtab, LNK_SymbolScopeFlag_Internal, LNK_COFF_SECT_HEADER_ARRAY_SYMBOL_NAME);
|
||||
LNK_Chunk *coff_sect_chunk = lnk_defined_symbol_get_chunk(&coff_sect_array_symbol->u.defined);
|
||||
String8 coff_sect_chunk_data = lnk_data_from_chunk_ref(sect_id_map, coff_sect_chunk->ref);
|
||||
LNK_Chunk *coff_sect_chunk = lnk_chunk_from_symbol(coff_sect_array_symbol);
|
||||
String8 coff_sect_chunk_data = lnk_data_from_chunk_ref(sect_id_map, image_data, coff_sect_chunk->ref);
|
||||
U64 coff_sect_count = coff_sect_chunk_data.size / sizeof(COFF_SectionHeader);
|
||||
COFF_SectionHeader *coff_sect_ptr = (COFF_SectionHeader*)coff_sect_chunk_data.str;
|
||||
for (COFF_SectionHeader *hdr_ptr = &coff_sect_ptr[0], *opl = hdr_ptr + coff_sect_count;
|
||||
@@ -3089,6 +3296,7 @@ lnk_build_pdb(TP_Context *tp,
|
||||
task.sect_id_map = sect_id_map;
|
||||
task.mod_arr = mod_arr;
|
||||
task.sc_list = push_array(scratch.arena, PDB_DbiSectionContribList, obj_count);
|
||||
task.image_data = image_data;
|
||||
tp_for_parallel(tp, tp_arena, obj_count, lnk_push_dbi_sec_contrib_task, &task);
|
||||
|
||||
dbi_sec_list_concat_arr(&pdb->dbi->sec_contrib_list, obj_count, task.sc_list);
|
||||
@@ -3098,7 +3306,7 @@ lnk_build_pdb(TP_Context *tp,
|
||||
ProfBegin("Build NatVis");
|
||||
{
|
||||
String8Array natvis_file_path_arr = str8_array_from_list(scratch.arena, &natvis_list);
|
||||
String8Array natvis_file_data_arr = os_data_from_file_path_parallel(tp, scratch.arena, natvis_file_path_arr);
|
||||
String8Array natvis_file_data_arr = lnk_read_data_from_file_path_parallel(tp, scratch.arena, natvis_file_path_arr);
|
||||
|
||||
for (U64 i = 0; i < natvis_file_data_arr.count; ++i) {
|
||||
String8 natvis_file_path = natvis_file_path_arr.v[i];
|
||||
@@ -3125,7 +3333,7 @@ lnk_build_pdb(TP_Context *tp,
|
||||
}
|
||||
ProfEnd();
|
||||
|
||||
lnk_build_pdb_public_symbols(tp, tp_arena, symtab, sect_id_map, pdb->psi, LNK_SymbolScopeIndex_Defined);
|
||||
lnk_build_pdb_public_symbols(tp, tp_arena, symtab, sect_id_map, pdb->psi);
|
||||
|
||||
pdb_build(tp, tp_arena, pdb, string_ht);
|
||||
|
||||
|
||||
@@ -316,6 +316,7 @@ typedef struct
|
||||
LNK_Section **sect_id_map;
|
||||
PDB_DbiModule **mod_arr;
|
||||
PDB_DbiSectionContribList *sc_list;
|
||||
String8 image_data;
|
||||
} LNK_PushDbiSecContribTaskData;
|
||||
|
||||
typedef struct
|
||||
@@ -333,16 +334,15 @@ typedef struct
|
||||
|
||||
typedef struct
|
||||
{
|
||||
LNK_Section **sect_id_map;
|
||||
LNK_SymbolScopeIndex scope_idx;
|
||||
LNK_SymbolList **bucket_arr;
|
||||
CV_SymbolList *pub_list_arr;
|
||||
LNK_Section **sect_id_map;
|
||||
LNK_SymbolHashTrieChunkList *chunk_lists;
|
||||
CV_SymbolList *pub_list_arr;
|
||||
|
||||
Rng1U64 *symbol_ranges;
|
||||
PDB_GsiContext *gsi;
|
||||
CV_SymbolPtrArray symbols;
|
||||
U32 *hashes;
|
||||
} LNK_BuildPublicSymbolsTaskData;
|
||||
} LNK_BuildPublicSymbolsTask;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@@ -368,6 +368,16 @@ typedef struct
|
||||
CV_SymbolNode **symbol_arr;
|
||||
} LNK_GsiUnbucket;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
CV_DebugT debug_t;
|
||||
Rng1U64 *ranges;
|
||||
U64 hash_length;
|
||||
B32 make_map;
|
||||
TP_Arena *map_arena;
|
||||
String8List *maps;
|
||||
} LNK_TypeNameReplacer;
|
||||
|
||||
////////////////////////////////
|
||||
// RAD Debug Info
|
||||
|
||||
@@ -525,6 +535,8 @@ internal void lnk_patch_leaves(TP_Context *tp, LNK_CodeViewInput
|
||||
internal String8Node * lnk_copy_raw_leaf_arr_to_type_server(TP_Context *tp, CV_DebugT types, PDB_TypeServer *type_server);
|
||||
internal CV_DebugT * lnk_import_types(TP_Context *tp, TP_Arena *tp_temp, LNK_CodeViewInput *input);
|
||||
|
||||
internal void lnk_replace_type_names_with_hashes(TP_Context *tp, TP_Arena *arena, CV_DebugT debug_t, LNK_TypeNameHashMode mode, U64 hash_length, String8 map_name);
|
||||
|
||||
////////////////////////////////
|
||||
// RAD Debug info
|
||||
|
||||
@@ -566,12 +578,12 @@ internal void lnk_build_pdb_public_symbols(TP_Context *tp,
|
||||
TP_Arena *arena,
|
||||
LNK_SymbolTable *symtab,
|
||||
LNK_Section **sect_id_map,
|
||||
PDB_PsiContext *psi,
|
||||
LNK_SymbolScopeIndex scope_idx);
|
||||
PDB_PsiContext *psi);
|
||||
|
||||
internal String8List lnk_build_pdb(TP_Context *tp,
|
||||
TP_Arena *tp_arena,
|
||||
OS_Guid guid,
|
||||
String8 image_data,
|
||||
Guid guid,
|
||||
COFF_MachineType machine,
|
||||
COFF_TimeStamp time_stamp,
|
||||
U32 age,
|
||||
|
||||
@@ -70,6 +70,9 @@ lnk_parse_directives(Arena *arena, LNK_DirectiveInfo *directive_info, String8 bu
|
||||
for (U64 i = 0; i < ArrayCount(directive_table); ++i) {
|
||||
if (str8_match(directive_table[i].name, opt->string, StringMatchFlag_CaseInsensitive)) {
|
||||
kind = directive_table[i].kind;
|
||||
if (kind == LNK_Directive_Merge) {
|
||||
String8 v = str8_list_join(scratch.arena, &opt->value_strings, &(StringJoin){ .sep = str8_lit_comp(" ")});
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,8 @@ typedef enum
|
||||
LNK_Error_UnsupportedMachine,
|
||||
LNK_Error_Mt,
|
||||
LNK_Error_UnableToSerializeMsf,
|
||||
LNK_Error_LoadRes,
|
||||
LNK_Error_IO,
|
||||
LNK_Error_StopLast,
|
||||
|
||||
LNK_Error_First,
|
||||
@@ -75,6 +77,7 @@ typedef enum
|
||||
LNK_Warning_UnusedDelayLoadDll,
|
||||
LNK_Warning_LongSectionName,
|
||||
LNK_Warning_UnknownSwitch,
|
||||
LNK_Warning_TLSAlign,
|
||||
LNK_Warning_Last,
|
||||
|
||||
LNK_Error_Count
|
||||
@@ -115,7 +118,7 @@ internal void lnk_suppress_error(LNK_ErrorCode code);
|
||||
internal LNK_ErrorCodeStatus lnk_get_error_code_status(LNK_ErrorCode code);
|
||||
|
||||
internal void lnk_internal_error(LNK_InternalError code, char *file, int line, char *fmt, ...);
|
||||
#define lnk_invalid_path(fmt, ...) lnk_internal_error(LNK_InternalError_InvalidPath, __FILE__, __LINE__, fmt, __VA_ARGS__)
|
||||
#define lnk_not_implemented(fmt, ...) lnk_internal_error(LNK_InternalError_NotImplemented, __FILE__, __LINE__, fmt, __VA_ARGS__)
|
||||
#define lnk_incomplete_switch(fmt, ...) lnk_internal_error(LNK_InternalError_IncompleteSwitch, __FILE__, __LINE__, fmt, __VA_ARGS__)
|
||||
#define lnk_invalid_path(...) lnk_internal_error(LNK_InternalError_InvalidPath, __FILE__, __LINE__, __VA_ARGS__)
|
||||
#define lnk_not_implemented(...) lnk_internal_error(LNK_InternalError_NotImplemented, __FILE__, __LINE__, __VA_ARGS__)
|
||||
#define lnk_incomplete_switch(...) lnk_internal_error(LNK_InternalError_IncompleteSwitch, __FILE__, __LINE__, __VA_ARGS__)
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ lnk_export_name_compar(const void *a_, const void *b_)
|
||||
{
|
||||
const LNK_Export *a = (const LNK_Export *)a_;
|
||||
const LNK_Export *b = (const LNK_Export *)b_;
|
||||
return str8_compar_case_sensetive(&a->name, &b->name);
|
||||
return str8_compar_case_sensitive(&a->name, &b->name);
|
||||
}
|
||||
|
||||
int
|
||||
@@ -23,11 +23,15 @@ lnk_export_table_alloc(void)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
Arena *arena = arena_alloc();
|
||||
LNK_ExportTable *exptab = push_array(arena, LNK_ExportTable, 1);
|
||||
exptab->arena = arena;
|
||||
exptab->voff_size = sizeof(U32);
|
||||
exptab->max_ordinal = max_U16;
|
||||
exptab->is_ordinal_used = push_array(arena, B8, exptab->max_ordinal);
|
||||
|
||||
LNK_ExportTable *exptab = push_array(arena, LNK_ExportTable, 1);
|
||||
exptab->arena = arena;
|
||||
exptab->voff_size = sizeof(U32);
|
||||
exptab->max_ordinal = max_U16;
|
||||
exptab->is_ordinal_used = push_array(arena, B8, exptab->max_ordinal);
|
||||
exptab->name_export_ht = hash_table_init(arena, 0x10000);
|
||||
exptab->noname_export_ht = hash_table_init(arena, 0x100);
|
||||
|
||||
ProfEnd();
|
||||
return exptab;
|
||||
}
|
||||
@@ -44,12 +48,11 @@ lnk_export_table_release(LNK_ExportTable **exptab_ptr)
|
||||
internal LNK_Export *
|
||||
lnk_export_table_search(LNK_ExportTable *exptab, String8 name)
|
||||
{
|
||||
for (LNK_Export *exp = exptab->name_export_list.first; exp != NULL; exp = exp->next) {
|
||||
if (str8_match(exp->name, name, 0)) {
|
||||
return exp;
|
||||
}
|
||||
KeyValuePair *kv = hash_table_search_string(exptab->name_export_ht, name);
|
||||
if (kv) {
|
||||
return kv->value_raw;
|
||||
}
|
||||
return NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
internal LNK_Export *
|
||||
@@ -69,6 +72,7 @@ lnk_export_table_push_export(LNK_ExportTable *exptab, LNK_SymbolTable *symtab, L
|
||||
goto exit;
|
||||
}
|
||||
LNK_DefinedSymbol *def = &symbol->u.defined;
|
||||
|
||||
|
||||
// NOTE: It is possible to export a global variable as CODE
|
||||
// with following snippet:
|
||||
@@ -141,14 +145,12 @@ lnk_export_table_push_export(LNK_ExportTable *exptab, LNK_SymbolTable *symtab, L
|
||||
exp->next = 0;
|
||||
exp->name = push_str8_copy(exptab->arena, exp_parse->alias.size > 0 ? exp_parse->alias : exp_parse->name);
|
||||
exp->symbol = symbol;
|
||||
exp->id = exptab->name_export_list.count;
|
||||
exp->id = exptab->name_export_ht->count;
|
||||
exp->ordinal = ordinal;
|
||||
exp->type = type;
|
||||
exp->is_private = 0; // exports through directives are public
|
||||
|
||||
// push node
|
||||
SLLQueuePush(exptab->name_export_list.first, exptab->name_export_list.last, exp);
|
||||
exptab->name_export_list.count += 1;
|
||||
|
||||
hash_table_push_string_raw(exptab->arena, exptab->name_export_ht, exp->name, exp);
|
||||
|
||||
exit:;
|
||||
return exp;
|
||||
@@ -175,7 +177,7 @@ lnk_build_edata(LNK_ExportTable *exptab, LNK_SectionTable *st, LNK_SymbolTable *
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
|
||||
// is export table empty?
|
||||
if (exptab->name_export_list.count == 0 && exptab->noname_export_list.count == 0) {
|
||||
if (exptab->name_export_ht->count == 0 && exptab->noname_export_ht->count == 0) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
@@ -198,8 +200,8 @@ lnk_build_edata(LNK_ExportTable *exptab, LNK_SectionTable *st, LNK_SymbolTable *
|
||||
// push header
|
||||
PE_ExportTable *header = push_array(edata->arena, PE_ExportTable, 1);
|
||||
header->ordinal_base = safe_cast_u16(ordinal_low + 1);
|
||||
header->export_address_table_count = safe_cast_u32(exptab->name_export_list.count + exptab->noname_export_list.count);
|
||||
header->name_pointer_table_count = safe_cast_u32(exptab->name_export_list.count);
|
||||
header->export_address_table_count = safe_cast_u32(exptab->name_export_ht->count + exptab->noname_export_ht->count);
|
||||
header->name_pointer_table_count = safe_cast_u32(exptab->name_export_ht->count);
|
||||
|
||||
String8 header_data = str8((U8*)header, sizeof(*header));
|
||||
String8 image_name_cstr = push_cstr(edata->arena, str8_skip_last_slash(image_name));
|
||||
@@ -218,20 +220,16 @@ lnk_build_edata(LNK_ExportTable *exptab, LNK_SectionTable *st, LNK_SymbolTable *
|
||||
lnk_chunk_set_debugf(edata->arena, string_buffer_chunk, "EXPORT_STRING_BUFFER");
|
||||
lnk_chunk_set_debugf(edata->arena, image_name_chunk, "EXPORT_IMAGE_NAME");
|
||||
|
||||
LNK_Symbol *image_name_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_lit("export_table.name_voff"), LNK_DefinedSymbolVisibility_Internal, 0, image_name_chunk, 0, 0, 0);
|
||||
LNK_Symbol *address_table_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_lit("export_table.export_address_table_voff"), LNK_DefinedSymbolVisibility_Internal, 0, voff_table_chunk, 0, 0, 0);
|
||||
LNK_Symbol *name_table_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_lit("export_table.name_pointer_table_voff"), LNK_DefinedSymbolVisibility_Internal, 0, name_voff_table_chunk, 0, 0, 0);
|
||||
LNK_Symbol *ordinal_table_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_lit("export_table.ordinal_table_voff"), LNK_DefinedSymbolVisibility_Internal, 0, ordinal_table_chunk, 0, 0, 0);
|
||||
lnk_symbol_table_push(symtab, image_name_symbol);
|
||||
lnk_symbol_table_push(symtab, address_table_symbol);
|
||||
lnk_symbol_table_push(symtab, name_table_symbol);
|
||||
lnk_symbol_table_push(symtab, ordinal_table_symbol);
|
||||
LNK_Symbol *image_name_symbol = lnk_symbol_table_push_defined_chunk(symtab, str8_lit("export_table.name_voff"), LNK_DefinedSymbolVisibility_Internal, 0, image_name_chunk, 0, 0, 0);
|
||||
LNK_Symbol *address_table_symbol = lnk_symbol_table_push_defined_chunk(symtab, str8_lit("export_table.export_address_table_voff"), LNK_DefinedSymbolVisibility_Internal, 0, voff_table_chunk, 0, 0, 0);
|
||||
LNK_Symbol *name_table_symbol = lnk_symbol_table_push_defined_chunk(symtab, str8_lit("export_table.name_pointer_table_voff"), LNK_DefinedSymbolVisibility_Internal, 0, name_voff_table_chunk, 0, 0, 0);
|
||||
LNK_Symbol *ordinal_table_symbol = lnk_symbol_table_push_defined_chunk(symtab, str8_lit("export_table.ordinal_table_voff"), LNK_DefinedSymbolVisibility_Internal, 0, ordinal_table_chunk, 0, 0, 0);
|
||||
|
||||
// patch header fields
|
||||
lnk_section_push_reloc(edata, header_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_ExportTable, name_voff), image_name_symbol);
|
||||
lnk_section_push_reloc(edata, header_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_ExportTable, name_voff), image_name_symbol);
|
||||
lnk_section_push_reloc(edata, header_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_ExportTable, export_address_table_voff), address_table_symbol);
|
||||
lnk_section_push_reloc(edata, header_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_ExportTable, name_pointer_table_voff), name_table_symbol);
|
||||
lnk_section_push_reloc(edata, header_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_ExportTable, ordinal_table_voff), ordinal_table_symbol);
|
||||
lnk_section_push_reloc(edata, header_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_ExportTable, name_pointer_table_voff), name_table_symbol);
|
||||
lnk_section_push_reloc(edata, header_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_ExportTable, ordinal_table_voff), ordinal_table_symbol);
|
||||
|
||||
// reserve virtual offset chunks
|
||||
LNK_Chunk **ordinal_voff_map = push_array(scratch.arena, LNK_Chunk *, exptab->max_ordinal);
|
||||
@@ -242,21 +240,23 @@ lnk_build_edata(LNK_ExportTable *exptab, LNK_SectionTable *st, LNK_SymbolTable *
|
||||
}
|
||||
|
||||
B8 *is_ordinal_bound = push_array(scratch.arena, B8, exptab->max_ordinal);
|
||||
LNK_ExportList *exp_list_arr[] = { &exptab->name_export_list, &exptab->noname_export_list };
|
||||
for (LNK_ExportList *list_ptr = exp_list_arr[0], *list_opl = list_ptr + ArrayCount(exp_list_arr);
|
||||
list_ptr < list_opl;
|
||||
list_ptr += 1) {
|
||||
for (LNK_Export *exp = list_ptr->first; exp != 0; exp = exp->next) {
|
||||
String8 name_cstr = push_cstr(edata->arena, exp->name);
|
||||
HashTable *exp_ht_arr[] = { exptab->name_export_ht, exptab->noname_export_ht };
|
||||
for (HashTable **ht_ptr = &exp_ht_arr[0], **ht_opl = ht_ptr + ArrayCount(exp_ht_arr);
|
||||
ht_ptr < ht_opl;
|
||||
ht_ptr += 1) {
|
||||
KeyValuePair *kv_arr = key_value_pairs_from_hash_table(scratch.arena, *ht_ptr);
|
||||
|
||||
for (U64 i = 0; i < (*ht_ptr)->count; ++i) {
|
||||
LNK_Export *exp = kv_arr[i].value_raw;
|
||||
String8 name_cstr = push_cstr(edata->arena, exp->name);
|
||||
|
||||
// push name string
|
||||
LNK_Chunk *name_chunk = lnk_section_push_chunk_data(edata, string_buffer_chunk, name_cstr, str8(0,0));
|
||||
lnk_chunk_set_debugf(edata->arena, name_chunk, "export: %S", name_cstr);
|
||||
|
||||
// push name symbol
|
||||
String8 name_export_name = push_str8f(symtab->arena, "export.%S", name_cstr);
|
||||
LNK_Symbol *name_symbol = lnk_make_defined_symbol_chunk(symtab->arena, name_export_name, LNK_DefinedSymbolVisibility_Internal, 0, name_chunk, 0, 0, 0);
|
||||
lnk_symbol_table_push(symtab, name_symbol);
|
||||
String8 name_export_name = push_str8f(symtab->arena->v[0], "export.%S", name_cstr);
|
||||
LNK_Symbol *name_symbol = lnk_symbol_table_push_defined_chunk(symtab, name_export_name, LNK_DefinedSymbolVisibility_Internal, 0, name_chunk, 0, 0, 0);
|
||||
|
||||
// name voff
|
||||
LNK_Chunk *voff_chunk = lnk_section_push_chunk_bss(edata, name_voff_table_chunk, exptab->voff_size, /* export table must be sorted lexically: */ name_cstr);
|
||||
|
||||
@@ -30,8 +30,8 @@ typedef struct LNK_ExportArray
|
||||
typedef struct LNK_ExportTable
|
||||
{
|
||||
Arena *arena;
|
||||
LNK_ExportList name_export_list;
|
||||
LNK_ExportList noname_export_list;
|
||||
HashTable *name_export_ht;
|
||||
HashTable *noname_export_ht;
|
||||
U64 voff_size;
|
||||
U64 max_ordinal;
|
||||
B8 *is_ordinal_used;
|
||||
|
||||
+66
-105
@@ -2,7 +2,7 @@
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal LNK_ImportTable *
|
||||
lnk_import_table_alloc_regular(LNK_SectionTable *st, LNK_SymbolTable *symtab, COFF_MachineType machine)
|
||||
lnk_import_table_alloc_static(LNK_SectionTable *st, LNK_SymbolTable *symtab, COFF_MachineType machine)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
|
||||
@@ -18,17 +18,11 @@ lnk_import_table_alloc_regular(LNK_SectionTable *st, LNK_SymbolTable *symtab, CO
|
||||
LNK_Chunk *null_dll_import = lnk_section_push_chunk_data(data_sect, dll_table_chunk, str8(0, sizeof(PE_ImportEntry)), str8_lit("zzzzz"));
|
||||
lnk_chunk_set_debugf(data_sect->arena, null_dll_import, "DLL_DIRECTORY_TERMINATOR");
|
||||
|
||||
LNK_Symbol *dll_table_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_cstring(LNK_IMPORT_DLL_TABLE_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, dll_table_chunk, 0, 0, 0);
|
||||
LNK_Symbol *int_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_cstring(LNK_IMPORT_NAME_TABLE_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, int_chunk , 0, 0, 0);
|
||||
LNK_Symbol *iat_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_cstring(LNK_IMPORT_IAT_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, iat_chunk , 0, 0, 0);
|
||||
LNK_Symbol *ilt_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_cstring(LNK_IMPORT_ILT_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, ilt_chunk , 0, 0, 0);
|
||||
LNK_Symbol *code_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_cstring(LNK_IMPORT_JMP_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, code_chunk , 0, 0, 0);
|
||||
|
||||
lnk_symbol_table_push(symtab, dll_table_symbol);
|
||||
lnk_symbol_table_push(symtab, int_symbol);
|
||||
lnk_symbol_table_push(symtab, iat_symbol);
|
||||
lnk_symbol_table_push(symtab, ilt_symbol);
|
||||
lnk_symbol_table_push(symtab, code_symbol);
|
||||
lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_IMPORT_DLL_TABLE_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, dll_table_chunk, 0, 0, 0);
|
||||
lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_IMPORT_NAME_TABLE_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, int_chunk , 0, 0, 0);
|
||||
lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_IMPORT_IAT_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, iat_chunk , 0, 0, 0);
|
||||
lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_IMPORT_ILT_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, ilt_chunk , 0, 0, 0);
|
||||
lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_IMPORT_JMP_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, code_chunk , 0, 0, 0);
|
||||
|
||||
Arena *arena = arena_alloc();
|
||||
LNK_ImportTable *imptab = push_array(arena, LNK_ImportTable, 1);
|
||||
@@ -79,23 +73,14 @@ lnk_import_table_alloc_delayed(LNK_SectionTable *st, LNK_SymbolTable *symtab, CO
|
||||
lnk_chunk_set_debugf(data_sect->arena, null_biat_chunk, "BIAT_TERMINATOR");
|
||||
}
|
||||
|
||||
LNK_Symbol *dll_table_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_cstring(LNK_DELAYED_IMPORT_DLL_TABLE_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, dll_table_chunk , 0, 0, 0);
|
||||
LNK_Symbol *int_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_cstring(LNK_DELAYED_IMPORT_INT_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, int_chunk , 0, 0, 0);
|
||||
LNK_Symbol *handle_table_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_cstring(LNK_DELAYED_IMPORT_HANDLE_TABLE_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, handle_table_chunk, 0, 0, 0);
|
||||
LNK_Symbol *iat_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_cstring(LNK_DELAYED_IMPORT_IAT_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, iat_chunk , 0, 0, 0);
|
||||
LNK_Symbol *ilt_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_cstring(LNK_DELAYED_IMPORT_ILT_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, ilt_chunk , 0, 0, 0);
|
||||
LNK_Symbol *biat_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_cstring(LNK_DELAYED_IMPORT_BIAT_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, biat_chunk , 0, 0, 0);
|
||||
LNK_Symbol *uiat_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_cstring(LNK_DELAYED_IMPORT_UIAT_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, uiat_chunk , 0, 0, 0);
|
||||
LNK_Symbol *code_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_cstring(LNK_DELAYED_IMPORT_CODE_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, code_chunk , 0, 0, 0);
|
||||
|
||||
lnk_symbol_table_push(symtab, dll_table_symbol);
|
||||
lnk_symbol_table_push(symtab, int_symbol);
|
||||
lnk_symbol_table_push(symtab, handle_table_symbol);
|
||||
lnk_symbol_table_push(symtab, iat_symbol);
|
||||
lnk_symbol_table_push(symtab, ilt_symbol);
|
||||
lnk_symbol_table_push(symtab, biat_symbol);
|
||||
lnk_symbol_table_push(symtab, uiat_symbol);
|
||||
lnk_symbol_table_push(symtab, code_symbol);
|
||||
lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_DELAYED_IMPORT_DLL_TABLE_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, dll_table_chunk , 0, 0, 0);
|
||||
lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_DELAYED_IMPORT_INT_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, int_chunk , 0, 0, 0);
|
||||
lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_DELAYED_IMPORT_HANDLE_TABLE_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, handle_table_chunk, 0, 0, 0);
|
||||
lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_DELAYED_IMPORT_IAT_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, iat_chunk , 0, 0, 0);
|
||||
lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_DELAYED_IMPORT_ILT_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, ilt_chunk , 0, 0, 0);
|
||||
lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_DELAYED_IMPORT_BIAT_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, biat_chunk , 0, 0, 0);
|
||||
lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_DELAYED_IMPORT_UIAT_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, uiat_chunk , 0, 0, 0);
|
||||
lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_DELAYED_IMPORT_CODE_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, code_chunk , 0, 0, 0);
|
||||
|
||||
LNK_ImportTableFlags flags = 0;
|
||||
if (is_unloadable) {
|
||||
@@ -178,7 +163,7 @@ lnk_import_table_search_func(LNK_ImportDLL *dll, String8 name)
|
||||
}
|
||||
|
||||
internal LNK_ImportDLL *
|
||||
lnk_import_table_push_dll_regular(LNK_ImportTable *imptab, LNK_SymbolTable *symtab, String8 dll_name, COFF_MachineType machine)
|
||||
lnk_import_table_push_dll_static(LNK_ImportTable *imptab, LNK_SymbolTable *symtab, String8 dll_name, COFF_MachineType machine)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
|
||||
@@ -193,21 +178,18 @@ lnk_import_table_push_dll_regular(LNK_ImportTable *imptab, LNK_SymbolTable *symt
|
||||
LNK_Chunk *iat_table_chunk = lnk_section_push_chunk_list(data_sect, imptab->iat_chunk, str8_zero());
|
||||
LNK_Chunk *code_table_chunk = lnk_section_push_chunk_list(code_sect, imptab->code_chunk, str8_zero());
|
||||
|
||||
String8 ilt_symbol_name = push_str8f(symtab->arena, "%S.lookup_table_voff", dll_name);
|
||||
LNK_Symbol *ilt_symbol = lnk_make_defined_symbol_chunk(symtab->arena, ilt_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, ilt_table_chunk, 0, 0, 0);
|
||||
lnk_symbol_table_push(symtab, ilt_symbol);
|
||||
String8 ilt_symbol_name = push_str8f(symtab->arena->v[0], "%S.lookup_table_voff", dll_name);
|
||||
LNK_Symbol *ilt_symbol = lnk_symbol_table_push_defined_chunk(symtab, ilt_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, ilt_table_chunk, 0, 0, 0);
|
||||
|
||||
String8 iat_symbol_name = push_str8f(symtab->arena, "%S.import_addr_table_voff", dll_name);
|
||||
LNK_Symbol *iat_symbol = lnk_make_defined_symbol_chunk(symtab->arena, iat_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, iat_table_chunk, 0, 0, 0);
|
||||
lnk_symbol_table_push(symtab, iat_symbol);
|
||||
String8 iat_symbol_name = push_str8f(symtab->arena->v[0], "%S.import_addr_table_voff", dll_name);
|
||||
LNK_Symbol *iat_symbol = lnk_symbol_table_push_defined_chunk(symtab, iat_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, iat_table_chunk, 0, 0, 0);
|
||||
|
||||
String8 dll_name_cstr = push_cstr(data_sect->arena, dll_name);
|
||||
String8 dll_name_cstr = push_cstr(data_sect->arena, dll_name);
|
||||
LNK_Chunk *dll_name_chunk = lnk_section_push_chunk_data(data_sect, int_table_chunk, dll_name_cstr, str8_zero());
|
||||
lnk_chunk_set_debugf(data_sect->arena, dll_name_chunk, "DLL name chunk (%S)", dll_name);
|
||||
|
||||
String8 dll_name_voff_name = push_str8f(symtab->arena, "%S.name_voff", dll_name);
|
||||
LNK_Symbol *dll_name_voff_symbol = lnk_make_defined_symbol_chunk(symtab->arena, dll_name_voff_name, LNK_DefinedSymbolVisibility_Internal, 0, dll_name_chunk, 0, 0, 0);
|
||||
lnk_symbol_table_push(symtab, dll_name_voff_symbol);
|
||||
String8 dll_name_voff_name = push_str8f(symtab->arena->v[0], "%S.name_voff", dll_name);
|
||||
LNK_Symbol *dll_name_voff_symbol = lnk_symbol_table_push_defined_chunk(symtab, dll_name_voff_name, LNK_DefinedSymbolVisibility_Internal, 0, dll_name_chunk, 0, 0, 0);
|
||||
|
||||
// chunk for dll directory entry
|
||||
PE_ImportEntry *dir = push_array(imptab->arena, PE_ImportEntry, 1);
|
||||
@@ -272,32 +254,29 @@ lnk_import_table_push_dll_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *symt
|
||||
imp_desc->time_stamp = 0;
|
||||
|
||||
// emit entry chunk
|
||||
String8 imp_desc_data = str8_struct(imp_desc);
|
||||
String8 imp_desc_data = str8_struct(imp_desc);
|
||||
LNK_Chunk *imp_desc_chunk = lnk_section_push_chunk_data(data_sect, imptab->dll_table_chunk, imp_desc_data, str8_zero());
|
||||
|
||||
// emit entry symbol
|
||||
String8 imp_desc_name = push_str8f(symtab->arena, "__DELAY_IMPORT_DESCRIPTOR_%S", dll_name);
|
||||
LNK_Symbol *imp_desc_symbol = lnk_make_defined_symbol_chunk(symtab->arena, imp_desc_name, LNK_DefinedSymbolVisibility_Extern, 0, imp_desc_chunk, 0, 0, 0);
|
||||
lnk_symbol_table_push(symtab, imp_desc_symbol);
|
||||
String8 imp_desc_name = push_str8f(symtab->arena->v[0], "__DELAY_IMPORT_DESCRIPTOR_%S", dll_name);
|
||||
LNK_Symbol *imp_desc_symbol = lnk_symbol_table_push_defined_chunk(symtab, imp_desc_name, LNK_DefinedSymbolVisibility_Extern, 0, imp_desc_chunk, 0, 0, 0);
|
||||
|
||||
// emit string table chunk
|
||||
String8 int_table_chunk_debug = push_str8f(data_sect->arena, "delayed.%S.int", dll_name);
|
||||
LNK_Chunk *int_table_chunk = lnk_section_push_chunk_list(data_sect, imptab->int_chunk, int_table_chunk_debug);
|
||||
String8 int_table_chunk_debug = push_str8f(data_sect->arena, "delayed.%S.int", dll_name);
|
||||
LNK_Chunk *int_table_chunk = lnk_section_push_chunk_list(data_sect, imptab->int_chunk, int_table_chunk_debug);
|
||||
|
||||
String8 int_table_symbol_name = push_str8f(symtab->arena, "delayed.%S.int", dll_name);
|
||||
LNK_Symbol *int_table_symbol = lnk_make_defined_symbol_chunk(symtab->arena, int_table_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, int_table_chunk, 0, 0, 0);
|
||||
lnk_symbol_table_push(symtab, int_table_symbol);
|
||||
String8 int_table_symbol_name = push_str8f(symtab->arena->v[0], "delayed.%S.int", dll_name);
|
||||
LNK_Symbol *int_table_symbol = lnk_symbol_table_push_defined_chunk(symtab, int_table_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, int_table_chunk, 0, 0, 0);
|
||||
|
||||
LNK_Chunk *null_string_chunk = lnk_section_push_chunk_list(data_sect, int_table_chunk, str8_lit("zzzzz"));
|
||||
lnk_chunk_set_debugf(data_sect->arena, null_string_chunk, "string table null");
|
||||
|
||||
// emit DLL name chunk
|
||||
String8 name_chunk_data = push_cstr(data_sect->arena, dll_name);
|
||||
LNK_Chunk *name_chunk = lnk_section_push_chunk_data(data_sect, int_table_chunk, name_chunk_data, str8_zero());
|
||||
String8 name_chunk_data = push_cstr(data_sect->arena, dll_name);
|
||||
LNK_Chunk *name_chunk = lnk_section_push_chunk_data(data_sect, int_table_chunk, name_chunk_data, str8_zero());
|
||||
|
||||
String8 name_symbol_name = push_str8f(symtab->arena, "delayed.%S.name", dll_name);
|
||||
LNK_Symbol *name_symbol = lnk_make_defined_symbol_chunk(symtab->arena, name_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, name_chunk, 0, 0, 0);
|
||||
lnk_symbol_table_push(symtab, name_symbol);
|
||||
String8 name_symbol_name = push_str8f(symtab->arena->v[0], "delayed.%S.name", dll_name);
|
||||
LNK_Symbol *name_symbol = lnk_symbol_table_push_defined_chunk(symtab, name_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, name_chunk, 0, 0, 0);
|
||||
|
||||
// patch DLL name voff
|
||||
lnk_section_push_reloc(data_sect, imp_desc_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_DelayedImportEntry, name_voff), name_symbol);
|
||||
@@ -305,9 +284,8 @@ lnk_import_table_push_dll_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *symt
|
||||
// emit DLL handle chunk
|
||||
LNK_Chunk *handle_chunk = lnk_section_push_chunk_bss(data_sect, imptab->handle_table_chunk, handle_size, str8_zero());
|
||||
|
||||
String8 handle_name = push_str8f(symtab->arena, "delayed.%S.handle", dll_name);
|
||||
LNK_Symbol *handle_symbol = lnk_make_defined_symbol_chunk(symtab->arena, handle_name, LNK_DefinedSymbolVisibility_Internal, 0, handle_chunk, 0, 0, 0);
|
||||
lnk_symbol_table_push(symtab, handle_symbol);
|
||||
String8 handle_name = push_str8f(symtab->arena->v[0], "delayed.%S.handle", dll_name);
|
||||
LNK_Symbol *handle_symbol = lnk_symbol_table_push_defined_chunk(symtab, handle_name, LNK_DefinedSymbolVisibility_Internal, 0, handle_chunk, 0, 0, 0);
|
||||
|
||||
// patch DLL handle voff
|
||||
lnk_section_push_reloc(data_sect, imp_desc_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_DelayedImportEntry, module_handle_voff), handle_symbol);
|
||||
@@ -315,9 +293,8 @@ lnk_import_table_push_dll_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *symt
|
||||
// emit IAT chunk
|
||||
LNK_Chunk *iat_table_chunk = lnk_section_push_chunk_list(data_sect, imptab->iat_chunk, str8_zero());
|
||||
|
||||
String8 iat_table_name = push_str8f(symtab->arena, "delayed.%S.iat", dll_name);
|
||||
LNK_Symbol *iat_table_symbol = lnk_make_defined_symbol_chunk(symtab->arena, iat_table_name, LNK_DefinedSymbolVisibility_Internal, 0, iat_table_chunk, 0, 0, 0);
|
||||
lnk_symbol_table_push(symtab, iat_table_symbol);
|
||||
String8 iat_table_name = push_str8f(symtab->arena->v[0], "delayed.%S.iat", dll_name);
|
||||
LNK_Symbol *iat_table_symbol = lnk_symbol_table_push_defined_chunk(symtab, iat_table_name, LNK_DefinedSymbolVisibility_Internal, 0, iat_table_chunk, 0, 0, 0);
|
||||
|
||||
LNK_Chunk *null_iat_chunk = lnk_section_push_chunk_bss(data_sect, iat_table_chunk, import_size, str8_lit("zzzzzz"));
|
||||
lnk_chunk_set_debugf(data_sect->arena, null_iat_chunk, "%S: IAT terminator", dll_name);
|
||||
@@ -328,9 +305,8 @@ lnk_import_table_push_dll_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *symt
|
||||
LNK_Chunk *null_ilt_chunk = lnk_section_push_chunk_bss(data_sect, ilt_table_chunk, import_size, str8_lit("zzzzzz"));
|
||||
lnk_chunk_set_debugf(data_sect->arena, null_ilt_chunk, "%S: ILT terminator", dll_name);
|
||||
|
||||
String8 ilt_table_name = push_str8f(symtab->arena, "delayed.%S.ilt", dll_name);
|
||||
LNK_Symbol *ilt_table_symbol = lnk_make_defined_symbol_chunk(symtab->arena, ilt_table_name, LNK_DefinedSymbolVisibility_Extern, 0, ilt_table_chunk, 0, 0, 0);
|
||||
lnk_symbol_table_push(symtab, ilt_table_symbol);
|
||||
String8 ilt_table_name = push_str8f(symtab->arena->v[0], "delayed.%S.ilt", dll_name);
|
||||
LNK_Symbol *ilt_table_symbol = lnk_symbol_table_push_defined_chunk(symtab, ilt_table_name, LNK_DefinedSymbolVisibility_Extern, 0, ilt_table_chunk, 0, 0, 0);
|
||||
|
||||
// patch import address table voff
|
||||
lnk_section_push_reloc(data_sect, imp_desc_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_DelayedImportEntry, iat_voff), iat_table_symbol);
|
||||
@@ -343,9 +319,8 @@ lnk_import_table_push_dll_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *symt
|
||||
if (imptab->flags & LNK_ImportTableFlag_EmitBiat) {
|
||||
biat_chunk = lnk_section_push_chunk_list(data_sect, imptab->biat_chunk, str8_zero());
|
||||
|
||||
String8 biat_symbol_name = push_str8f(symtab->arena, "delayed.%S.BIAT", dll_name);
|
||||
LNK_Symbol *biat_symbol = lnk_make_defined_symbol_chunk(symtab->arena, biat_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, biat_chunk, 0, 0, 0);
|
||||
lnk_symbol_table_push(symtab, biat_symbol);
|
||||
String8 biat_symbol_name = push_str8f(symtab->arena->v[0], "delayed.%S.BIAT", dll_name);
|
||||
LNK_Symbol *biat_symbol = lnk_symbol_table_push_defined_chunk(symtab, biat_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, biat_chunk, 0, 0, 0);
|
||||
|
||||
// patch BIAT field off
|
||||
lnk_section_push_reloc(data_sect, imp_desc_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_DelayedImportEntry, bound_table_voff), biat_symbol);
|
||||
@@ -356,9 +331,8 @@ lnk_import_table_push_dll_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *symt
|
||||
if (imptab->flags & LNK_ImportTableFlag_EmitUiat) {
|
||||
uiat_chunk = lnk_section_push_chunk_list(data_sect, imptab->uiat_chunk, str8_zero());
|
||||
|
||||
String8 uiat_symbol_name = push_str8f(symtab->arena, "delayed.%S.UIAT", dll_name);
|
||||
LNK_Symbol *uiat_symbol = lnk_make_defined_symbol_chunk(symtab->arena, uiat_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, uiat_chunk, 0, 0, 0);
|
||||
lnk_symbol_table_push(symtab, uiat_symbol);
|
||||
String8 uiat_symbol_name = push_str8f(symtab->arena->v[0], "delayed.%S.UIAT", dll_name);
|
||||
LNK_Symbol *uiat_symbol = lnk_symbol_table_push_defined_chunk(symtab, uiat_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, uiat_chunk, 0, 0, 0);
|
||||
|
||||
// patch UIAT field voff
|
||||
lnk_section_push_reloc(data_sect, imp_desc_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_DelayedImportEntry, unload_table_voff), uiat_symbol);
|
||||
@@ -372,7 +346,7 @@ lnk_import_table_push_dll_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *symt
|
||||
LNK_Chunk *tail_merge_chunk = 0;
|
||||
switch (machine) {
|
||||
case COFF_MachineType_X64: {
|
||||
LNK_Symbol *delay_load_helper_symbol = lnk_make_undefined_symbol(symtab->arena, str8_lit(LNK_DELAY_LOAD_HELPER2_SYMBOL_NAME), LNK_SymbolScopeFlag_Main);
|
||||
LNK_Symbol *delay_load_helper_symbol = lnk_make_undefined_symbol(symtab->arena->v[0], str8_lit(LNK_DELAY_LOAD_HELPER2_SYMBOL_NAME), LNK_SymbolScopeFlag_Main);
|
||||
tail_merge_chunk = lnk_emit_tail_merge_thunk_x64(code_sect, code_chunk, imp_desc_symbol, delay_load_helper_symbol);
|
||||
} break;
|
||||
default: {
|
||||
@@ -401,7 +375,7 @@ lnk_import_table_push_dll_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *symt
|
||||
}
|
||||
|
||||
internal LNK_ImportFunc *
|
||||
lnk_import_table_push_func_regular(LNK_ImportTable *imptab, LNK_SymbolTable *symtab, LNK_ImportDLL *dll, COFF_ImportHeader *header)
|
||||
lnk_import_table_push_func_static(LNK_ImportTable *imptab, LNK_SymbolTable *symtab, LNK_ImportDLL *dll, COFF_ImportHeader *header)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
|
||||
@@ -438,9 +412,8 @@ lnk_import_table_push_func_regular(LNK_ImportTable *imptab, LNK_SymbolTable *sym
|
||||
LNK_Chunk *int_chunk = lnk_section_push_chunk_data(data_sect, int_table_chunk, int_data, str8_zero());
|
||||
|
||||
// create symbol for lookup chunk
|
||||
String8 int_symbol_name = push_str8f(symtab->arena, "regular.%S.%S.name", dll->name, header->func_name);
|
||||
LNK_Symbol *int_symbol = lnk_make_defined_symbol_chunk(symtab->arena, int_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, int_chunk, 0, 0, 0);
|
||||
lnk_symbol_table_push(symtab, int_symbol);
|
||||
String8 int_symbol_name = push_str8f(symtab->arena->v[0], "static.%S.%S.name", dll->name, header->func_name);
|
||||
LNK_Symbol *int_symbol = lnk_symbol_table_push_defined_chunk(symtab, int_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, int_chunk, 0, 0, 0);
|
||||
|
||||
// in the file IAT mirrors ILT, dynamic linker later overwrites it with imported function addresses.
|
||||
ilt_chunk = lnk_section_push_chunk_bss(data_sect, ilt_table_chunk, import_size, sort_index);
|
||||
@@ -464,12 +437,10 @@ lnk_import_table_push_func_regular(LNK_ImportTable *imptab, LNK_SymbolTable *sym
|
||||
} break;
|
||||
}
|
||||
|
||||
String8 ilt_symbol_name = push_str8f(symtab->arena, "regular.%S.%S.ilt", dll->name, header->func_name);
|
||||
String8 iat_symbol_name = push_str8f(symtab->arena, "__imp_%S", header->func_name);
|
||||
LNK_Symbol *ilt_symbol = lnk_make_defined_symbol_chunk(symtab->arena, ilt_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, ilt_chunk, 0, 0, 0);
|
||||
LNK_Symbol *iat_symbol = lnk_make_defined_symbol_chunk(symtab->arena, iat_symbol_name, LNK_DefinedSymbolVisibility_Extern, 0, iat_chunk, 0, 0, 0);
|
||||
lnk_symbol_table_push(symtab, ilt_symbol);
|
||||
lnk_symbol_table_push(symtab, iat_symbol);
|
||||
String8 ilt_symbol_name = push_str8f(symtab->arena->v[0], "static.%S.%S.ilt", dll->name, header->func_name);
|
||||
String8 iat_symbol_name = push_str8f(symtab->arena->v[0], "__imp_%S", header->func_name);
|
||||
LNK_Symbol *ilt_symbol = lnk_symbol_table_push_defined_chunk(symtab, ilt_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, ilt_chunk, 0, 0, 0);
|
||||
LNK_Symbol *iat_symbol = lnk_symbol_table_push_defined_chunk(symtab, iat_symbol_name, LNK_DefinedSymbolVisibility_Extern, 0, iat_chunk, 0, 0, 0);
|
||||
|
||||
// generate thunks
|
||||
LNK_Symbol *jmp_thunk_symbol = g_null_symbol_ptr;
|
||||
@@ -481,9 +452,8 @@ lnk_import_table_push_func_regular(LNK_ImportTable *imptab, LNK_SymbolTable *sym
|
||||
lnk_section_associate_chunks(data_sect, iat_chunk, jmp_thunk_chunk);
|
||||
|
||||
// push jump thunk symbol
|
||||
String8 jmp_thunk_symbol_name = push_str8_copy(symtab->arena, header->func_name);
|
||||
String8 jmp_thunk_symbol_name = push_str8_copy(symtab->arena->v[0], header->func_name);
|
||||
jmp_thunk_symbol = lnk_emit_jmp_thunk_symbol(symtab, jmp_thunk_chunk, jmp_thunk_symbol_name);
|
||||
lnk_symbol_set_debugf(symtab->arena, jmp_thunk_symbol, "x64 jmp thunk %S.%S", dll->name, header->func_name);
|
||||
} break;
|
||||
default: lnk_not_implemented("TODO: support for machine 0x%X", dll->machine); break;
|
||||
}
|
||||
@@ -538,19 +508,16 @@ lnk_import_table_push_func_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *sym
|
||||
if (header->type == COFF_ImportHeaderType_CODE) {
|
||||
switch (dll->machine) {
|
||||
case COFF_MachineType_X64: {
|
||||
String8 iat_symbol_name = push_str8f(symtab->arena, "__imp_%S", header->func_name);
|
||||
LNK_Symbol *iat_symbol = lnk_make_undefined_symbol(symtab->arena, iat_symbol_name, LNK_SymbolScopeFlag_Main);
|
||||
lnk_symbol_set_debugf(symtab->arena, iat_symbol, "x64 IAT (delayed) %S.%S", dll->name, header->func_name);
|
||||
String8 iat_symbol_name = push_str8f(symtab->arena->v[0], "__imp_%S", header->func_name);
|
||||
LNK_Symbol *iat_symbol = lnk_make_undefined_symbol(symtab->arena->v[0], iat_symbol_name, LNK_SymbolScopeFlag_Main);
|
||||
|
||||
// emit jmp thunk chunk
|
||||
jmp_thunk_chunk = lnk_emit_indirect_jump_thunk_x64(code_sect, code_table_chunk, iat_symbol);
|
||||
jmp_thunk_symbol = lnk_emit_jmp_thunk_symbol(symtab, jmp_thunk_chunk, header->func_name);
|
||||
lnk_symbol_set_debugf(symtab->arena, jmp_thunk_symbol, "x64 jmp thunk (delayed) %S.%S", dll->name, header->func_name);
|
||||
|
||||
// emit load thunk
|
||||
load_thunk_chunk = lnk_emit_load_thunk_x64(code_sect, code_table_chunk, iat_symbol, dll->tail_merge_symbol);
|
||||
load_thunk_symbol = lnk_emit_load_thunk_symbol(symtab, load_thunk_chunk, header->func_name);
|
||||
lnk_symbol_set_debugf(symtab->arena, load_thunk_symbol, "x64 load thunk (delayed) %S.%S", dll->name, header->func_name);
|
||||
} break;
|
||||
default: lnk_not_implemented("TODO: support for machine 0x%X", dll->machine); break;
|
||||
}
|
||||
@@ -582,9 +549,8 @@ lnk_import_table_push_func_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *sym
|
||||
LNK_Chunk *int_chunk = lnk_section_push_chunk_data(data_sect, int_table_chunk, int_data, str8_zero());
|
||||
|
||||
// create symbol for lookup chunk
|
||||
String8 int_symbol_name = push_str8f(symtab->arena, "%S.%S.name.delayed", dll->name, header->func_name);
|
||||
int_symbol = lnk_make_defined_symbol_chunk(symtab->arena, int_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, int_chunk, 0, 0, 0);
|
||||
lnk_symbol_table_push(symtab, int_symbol);
|
||||
String8 int_symbol_name = push_str8f(symtab->arena->v[0], "%S.%S.name.delayed", dll->name, header->func_name);
|
||||
int_symbol = lnk_symbol_table_push_defined_chunk(symtab, int_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, int_chunk, 0, 0, 0);
|
||||
|
||||
// dynamic linker patches this voff on DLL load event
|
||||
ilt_chunk = lnk_section_push_chunk_bss(data_sect, ilt_table_chunk, import_size, sort_index);
|
||||
@@ -635,13 +601,11 @@ lnk_import_table_push_func_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *sym
|
||||
lnk_section_associate_chunks(data_sect, iat_chunk, load_thunk_chunk);
|
||||
}
|
||||
|
||||
String8 iat_symbol_name = push_str8f(symtab->arena, "__imp_%S", header->func_name);
|
||||
LNK_Symbol *iat_symbol = lnk_make_defined_symbol_chunk(symtab->arena, iat_symbol_name, LNK_DefinedSymbolVisibility_Extern, 0, iat_chunk, 0, 0, 0);
|
||||
lnk_symbol_table_push(symtab, iat_symbol);
|
||||
String8 iat_symbol_name = push_str8f(symtab->arena->v[0], "__imp_%S", header->func_name);
|
||||
LNK_Symbol *iat_symbol = lnk_symbol_table_push_defined_chunk(symtab, iat_symbol_name, LNK_DefinedSymbolVisibility_Extern, 0, iat_chunk, 0, 0, 0);
|
||||
|
||||
String8 ilt_symbol_name = push_str8f(symtab->arena, "%S.%S.ilt.delayed", dll->name, header->func_name);
|
||||
LNK_Symbol *ilt_symbol = lnk_make_defined_symbol_chunk(symtab->arena, ilt_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, ilt_chunk, 0, 0, 0);
|
||||
lnk_symbol_table_push(symtab, ilt_symbol);
|
||||
String8 ilt_symbol_name = push_str8f(symtab->arena->v[0], "%S.%S.ilt.delayed", dll->name, header->func_name);
|
||||
LNK_Symbol *ilt_symbol = lnk_symbol_table_push_defined_chunk(symtab, ilt_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, ilt_chunk, 0, 0, 0);
|
||||
|
||||
// fill out import
|
||||
LNK_ImportFunc *func = push_array(imptab->arena, LNK_ImportFunc, 1);
|
||||
@@ -771,9 +735,8 @@ lnk_emit_load_thunk_symbol(LNK_SymbolTable *symtab, LNK_Chunk *chunk, String8 fu
|
||||
{
|
||||
ProfBeginFunction();
|
||||
// emit load thunk symbol
|
||||
String8 load_thunk_name = push_str8f(symtab->arena, "__imp_load_%S", func_name);
|
||||
LNK_Symbol *load_thunk_symbol = lnk_make_defined_symbol_chunk(symtab->arena, load_thunk_name, LNK_DefinedSymbolVisibility_Extern, LNK_DefinedSymbolFlag_IsFunc|LNK_DefinedSymbolFlag_IsThunk, chunk, 0, 0, 0);
|
||||
lnk_symbol_table_push(symtab, load_thunk_symbol);
|
||||
String8 load_thunk_name = push_str8f(symtab->arena->v[0], "__imp_load_%S", func_name);
|
||||
LNK_Symbol *load_thunk_symbol = lnk_symbol_table_push_defined_chunk(symtab, load_thunk_name, LNK_DefinedSymbolVisibility_Extern, LNK_DefinedSymbolFlag_IsFunc|LNK_DefinedSymbolFlag_IsThunk, chunk, 0, 0, 0);
|
||||
ProfEnd();
|
||||
return load_thunk_symbol;
|
||||
}
|
||||
@@ -782,9 +745,8 @@ internal LNK_Symbol *
|
||||
lnk_emit_jmp_thunk_symbol(LNK_SymbolTable *symtab, LNK_Chunk *chunk, String8 func_name)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
String8 jmp_thunk_name = push_str8f(symtab->arena, "%S", func_name);
|
||||
LNK_Symbol *jmp_thunk_symbol = lnk_make_defined_symbol_chunk(symtab->arena, jmp_thunk_name, LNK_DefinedSymbolVisibility_Extern, LNK_DefinedSymbolFlag_IsFunc|LNK_DefinedSymbolFlag_IsThunk, chunk, 0, 0, 0);
|
||||
lnk_symbol_table_push(symtab, jmp_thunk_symbol);
|
||||
String8 jmp_thunk_name = push_str8f(symtab->arena->v[0], "%S", func_name);
|
||||
LNK_Symbol *jmp_thunk_symbol = lnk_symbol_table_push_defined_chunk(symtab, jmp_thunk_name, LNK_DefinedSymbolVisibility_Extern, LNK_DefinedSymbolFlag_IsFunc|LNK_DefinedSymbolFlag_IsThunk, chunk, 0, 0, 0);
|
||||
ProfEnd();
|
||||
return jmp_thunk_symbol;
|
||||
}
|
||||
@@ -793,9 +755,8 @@ internal LNK_Symbol *
|
||||
lnk_emit_tail_merge_symbol(LNK_SymbolTable *symtab, LNK_Chunk *chunk, String8 func_name)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
String8 tail_merge_name = push_str8f(symtab->arena, "__tailMerge_%S", func_name);
|
||||
LNK_Symbol *tail_merge_symbol = lnk_make_defined_symbol_chunk(symtab->arena, tail_merge_name, LNK_DefinedSymbolVisibility_Extern, LNK_DefinedSymbolFlag_IsFunc|LNK_DefinedSymbolFlag_IsThunk, chunk, 0, 0, 0);
|
||||
lnk_symbol_table_push(symtab, tail_merge_symbol);
|
||||
String8 tail_merge_name = push_str8f(symtab->arena->v[0], "__tailMerge_%S", func_name);
|
||||
LNK_Symbol *tail_merge_symbol = lnk_symbol_table_push_defined_chunk(symtab, tail_merge_name, LNK_DefinedSymbolVisibility_Extern, LNK_DefinedSymbolFlag_IsFunc|LNK_DefinedSymbolFlag_IsThunk, chunk, 0, 0, 0);
|
||||
ProfEnd();
|
||||
return tail_merge_symbol;
|
||||
}
|
||||
|
||||
@@ -59,12 +59,12 @@ typedef struct LNK_ImportTable
|
||||
HashTable *dll_ht;
|
||||
} LNK_ImportTable;
|
||||
|
||||
internal LNK_ImportTable * lnk_import_table_alloc_regular(LNK_SectionTable *st, LNK_SymbolTable *symtab, COFF_MachineType machine);
|
||||
internal LNK_ImportTable * lnk_import_table_alloc_static(LNK_SectionTable *st, LNK_SymbolTable *symtab, COFF_MachineType machine);
|
||||
internal LNK_ImportTable * lnk_import_table_alloc_delayed(LNK_SectionTable *st, LNK_SymbolTable *symtab, COFF_MachineType machine, B32 is_unloadable, B32 is_bindable);
|
||||
internal void lnk_import_table_release(LNK_ImportTable **imptab);
|
||||
internal LNK_ImportDLL * lnk_import_table_push_dll_regular(LNK_ImportTable *imptab, LNK_SymbolTable *symtab, String8 dll_name, COFF_MachineType machine);
|
||||
internal LNK_ImportDLL * lnk_import_table_push_dll_static(LNK_ImportTable *imptab, LNK_SymbolTable *symtab, String8 dll_name, COFF_MachineType machine);
|
||||
internal LNK_ImportDLL * lnk_import_table_push_dll_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *symtab, String8 dll_name, COFF_MachineType machine);
|
||||
internal LNK_ImportFunc * lnk_import_table_push_func_regular(LNK_ImportTable *imptab, LNK_SymbolTable *symtab, LNK_ImportDLL *dll, COFF_ImportHeader *header);
|
||||
internal LNK_ImportFunc * lnk_import_table_push_func_static(LNK_ImportTable *imptab, LNK_SymbolTable *symtab, LNK_ImportDLL *dll, COFF_ImportHeader *header);
|
||||
internal LNK_ImportFunc * lnk_import_table_push_func_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *symtab, LNK_ImportDLL *dll, COFF_ImportHeader *header);
|
||||
internal LNK_ImportDLL * lnk_import_table_search_dll(LNK_ImportTable *imptab, String8 name);
|
||||
internal LNK_ImportFunc * lnk_import_table_search_func(LNK_ImportDLL *dll, String8 name);
|
||||
|
||||
@@ -0,0 +1,256 @@
|
||||
////////////////////////////////
|
||||
// Shared File API
|
||||
|
||||
shared_function int
|
||||
lnk_open_file_read(char *path, uint64_t path_size, void *handle_buffer, uint64_t handle_buffer_max)
|
||||
{
|
||||
OS_Handle handle = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead, str8((U8*)path, path_size));
|
||||
Assert(sizeof(handle) <= handle_buffer_max);
|
||||
MemoryCopy(handle_buffer, &handle, sizeof(handle));
|
||||
return !os_handle_match(handle, os_handle_zero());
|
||||
}
|
||||
|
||||
shared_function int
|
||||
lnk_open_file_write(char *path, uint64_t path_size, void *handle_buffer, uint64_t handle_buffer_max)
|
||||
{
|
||||
OS_Handle handle = os_file_open(OS_AccessFlag_Write, str8((U8*)path, path_size));
|
||||
Assert(sizeof(handle) <= handle_buffer_max);
|
||||
MemoryCopy(handle_buffer, &handle, sizeof(handle));
|
||||
return !os_handle_match(handle, os_handle_zero());
|
||||
}
|
||||
|
||||
shared_function void
|
||||
lnk_close_file(void *raw_handle)
|
||||
{
|
||||
OS_Handle handle = *(OS_Handle *)raw_handle;
|
||||
os_file_close(handle);
|
||||
}
|
||||
|
||||
shared_function uint64_t
|
||||
lnk_size_from_file(void *raw_handle)
|
||||
{
|
||||
OS_Handle handle = *(OS_Handle *)raw_handle;
|
||||
FileProperties props = os_properties_from_file(handle);
|
||||
return props.size;
|
||||
}
|
||||
|
||||
shared_function uint64_t
|
||||
lnk_read_file(void *raw_handle, void *buffer, uint64_t buffer_max)
|
||||
{
|
||||
OS_Handle handle = *(OS_Handle *)raw_handle;
|
||||
U64 read_size = os_file_read(handle, rng_1u64(0, buffer_max), buffer);
|
||||
Assert(read_size == buffer_max);
|
||||
return read_size;
|
||||
}
|
||||
|
||||
shared_function uint64_t
|
||||
lnk_write_file(void *raw_handle, uint64_t offset, void *buffer, uint64_t buffer_size)
|
||||
{
|
||||
OS_Handle handle = *(OS_Handle*)raw_handle;
|
||||
U64 write_size = os_file_write(handle, r1u64(offset, offset + buffer_size), buffer);
|
||||
return write_size;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal void
|
||||
lnk_log_read(String8 path, U64 size)
|
||||
{
|
||||
lnk_log(LNK_Log_IO_Read, "Read from \"%S\" %M", path, size);
|
||||
}
|
||||
|
||||
internal String8
|
||||
lnk_read_data_from_file_path(Arena *arena, String8 path)
|
||||
{
|
||||
String8 data = str8_zero();
|
||||
OS_Handle handle = {0};
|
||||
int is_open = lnk_open_file_read((char*)path.str, path.size, &handle, sizeof(handle));
|
||||
if (is_open) {
|
||||
U64 buffer_size = lnk_size_from_file(&handle);
|
||||
U8 *buffer = push_array_no_zero(arena, U8, buffer_size);
|
||||
U64 read_size = lnk_read_file(&handle, buffer, buffer_size);
|
||||
|
||||
data = str8(buffer, read_size);
|
||||
|
||||
lnk_close_file(&handle);
|
||||
|
||||
if (read_size != buffer_size) {
|
||||
lnk_error(LNK_Warning_IllData, "incomplete file read occurred, read %u bytes, expected %u bytes, file %S", path);
|
||||
}
|
||||
|
||||
if (lnk_get_log_status(LNK_Log_IO_Read)) {
|
||||
lnk_log_read(path, data.size);
|
||||
}
|
||||
} else {
|
||||
lnk_error(LNK_Error_FileNotFound, "unable to open file %S", path);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
internal
|
||||
THREAD_POOL_TASK_FUNC(lnk_data_size_from_file_path_task)
|
||||
{
|
||||
LNK_DiskReader *task = raw_task;
|
||||
String8 path = task->path_arr.v[task_id];
|
||||
|
||||
OS_Handle handle = {0};
|
||||
U64 size = 0;
|
||||
|
||||
int is_open = lnk_open_file_read((char*)path.str, path.size, &handle, sizeof(handle));
|
||||
if (is_open) {
|
||||
size = lnk_size_from_file(&handle);
|
||||
}
|
||||
|
||||
task->handle_arr[task_id] = handle;
|
||||
task->size_arr[task_id] = size;
|
||||
}
|
||||
|
||||
internal
|
||||
THREAD_POOL_TASK_FUNC(lnk_data_from_file_path_task)
|
||||
{
|
||||
LNK_DiskReader *task = raw_task;
|
||||
|
||||
OS_Handle handle = task->handle_arr[task_id];
|
||||
U64 buffer_size = task->size_arr[task_id];
|
||||
U8 *buffer = task->buffer + task->off_arr[task_id];
|
||||
|
||||
U64 read_size = lnk_read_file(&handle, buffer, buffer_size);
|
||||
Assert(read_size == buffer_size);
|
||||
|
||||
task->data_arr.v[task_id] = str8(buffer, read_size);
|
||||
}
|
||||
|
||||
internal String8Array
|
||||
lnk_read_data_from_file_path_parallel(TP_Context *tp, Arena *arena, String8Array path_arr)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena,1);
|
||||
|
||||
LNK_DiskReader reader = {0};
|
||||
reader.path_arr = path_arr;
|
||||
reader.handle_arr = push_array_no_zero(scratch.arena, OS_Handle, path_arr.count);
|
||||
reader.size_arr = push_array_no_zero(scratch.arena, U64, path_arr.count);
|
||||
|
||||
// open handles and get sizes
|
||||
tp_for_parallel(tp, 0, path_arr.count, lnk_data_size_from_file_path_task, &reader);
|
||||
|
||||
// compute file buffer size
|
||||
U64 total_data_size = sum_array_u64(path_arr.count, reader.size_arr);
|
||||
|
||||
// assign offsets into file buffer
|
||||
U64 *off_arr = push_array_no_zero(scratch.arena, U64, path_arr.count);
|
||||
MemoryCopyTyped(off_arr, reader.size_arr, path_arr.count);
|
||||
counts_to_offsets_array_u64(path_arr.count, off_arr);
|
||||
|
||||
reader.data_arr = str8_array_reserve(arena, path_arr.count);
|
||||
reader.off_arr = off_arr;
|
||||
reader.buffer = push_array_no_zero(arena, U8, total_data_size);
|
||||
|
||||
// read files and close handles
|
||||
tp_for_parallel(tp, 0, path_arr.count, lnk_data_from_file_path_task, &reader);
|
||||
|
||||
String8Array result = {0};
|
||||
result.count = path_arr.count;
|
||||
result.v = reader.data_arr.v;
|
||||
|
||||
if (lnk_get_log_status(LNK_Log_IO_Read)) {
|
||||
for (U64 i = 0; i < result.count; ++i) {
|
||||
lnk_log_read(path_arr.v[i], result.v[i].size);
|
||||
}
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal void
|
||||
lnk_write_data_list_to_file_path(String8 path, String8List data)
|
||||
{
|
||||
ProfBeginV("Write %M to %S", data.total_size, path);
|
||||
|
||||
B32 is_written = 0;
|
||||
|
||||
OS_Handle handle;
|
||||
if (lnk_open_file_write((char*)path.str, path.size, &handle, sizeof(handle))) {
|
||||
U64 offset = 0;
|
||||
for (String8Node *data_n = data.first; data_n != 0; data_n = data_n->next) {
|
||||
if (!lnk_write_file(&handle, offset, data_n->string.str, data_n->string.size)) {
|
||||
break;
|
||||
}
|
||||
offset += data_n->string.size;
|
||||
}
|
||||
|
||||
lnk_close_file(&handle);
|
||||
|
||||
is_written = (offset == data.total_size);
|
||||
if (is_written) {
|
||||
if (lnk_get_log_status(LNK_Log_IO_Write)) {
|
||||
lnk_log(LNK_Log_IO_Write, "File \"%S\" %M written", path, data.total_size);
|
||||
}
|
||||
} else {
|
||||
lnk_error(LNK_Error_IO, "incomplete write occurred, %M written, expected %M, file %S",
|
||||
offset, data.total_size, path);
|
||||
}
|
||||
} else {
|
||||
lnk_error(LNK_Error_NoAccess, "don't have access to write to %S", path);
|
||||
}
|
||||
|
||||
ProfEnd();
|
||||
}
|
||||
|
||||
internal void
|
||||
lnk_write_data_to_file_path(String8 path, String8 data)
|
||||
{
|
||||
Temp scratch = scratch_begin(0,0);
|
||||
String8List data_list = {0};
|
||||
str8_list_push(scratch.arena, &data_list, data);
|
||||
lnk_write_data_list_to_file_path(path, data_list);
|
||||
scratch_end(scratch);
|
||||
}
|
||||
|
||||
internal String8List
|
||||
lnk_file_search(Arena *arena, String8List dir_list, String8 file_path)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
String8List match_list; MemoryZeroStruct(&match_list);
|
||||
|
||||
if (os_file_path_exists(file_path)) {
|
||||
String8 str = push_str8_copy(arena, file_path);
|
||||
str8_list_push(arena, &match_list, str);
|
||||
}
|
||||
|
||||
PathStyle file_path_style = path_style_from_str8(file_path);
|
||||
B32 is_relative = file_path_style != PathStyle_WindowsAbsolute &&
|
||||
file_path_style != PathStyle_UnixAbsolute;
|
||||
|
||||
if (is_relative) {
|
||||
for (String8Node *i = dir_list.first; i != 0; i = i->next) {
|
||||
String8List path_list = {0};
|
||||
str8_list_push(scratch.arena, &path_list, i->string);
|
||||
str8_list_push(scratch.arena, &path_list, file_path);
|
||||
String8 path = str8_path_list_join_by_style(scratch.arena, &path_list, PathStyle_SystemAbsolute);
|
||||
B32 file_exists = os_file_path_exists(path);
|
||||
if (file_exists) {
|
||||
B32 is_unique = 1;
|
||||
OS_FileID file_id = os_id_from_file_path(path);
|
||||
for (String8Node *k = match_list.first; k != 0; k = k->next) {
|
||||
OS_FileID test_id = os_id_from_file_path(k->string);
|
||||
int cmp = os_file_id_compare(test_id, file_id) != 0;
|
||||
if (cmp == 0) {
|
||||
is_unique = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (is_unique) {
|
||||
String8 str = push_str8_copy(arena, path);
|
||||
str8_list_push(arena, &match_list, str);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
ProfEnd();
|
||||
return match_list;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
typedef struct
|
||||
{
|
||||
String8Array path_arr;
|
||||
String8Array data_arr;
|
||||
OS_Handle *handle_arr;
|
||||
U64 *size_arr;
|
||||
U64 *off_arr;
|
||||
U8 *buffer;
|
||||
} LNK_DiskReader;
|
||||
|
||||
////////////////////////////////
|
||||
// Shared File API
|
||||
|
||||
shared_function int lnk_open_file_read(char *path, uint64_t path_size, void *handle_buffer, uint64_t handle_buffer_max);
|
||||
shared_function int lnk_open_file_write(char *path, uint64_t path_size, void *handle_buffer, uint64_t handle_buffer_max);
|
||||
shared_function void lnk_close_file(void *raw_handle);
|
||||
shared_function uint64_t lnk_size_from_file(void *raw_handle);
|
||||
shared_function uint64_t lnk_read_file(void *raw_handle, void *buffer, uint64_t buffer_max);
|
||||
shared_function uint64_t lnk_write_file(void *raw_handle, uint64_t offset, void *buffer, uint64_t buffer_size);
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal String8 lnk_read_data_from_file_path(Arena *arena, String8 path);
|
||||
internal String8Array lnk_read_data_from_file_path_parallel(TP_Context *tp, Arena *arena, String8Array path_arr);
|
||||
|
||||
internal void lnk_write_data_list_to_file_path(String8 path, String8List list);
|
||||
internal void lnk_write_data_to_file_path(String8 path, String8 data);
|
||||
|
||||
internal String8List lnk_file_search(Arena *arena, String8List dir_list, String8 file_path);
|
||||
|
||||
+23
-10
@@ -74,7 +74,7 @@ lnk_lib_symbol_name_compar(const void *raw_a, const void *raw_b)
|
||||
{
|
||||
const LNK_Symbol *sa = (const LNK_Symbol *)raw_a;
|
||||
const LNK_Symbol *sb = (const LNK_Symbol *)raw_b;
|
||||
return str8_compar_case_sensetive(&sa->name, &sb->name);
|
||||
return str8_compar_case_sensitive(&sa->name, &sb->name);
|
||||
}
|
||||
|
||||
int
|
||||
@@ -97,6 +97,8 @@ lnk_lib_symbol_array_sort(LNK_LibSymbol *arr, U64 count)
|
||||
internal LNK_Lib
|
||||
lnk_lib_from_data(Arena *arena, String8 data, String8 path)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
|
||||
U64 symbol_count;
|
||||
String8 string_table;
|
||||
U32 *member_off_arr;
|
||||
@@ -167,9 +169,11 @@ lnk_lib_from_data(Arena *arena, String8 data, String8 path)
|
||||
lib.symbol_name_list = symbol_name_list;
|
||||
lib.long_names = parse.long_names;
|
||||
|
||||
ProfEnd();
|
||||
return lib;
|
||||
}
|
||||
|
||||
internal
|
||||
THREAD_POOL_TASK_FUNC(lnk_lib_initer)
|
||||
{
|
||||
LNK_LibIniter *task = raw_task;
|
||||
@@ -179,6 +183,7 @@ THREAD_POOL_TASK_FUNC(lnk_lib_initer)
|
||||
String8 path = task->path_arr[task_id];
|
||||
|
||||
*lib = lnk_lib_from_data(arena, data, path);
|
||||
lib->input_idx = task->base_input_idx + task_id;
|
||||
}
|
||||
|
||||
internal LNK_LibNodeArray
|
||||
@@ -187,15 +192,16 @@ lnk_lib_list_push_parallel(TP_Context *tp, TP_Arena *arena, LNK_LibList *list, S
|
||||
Assert(data_arr.count == path_arr.count);
|
||||
U64 lib_count = data_arr.count;
|
||||
|
||||
LNK_LibIniter lib_initer = {0};
|
||||
lib_initer.node_arr = lnk_lib_list_reserve(arena->v[0], list, lib_count);
|
||||
lib_initer.data_arr = data_arr.v;
|
||||
lib_initer.path_arr = path_arr.v;
|
||||
tp_for_parallel(tp, arena, lib_count, lnk_lib_initer, &lib_initer);
|
||||
LNK_LibIniter task = {0};
|
||||
task.node_arr = lnk_lib_list_reserve(arena->v[0], list, lib_count);
|
||||
task.data_arr = data_arr.v;
|
||||
task.path_arr = path_arr.v;
|
||||
task.base_input_idx = list->count;
|
||||
tp_for_parallel(tp, arena, lib_count, lnk_lib_initer, &task);
|
||||
|
||||
LNK_LibNodeArray arr;
|
||||
arr.count = lib_count;
|
||||
arr.v = lib_initer.node_arr;
|
||||
LNK_LibNodeArray arr = {0};
|
||||
arr.count = lib_count;
|
||||
arr.v = task.node_arr;
|
||||
return arr;
|
||||
}
|
||||
|
||||
@@ -507,15 +513,22 @@ internal LNK_LibBuild
|
||||
lnk_build_lib(Arena *arena, COFF_MachineType machine, COFF_TimeStamp time_stamp, String8 dll_name, LNK_ObjList obj_list, LNK_ExportTable *exptab)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
|
||||
LNK_LibWriter *writer = lnk_lib_writer_alloc();
|
||||
for (LNK_ObjNode *obj_node = obj_list.first; obj_node != 0; obj_node = obj_node->next) {
|
||||
lnk_lib_writer_push_obj(writer, &obj_node->data);
|
||||
}
|
||||
for (LNK_Export *exp = exptab->name_export_list.first; exp != 0; exp = exp->next) {
|
||||
|
||||
KeyValuePair *raw_export_arr = key_value_pairs_from_hash_table(scratch.arena, exptab->name_export_ht);
|
||||
for (U64 i = 0; i < exptab->name_export_ht->count; ++i) {
|
||||
LNK_Export *exp = raw_export_arr[i].value_raw;
|
||||
lnk_lib_writer_push_export(writer, machine, time_stamp, dll_name, exp);
|
||||
}
|
||||
LNK_LibBuild lib = lnk_lib_build_from_writer(arena, writer);
|
||||
lnk_lib_writer_release(&writer);
|
||||
|
||||
scratch_end(scratch);
|
||||
ProfEnd();
|
||||
return lib;
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ typedef struct LNK_Lib
|
||||
U32 * member_off_arr;
|
||||
String8List symbol_name_list;
|
||||
String8 long_names;
|
||||
U64 input_idx;
|
||||
} LNK_Lib;
|
||||
|
||||
typedef struct LNK_LibNode
|
||||
@@ -92,9 +93,10 @@ typedef struct LNK_LibBuild
|
||||
|
||||
typedef struct
|
||||
{
|
||||
LNK_LibNode *node_arr;
|
||||
String8 *data_arr;
|
||||
String8 *path_arr;
|
||||
LNK_LibNode *node_arr;
|
||||
String8 *data_arr;
|
||||
String8 *path_arr;
|
||||
U64 base_input_idx;
|
||||
} LNK_LibIniter;
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
@@ -40,7 +40,8 @@ lnk_log_type_from_string(String8 string)
|
||||
"Debug", LNK_Log_Debug,
|
||||
"InputObj", LNK_Log_InputObj,
|
||||
"InputLib", LNK_Log_InputLib,
|
||||
"IO", LNK_Log_IO,
|
||||
"IO_Read", LNK_Log_IO_Read,
|
||||
"IO_Write", LNK_Log_IO_Write,
|
||||
"SizeBreakdown", LNK_Log_SizeBreakdown,
|
||||
"LinkStats", LNK_Log_LinkStats,
|
||||
"Timers", LNK_Log_Timers,
|
||||
|
||||
@@ -9,7 +9,8 @@ typedef enum
|
||||
LNK_Log_Debug,
|
||||
LNK_Log_InputObj,
|
||||
LNK_Log_InputLib,
|
||||
LNK_Log_IO,
|
||||
LNK_Log_IO_Read,
|
||||
LNK_Log_IO_Write,
|
||||
LNK_Log_SizeBreakdown,
|
||||
LNK_Log_LinkStats,
|
||||
LNK_Log_Timers,
|
||||
|
||||
+29
-14
@@ -61,7 +61,7 @@ lnk_input_obj_compar(const void *raw_a, const void *raw_b)
|
||||
{
|
||||
const LNK_InputObj **a = (const LNK_InputObj **) raw_a;
|
||||
const LNK_InputObj **b = (const LNK_InputObj **) raw_b;
|
||||
int cmp = str8_compar_case_sensetive(&(*a)->path, &(*b)->path);
|
||||
int cmp = str8_compar_case_sensitive(&(*a)->path, &(*b)->path);
|
||||
return cmp;
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ lnk_input_obj_compar_is_before(void *raw_a, void *raw_b)
|
||||
{
|
||||
LNK_InputObj **a = raw_a;
|
||||
LNK_InputObj **b = raw_b;
|
||||
int cmp = str8_compar_case_sensetive(&(*a)->path, &(*b)->path);
|
||||
int cmp = str8_compar_case_sensitive(&(*a)->path, &(*b)->path);
|
||||
int is_before = cmp < 0;
|
||||
return is_before;
|
||||
}
|
||||
@@ -259,11 +259,11 @@ THREAD_POOL_TASK_FUNC(lnk_manifest_dependency_collector)
|
||||
Rng1U64 range = task->range_arr[task_id];
|
||||
String8List *list = &task->out_arr[task_id];
|
||||
|
||||
LNK_Obj **obj_ptr = &task->in_arr[range.min];
|
||||
LNK_Obj **obj_opl = &task->in_arr[range.max];
|
||||
LNK_ObjNode *obj_ptr = &task->in_arr[range.min];
|
||||
LNK_ObjNode *obj_opl = &task->in_arr[range.max];
|
||||
|
||||
for (; obj_ptr < obj_opl; obj_ptr += 1) {
|
||||
LNK_Obj *obj = *obj_ptr;
|
||||
LNK_Obj *obj = &obj_ptr->data;
|
||||
LNK_DirectiveList *dirs = &obj->directive_info.v[LNK_Directive_ManifestDependency];
|
||||
for (LNK_Directive *dir = dirs->first; dir != 0; dir = dir->next) {
|
||||
String8List dep = str8_list_copy(arena, &dir->value_list);
|
||||
@@ -273,14 +273,14 @@ THREAD_POOL_TASK_FUNC(lnk_manifest_dependency_collector)
|
||||
}
|
||||
|
||||
internal String8List
|
||||
lnk_collect_manifest_dependency_list(TP_Context *tp, TP_Arena *arena, LNK_Obj **obj_arr, U64 obj_count)
|
||||
lnk_collect_manifest_dependency_list(TP_Context *tp, TP_Arena *arena, LNK_ObjNodeArray obj_node_arr)
|
||||
{
|
||||
Temp scratch = scratch_begin(0,0);
|
||||
Temp scratch = scratch_begin(arena->v, arena->count);
|
||||
|
||||
LNK_ManifestDependencyCollector task_data = {0};
|
||||
task_data.in_arr = obj_arr;
|
||||
task_data.in_arr = obj_node_arr.v;
|
||||
task_data.out_arr = push_array(scratch.arena, String8List, tp->worker_count);
|
||||
task_data.range_arr = tp_divide_work(scratch.arena, obj_count, tp->worker_count);
|
||||
task_data.range_arr = tp_divide_work(scratch.arena, obj_node_arr.count, tp->worker_count);
|
||||
tp_for_parallel(tp, arena, tp->worker_count, lnk_manifest_dependency_collector, &task_data);
|
||||
|
||||
String8List result = str8_list_arr_concat(task_data.out_arr, tp->worker_count);
|
||||
@@ -399,7 +399,7 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer)
|
||||
chunk->flags = coff_sect->flags;
|
||||
chunk->associate = 0;
|
||||
chunk->u.leaf = data;
|
||||
lnk_chunk_set_debugf(arena, chunk, "%S: name: %S, isect: 0x%llX", path, sect_name_arr[sect_idx], sect_idx);
|
||||
lnk_chunk_set_debugf(arena, chunk, "%S: name: %S, obj_idx: 0x%llX isect: 0x%llX", cached_path, sect_name_arr[sect_idx], obj_idx, sect_idx);
|
||||
}
|
||||
|
||||
// :common_block
|
||||
@@ -414,10 +414,11 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer)
|
||||
master_common_block->flags = LNK_BSS_SECTION_FLAGS;
|
||||
master_common_block->associate = 0;
|
||||
master_common_block->u.list = push_array(arena, LNK_ChunkList, 1);
|
||||
lnk_chunk_set_debugf(arena, master_common_block, "%S: master common block", path);
|
||||
lnk_chunk_set_debugf(arena, master_common_block, "%S: master common block", cached_path);
|
||||
|
||||
// convert from coff
|
||||
LNK_SymbolArray symbol_arr = lnk_symbol_array_from_coff(arena, input->data, cached_path, coff_info.string_table_off, coff_info.section_count_no_null, coff_sect_arr, coff_symbols, chunk_arr, master_common_block);
|
||||
B32 is_big_obj = coff_info.type == COFF_DataType_BIG_OBJ;
|
||||
LNK_SymbolArray symbol_arr = lnk_symbol_array_from_coff(arena, input->data, obj, cached_path, is_big_obj, coff_info.string_table_off, coff_info.section_count_no_null, coff_sect_arr, coff_symbols, chunk_arr, master_common_block);
|
||||
LNK_SymbolList symbol_list = lnk_symbol_list_from_array(arena, symbol_arr);
|
||||
LNK_RelocList *reloc_list_arr = lnk_reloc_list_array_from_coff(arena, coff_info.machine, input->data, coff_info.section_count_no_null, coff_sect_arr, chunk_arr, symbol_arr);
|
||||
|
||||
@@ -425,6 +426,7 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer)
|
||||
obj->data = input->data;
|
||||
obj->path = cached_path;
|
||||
obj->lib_path = cached_lib_path;
|
||||
obj->input_idx = obj_idx;
|
||||
obj->machine = coff_info.machine;
|
||||
obj->chunk_count = chunk_count;
|
||||
obj->sect_count = coff_info.section_count_no_null;
|
||||
@@ -712,7 +714,9 @@ lnk_obj_list_push_parallel(TP_Context *tp, TP_Arena *arena, LNK_ObjList *obj_lis
|
||||
internal LNK_SymbolArray
|
||||
lnk_symbol_array_from_coff(Arena *arena,
|
||||
String8 coff_data,
|
||||
LNK_Obj *obj,
|
||||
String8 obj_path,
|
||||
B32 is_big_obj,
|
||||
U64 string_table_off,
|
||||
U64 sect_count,
|
||||
COFF_SectionHeader *coff_sect_arr,
|
||||
@@ -729,7 +733,8 @@ lnk_symbol_array_from_coff(Arena *arena,
|
||||
for (U64 symbol_idx = 0; symbol_idx < coff_symbols.count; symbol_idx += 1) {
|
||||
COFF_Symbol32 *coff_symbol = &coff_symbols.v[symbol_idx];
|
||||
LNK_Symbol *symbol = &symbol_array.v[symbol_idx];
|
||||
lnk_symbol_set_debug(symbol, obj_path);
|
||||
|
||||
symbol->obj = obj;
|
||||
|
||||
String8 name = coff_read_symbol_name(coff_data, string_table_off, &coff_symbol->name);
|
||||
|
||||
@@ -771,7 +776,17 @@ lnk_symbol_array_from_coff(Arena *arena,
|
||||
check_sum = secdef->check_sum;
|
||||
|
||||
if (secdef->selection == COFF_ComdatSelectType_ASSOCIATIVE) {
|
||||
LNK_Chunk *head_chunk = &chunk_arr[secdef->number - 1];
|
||||
U32 secdef_number = secdef->number_lo;
|
||||
if (is_big_obj) {
|
||||
secdef_number |= (U32)secdef->number_hi << 16;
|
||||
}
|
||||
|
||||
if (secdef_number == 0 || secdef_number > sect_count) {
|
||||
lnk_error(LNK_Error_IllData, "%S: symbol %u has out of bounds section definition number %u", name, symbol_idx, secdef_number);
|
||||
break;
|
||||
}
|
||||
|
||||
LNK_Chunk *head_chunk = &chunk_arr[secdef_number - 1];
|
||||
LNK_Chunk *associate_chunk = &chunk_arr[coff_symbol->section_number - 1];
|
||||
lnk_chunk_associate(arena, head_chunk, associate_chunk);
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ typedef struct LNK_Obj
|
||||
String8 data;
|
||||
String8 path;
|
||||
String8 lib_path;
|
||||
U64 input_idx;
|
||||
U64 common_symbol_size;
|
||||
COFF_MachineType machine;
|
||||
U64 chunk_count;
|
||||
@@ -151,7 +152,7 @@ typedef struct
|
||||
|
||||
typedef struct
|
||||
{
|
||||
LNK_Obj **in_arr;
|
||||
LNK_ObjNode *in_arr;
|
||||
String8List *out_arr;
|
||||
Rng1U64 *range_arr;
|
||||
} LNK_ManifestDependencyCollector;
|
||||
@@ -179,7 +180,7 @@ internal LNK_ChunkList * lnk_collect_obj_chunks(TP_Context *tp, TP_Arena *arena
|
||||
internal LNK_ObjNodeArray lnk_obj_list_push_parallel(TP_Context *tp, TP_Arena *tp_arena, LNK_ObjList *obj_list, LNK_SectionTable *st, U64 input_count, LNK_InputObj **inputs);
|
||||
|
||||
internal LNK_Chunk * lnk_sect_chunk_array_from_coff(Arena *arena, U64 obj_id, String8 obj_path, String8 coff_data, U64 sect_count, COFF_SectionHeader *coff_sect_arr, String8 *sect_name_arr, String8 *sect_postfix_arr);
|
||||
internal LNK_SymbolArray lnk_symbol_array_from_coff(Arena *arena, String8 coff_data, String8 obj_path, U64 string_table_off, U64 sect_count, COFF_SectionHeader *coff_sect_arr, COFF_Symbol32Array coff_symbols, LNK_Chunk *chunk_arr, LNK_Chunk *master_common_block);
|
||||
internal LNK_SymbolArray lnk_symbol_array_from_coff(Arena *arena, String8 coff_data, LNK_Obj *obj, String8 obj_path, B32 is_big_obj, U64 string_table_off, U64 sect_count, COFF_SectionHeader *coff_sect_arr, COFF_Symbol32Array coff_symbols, LNK_Chunk *chunk_arr, LNK_Chunk *master_common_block);
|
||||
internal LNK_RelocList lnk_reloc_list_from_coff_reloc_array(Arena *arena, COFF_MachineType machine, LNK_Chunk *chunk, LNK_SymbolArray symbol_array, COFF_Reloc *reloc_v, U64 reloc_count);
|
||||
internal LNK_RelocList * lnk_reloc_list_array_from_coff(Arena *arena, COFF_MachineType machine, String8 coff_data, U64 sect_count, COFF_SectionHeader *coff_sect_arr, LNK_Chunk *sect_chunk_arr, LNK_SymbolArray symbol_array);
|
||||
internal LNK_DirectiveInfo lnk_init_directives(Arena *arena, String8 obj_path, U64 chunk_count, String8 *sect_name_arr, LNK_Chunk *chunk_arr);
|
||||
|
||||
@@ -250,16 +250,18 @@ lnk_code_align_byte_from_machine(COFF_MachineType machine)
|
||||
internal void
|
||||
lnk_section_build_data(LNK_Section *sect, COFF_MachineType machine)
|
||||
{
|
||||
if (sect->is_loose && sect->has_layout) {
|
||||
// get value for align data fill
|
||||
U8 align_byte = 0;
|
||||
B32 is_code = !!(sect->flags & COFF_SectionFlag_CNT_CODE);
|
||||
if (is_code) {
|
||||
align_byte = lnk_code_align_byte_from_machine(machine);
|
||||
if (sect->is_loose) {
|
||||
if (sect->has_layout) {
|
||||
sect->layout = lnk_build_chunk_layout(sect->arena, sect->cman);
|
||||
} else {
|
||||
sect->layout.total_count = sect->cman->total_chunk_count;
|
||||
sect->layout.chunk_ptr_array = lnk_make_chunk_id_map(sect->arena, sect->cman);
|
||||
sect->layout.chunk_off_array = 0;
|
||||
sect->layout.chunk_file_size_array = 0;
|
||||
sect->layout.chunk_virt_size_array = 0;
|
||||
sect->layout.align_array_count = 0;
|
||||
sect->layout.align_array = 0;
|
||||
}
|
||||
|
||||
sect->layout = lnk_build_chunk_layout(sect->arena, sect->cman, sect->flags, align_byte);
|
||||
|
||||
sect->is_loose = 0;
|
||||
}
|
||||
}
|
||||
@@ -300,7 +302,7 @@ lnk_section_table_push(LNK_SectionTable *st, String8 name, COFF_SectionFlags fla
|
||||
B32 found = 0;
|
||||
for (LNK_SectionNode *curr = sect_list->first, *prev = NULL; curr != NULL; prev = curr, curr = curr->next) {
|
||||
LNK_Section *sect = &curr->data;
|
||||
int cmp = str8_compar_case_sensetive(&sort_index, §->sort_index);
|
||||
int cmp = str8_compar_case_sensitive(&sort_index, §->sort_index);
|
||||
if (cmp < 0) {
|
||||
if (prev == NULL) {
|
||||
SLLQueuePushFront(sect_list->first, sect_list->last, sect_node);
|
||||
@@ -594,19 +596,48 @@ lnk_section_table_assign_indices(LNK_SectionTable *st)
|
||||
}
|
||||
|
||||
internal String8
|
||||
lnk_section_table_serialize(Arena *arena, LNK_SectionTable *st)
|
||||
lnk_section_table_serialize(TP_Context *tp, Arena *arena, LNK_SectionTable *st, COFF_MachineType machine)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
String8List image_list = {0};
|
||||
for (LNK_SectionNode *sect_node = st->list.first; sect_node != NULL; sect_node = sect_node->next) {
|
||||
LNK_Section *sect = §_node->data;
|
||||
str8_list_push(scratch.arena, &image_list, sect->layout.data);
|
||||
|
||||
U64 image_size = 0;
|
||||
for (LNK_SectionNode *sect_n = st->list.first; sect_n != 0; sect_n = sect_n->next) {
|
||||
LNK_Section *sect = §_n->data;
|
||||
if (sect->has_layout) {
|
||||
U64 root_size = sect->layout.chunk_file_size_array[sect->root->ref.chunk_id];
|
||||
image_size += root_size;
|
||||
}
|
||||
}
|
||||
String8 result = str8_list_join(arena, &image_list, NULL);
|
||||
|
||||
U8 *image_buffer = push_array_no_zero(arena, U8, image_size);
|
||||
String8 image = str8(image_buffer, image_size);
|
||||
U64 image_cursor = 0;
|
||||
|
||||
for (LNK_SectionNode *sect_n = st->list.first; sect_n != 0; sect_n = sect_n->next) {
|
||||
LNK_Section *sect = §_n->data;
|
||||
if (sect->has_layout) {
|
||||
if (sect->flags & COFF_SectionFlag_CNT_UNINITIALIZED_DATA) {
|
||||
continue;
|
||||
}
|
||||
|
||||
U64 sect_size = sect->layout.chunk_file_size_array[sect->root->ref.chunk_id];
|
||||
String8 sect_data = str8_substr(image, rng_1u64(image_cursor, image_cursor + sect_size));
|
||||
|
||||
U8 fill_byte = 0;
|
||||
if (sect->flags & COFF_SectionFlag_CNT_CODE) {
|
||||
fill_byte = lnk_code_align_byte_from_machine(machine);
|
||||
}
|
||||
|
||||
lnk_serialize_chunk_layout(tp, sect->layout, sect_data, fill_byte);
|
||||
|
||||
image_cursor += sect_size;
|
||||
}
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
ProfEnd();
|
||||
return result;
|
||||
return image;
|
||||
}
|
||||
|
||||
internal LNK_ChunkPtr **
|
||||
@@ -736,24 +767,41 @@ lnk_file_size_from_chunk_ref(LNK_Section **sect_id_map, LNK_ChunkRef chunk_ref)
|
||||
}
|
||||
|
||||
internal String8
|
||||
lnk_data_from_chunk_ref(LNK_Section **sect_id_map, LNK_ChunkRef chunk_ref)
|
||||
lnk_data_from_chunk_ref(LNK_Section **sect_id_map, String8 image_data, LNK_ChunkRef chunk_ref)
|
||||
{
|
||||
LNK_ChunkRef final_chunk_ref = lnk_get_final_chunk_ref(sect_id_map, chunk_ref);
|
||||
LNK_Section *sect = sect_id_map[final_chunk_ref.sect_id];
|
||||
U64 chunk_off = lnk_off_from_chunk_ref(sect_id_map, chunk_ref);
|
||||
U64 chunk_size = lnk_file_size_from_chunk_ref(sect_id_map, chunk_ref);
|
||||
String8 chunk_data = str8_substr(sect->layout.data, r1u64(chunk_off, chunk_off + chunk_size));
|
||||
LNK_ChunkRef final_chunk_ref = lnk_get_final_chunk_ref(sect_id_map, chunk_ref);
|
||||
LNK_Section *sect = sect_id_map[final_chunk_ref.sect_id];
|
||||
String8 chunk_data;
|
||||
if (sect->has_layout) {
|
||||
U64 chunk_size = lnk_file_size_from_chunk_ref(sect_id_map, chunk_ref);
|
||||
U64 chunk_foff = lnk_file_off_from_chunk_ref(sect_id_map, chunk_ref);
|
||||
chunk_data = str8_substr(image_data, r1u64(chunk_foff, chunk_foff + chunk_size));
|
||||
} else {
|
||||
LNK_Chunk *chunk = sect->layout.chunk_ptr_array[final_chunk_ref.chunk_id];
|
||||
Assert(chunk->type == LNK_Chunk_Leaf);
|
||||
chunk_data = chunk->u.leaf;
|
||||
}
|
||||
|
||||
return chunk_data;
|
||||
}
|
||||
|
||||
internal String8
|
||||
lnk_data_from_chunk_ref_no_pad(LNK_Section **sect_id_map, LNK_ChunkRef chunk_ref)
|
||||
lnk_data_from_chunk_ref_no_pad(LNK_Section **sect_id_map, String8 image_data, LNK_ChunkRef chunk_ref)
|
||||
{
|
||||
LNK_ChunkRef final_chunk_ref = lnk_get_final_chunk_ref(sect_id_map, chunk_ref);
|
||||
LNK_Section *sect = sect_id_map[final_chunk_ref.sect_id];
|
||||
U64 chunk_off = lnk_off_from_chunk_ref(sect_id_map, chunk_ref);
|
||||
U64 chunk_size = lnk_virt_size_from_chunk_ref(sect_id_map, chunk_ref);
|
||||
String8 chunk_data = str8_substr(sect->layout.data, r1u64(chunk_off, chunk_off + chunk_size));
|
||||
|
||||
String8 chunk_data;
|
||||
if (sect->has_layout) {
|
||||
U64 chunk_size = lnk_virt_size_from_chunk_ref(sect_id_map, chunk_ref);
|
||||
U64 chunk_foff = lnk_file_off_from_chunk_ref(sect_id_map, chunk_ref);
|
||||
chunk_data = str8_substr(image_data, r1u64(chunk_foff, chunk_foff + chunk_size));
|
||||
} else {
|
||||
LNK_Chunk *chunk = sect->layout.chunk_ptr_array[final_chunk_ref.chunk_id];
|
||||
Assert(chunk->type == LNK_Chunk_Leaf);
|
||||
chunk_data = chunk->u.leaf;
|
||||
}
|
||||
|
||||
return chunk_data;
|
||||
}
|
||||
|
||||
|
||||
@@ -121,7 +121,7 @@ internal void lnk_section_table_build_data(TP_Context *tp, LNK_Se
|
||||
internal void lnk_section_table_assign_virtual_offsets(LNK_SectionTable *st);
|
||||
internal void lnk_section_table_assign_file_offsets(LNK_SectionTable *st);
|
||||
internal void lnk_section_table_assign_indices(LNK_SectionTable *st);
|
||||
internal String8 lnk_section_table_serialize(Arena *arena, LNK_SectionTable *st);
|
||||
internal String8 lnk_section_table_serialize(TP_Context *tp, Arena *arena, LNK_SectionTable *st, COFF_MachineType machine);
|
||||
|
||||
internal LNK_ChunkPtr ** lnk_chunk_id_map_from_section_table(Arena *arena, LNK_SectionTable *st);
|
||||
internal LNK_Section ** lnk_sect_id_map_from_section_table(Arena *arena, LNK_SectionTable *st);
|
||||
@@ -134,8 +134,8 @@ internal U64 lnk_virt_off_from_chunk_ref(LNK_Section **sect_id_map,
|
||||
internal U64 lnk_file_off_from_chunk_ref(LNK_Section **sect_id_map, LNK_ChunkRef chunk_ref);
|
||||
internal U64 lnk_virt_size_from_chunk_ref(LNK_Section **sect_id_map, LNK_ChunkRef chunk_ref);
|
||||
internal U64 lnk_file_size_from_chunk_ref(LNK_Section **sect_id_map, LNK_ChunkRef chunk_ref);
|
||||
internal String8 lnk_data_from_chunk_ref(LNK_Section **sect_id_map, LNK_ChunkRef chunk_ref);
|
||||
internal String8 lnk_data_from_chunk_ref_no_pad(LNK_Section **sect_id_map, LNK_ChunkRef chunk_ref);
|
||||
internal String8 lnk_data_from_chunk_ref(LNK_Section **sect_id_map, String8 image_data, LNK_ChunkRef chunk_ref);
|
||||
internal String8 lnk_data_from_chunk_ref_no_pad(LNK_Section **sect_id_map, String8 image_data, LNK_ChunkRef chunk_ref);
|
||||
internal ISectOff lnk_sc_from_chunk_ref(LNK_Section **sect_id_map, LNK_ChunkRef chunk_ref);
|
||||
internal U64 lnk_virt_off_from_reloc(LNK_Section **sect_id_map, LNK_Reloc *reloc);
|
||||
internal U64 lnk_isect_from_symbol(LNK_Section **sect_id_map, LNK_Symbol *symbol);
|
||||
|
||||
+420
-512
File diff suppressed because it is too large
Load Diff
@@ -90,27 +90,22 @@ typedef enum
|
||||
LNK_Symbol_Undefined,
|
||||
} LNK_SymbolType;
|
||||
|
||||
#define LNK_DEBUG_SYMBOLS 1
|
||||
typedef struct LNK_Symbol
|
||||
{
|
||||
String8 name;
|
||||
LNK_SymbolType type;
|
||||
String8 name;
|
||||
LNK_SymbolType type;
|
||||
struct LNK_Obj *obj;
|
||||
union {
|
||||
LNK_DefinedSymbol defined;
|
||||
LNK_WeakSymbol weak;
|
||||
LNK_UndefinedSymbol undefined;
|
||||
LNK_LazySymbol lazy;
|
||||
} u;
|
||||
#if LNK_DEBUG_SYMBOLS
|
||||
String8 debug;
|
||||
#endif
|
||||
} LNK_Symbol;
|
||||
|
||||
typedef struct LNK_SymbolNode
|
||||
{
|
||||
struct LNK_SymbolNode *next;
|
||||
struct LNK_SymbolNode *prev;
|
||||
U64 hash;
|
||||
LNK_Symbol *data;
|
||||
} LNK_SymbolNode;
|
||||
|
||||
@@ -133,59 +128,51 @@ typedef struct LNK_SymbolArray
|
||||
LNK_Symbol *v;
|
||||
} LNK_SymbolArray;
|
||||
|
||||
typedef struct LNK_SymbolHashTrie
|
||||
{
|
||||
String8 *name;
|
||||
LNK_Symbol *symbol;
|
||||
struct LNK_SymbolHashTrie *child[4];
|
||||
} LNK_SymbolHashTrie;
|
||||
|
||||
typedef struct LNK_SymbolHashTrieChunk
|
||||
{
|
||||
struct LNK_SymbolHashTrieChunk *next;
|
||||
U64 count;
|
||||
U64 cap;
|
||||
LNK_SymbolHashTrie *v;
|
||||
} LNK_SymbolHashTrieChunk;
|
||||
|
||||
typedef struct LNK_SymbolHashTrieChunkList
|
||||
{
|
||||
U64 count;
|
||||
LNK_SymbolHashTrieChunk *first;
|
||||
LNK_SymbolHashTrieChunk *last;
|
||||
} LNK_SymbolHashTrieChunkList;
|
||||
|
||||
typedef struct LNK_SymbolTable
|
||||
{
|
||||
Arena *arena;
|
||||
U64 bucket_count[LNK_SymbolScopeIndex_Count];
|
||||
LNK_SymbolList *buckets[LNK_SymbolScopeIndex_Count];
|
||||
TP_Arena *arena;
|
||||
LNK_SymbolHashTrie *scopes[LNK_SymbolScopeIndex_Count];
|
||||
LNK_SymbolHashTrieChunkList *chunk_lists[LNK_SymbolScopeIndex_Count];
|
||||
} LNK_SymbolTable;
|
||||
|
||||
////////////////////////////////
|
||||
// parallel for wrappers
|
||||
|
||||
typedef struct
|
||||
{
|
||||
LNK_Symbol *symbol_arr;
|
||||
Rng1U64 *range_arr;
|
||||
U64 *hash_arr;
|
||||
} LNK_SymbolNameHasher;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
LNK_SymbolNode **input_arr;
|
||||
Rng1U64 *range_arr;
|
||||
} LNK_SymbolNodePtrHasher;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
LNK_SymbolNode *input_arr;
|
||||
Rng1U64 *range_arr;
|
||||
} LNK_SymbolNodeHasher;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
LNK_SymbolTable *symtab;
|
||||
LNK_SymbolList *bucket_arr;
|
||||
Rng1U64 *range_arr;
|
||||
} LNK_DefinedSymbolInserter;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
LNK_SymbolTable *symtab;
|
||||
LNK_SymbolList *bucket_arr;
|
||||
Rng1U64 *range_arr;
|
||||
Rng1U64 *ranges;
|
||||
LNK_Symbol *arr;
|
||||
} LNK_LazySymbolInserter;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
LNK_SymbolTable *symtab;
|
||||
Rng1U64 *range_arr;
|
||||
} LNK_ComdatFolder;
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
extern LNK_Symbol g_null_symbol;
|
||||
extern LNK_Symbol *g_null_symbol_ptr;
|
||||
global read_only LNK_Symbol g_null_symbol = { str8_lit_comp("NULL"), LNK_Symbol_DefinedStatic };
|
||||
global read_only LNK_Symbol *g_null_symbol_ptr = &g_null_symbol;
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal void lnk_init_symbol(LNK_Symbol *symbol, String8 name, LNK_SymbolType type);
|
||||
internal void lnk_init_defined_symbol(LNK_Symbol *symbol, String8 name, LNK_DefinedSymbolVisibility visibility, LNK_DefinedSymbolFlags flags);
|
||||
@@ -201,53 +188,34 @@ internal LNK_Symbol * lnk_make_undefined_symbol(Arena *arena, String8 name, LNK_
|
||||
internal LNK_Symbol * lnk_make_weak_symbol(Arena *arena, String8 name, COFF_WeakExtType lookup, LNK_Symbol *fallback);
|
||||
internal LNK_Symbol * lnk_make_lazy_symbol(Arena *arena, String8 name, struct LNK_Lib *lib, U64 member_offset);
|
||||
|
||||
#if LNK_DEBUG_SYMBOLS
|
||||
#define lnk_symbol_set_debugf(a, s, fmt, ...) do { (s)->debug = push_str8f((a), fmt, __VA_ARGS__); } while (0)
|
||||
#define lnk_symbol_set_debug(s, str) do { (s)->debug = str; } while (0)
|
||||
#else
|
||||
#define lnk_symbol_set_debugf(...)
|
||||
#define lnk_symbol_set_debug(...)
|
||||
#endif
|
||||
internal LNK_Chunk * lnk_chunk_from_symbol(LNK_Symbol *symbol);
|
||||
|
||||
internal LNK_Chunk * lnk_defined_symbol_get_chunk(LNK_DefinedSymbol *symbol);
|
||||
|
||||
internal void lnk_symbol_update_chunk_ref(LNK_Symbol *symbol, U64 src_sect_id, U64 dst_sect_id, U64 *id_map, U64 id_count);
|
||||
////////////////////////////////
|
||||
|
||||
internal void lnk_symbol_list_push_node(LNK_SymbolList *list, LNK_SymbolNode *node);
|
||||
internal LNK_SymbolNode * lnk_symbol_list_push(Arena *arena, LNK_SymbolList *list, LNK_Symbol *symbol);
|
||||
internal void lnk_symbol_list_push_list(LNK_SymbolList *list, LNK_SymbolList *to_push);
|
||||
internal void lnk_symbol_list_insert_after(LNK_SymbolList *list, LNK_SymbolNode *node, LNK_SymbolNode *insert);
|
||||
internal LNK_SymbolNode * lnk_symbol_list_pop_node(LNK_SymbolList *list);
|
||||
internal LNK_Symbol * lnk_symbol_list_pop(LNK_SymbolList *list);
|
||||
internal void lnk_symbol_list_remove(LNK_SymbolList *list, LNK_SymbolNode *node);
|
||||
internal void lnk_symbol_list_concat_in_place(LNK_SymbolList *list, LNK_SymbolList *to_concat);
|
||||
internal LNK_SymbolNodeArray lnk_symbol_node_array_from_list(Arena *arena, LNK_SymbolList list);
|
||||
|
||||
internal LNK_SymbolList lnk_symbol_list_from_array(Arena *arena, LNK_SymbolArray arr);
|
||||
internal LNK_SymbolNodeArray lnk_symbol_node_array_from_list(Arena *arena, LNK_SymbolList list);
|
||||
internal LNK_SymbolArray lnk_symbol_array_from_list(Arena *arena, LNK_SymbolList list);
|
||||
internal LNK_Symbol * lnk_symbol_array_search(LNK_SymbolArray symarr, String8 name, StringMatchFlags flags);
|
||||
internal U64 * lnk_symbol_array_hash(TP_Context *tp, Arena *arena, LNK_Symbol *arr, U64 count);
|
||||
|
||||
internal LNK_SymbolTable * lnk_symbol_table_alloc(void);
|
||||
internal LNK_SymbolTable * lnk_symbol_table_alloc_ex(U64 defined_cap, U64 internal_cap, U64 weak_cap, U64 lib_cap);
|
||||
internal void lnk_symbol_table_release(LNK_SymbolTable **symtab);
|
||||
internal U64 lnk_symbol_table_hash(String8 string);
|
||||
internal LNK_SymbolNode * lnk_symbol_table_search_bucket(LNK_SymbolTable *symtab, LNK_SymbolScopeIndex scope_idx, U64 bucket_idx, String8 name, U64 hash);
|
||||
internal LNK_SymbolNode * lnk_symbol_table_search_node_hash(LNK_SymbolTable *symtab, LNK_SymbolScopeFlags scope_flags, String8 name, U64 hash);
|
||||
internal LNK_SymbolNode * lnk_symbol_table_search_node(LNK_SymbolTable *symtab, LNK_SymbolScopeFlags scope, String8 name);
|
||||
internal LNK_Symbol * lnk_symbol_table_search(LNK_SymbolTable *symtab, LNK_SymbolScopeFlags scope_flags, String8 name);
|
||||
internal LNK_Symbol * lnk_symbol_table_searchf(LNK_SymbolTable *symtab, LNK_SymbolScopeFlags scope_flags, char *fmt, ...);
|
||||
internal void lnk_symbol_table_push_node_hash(LNK_SymbolTable *symtab, LNK_SymbolNode *node, U64 hash);
|
||||
internal void lnk_symbol_table_push_node(LNK_SymbolTable *symtab, LNK_SymbolNode *node);
|
||||
internal LNK_SymbolNode * lnk_symbol_table_push(LNK_SymbolTable *symtab, LNK_Symbol *symbol);
|
||||
internal void lnk_symbol_table_push_lazy_arr(TP_Context *tp, LNK_SymbolTable *symtab, LNK_Symbol *arr, U64 count);
|
||||
////////////////////////////////
|
||||
|
||||
internal void lnk_symbol_hash_trie_insert_or_replace(Arena *arena, LNK_SymbolHashTrieChunkList *chunk_list, LNK_SymbolHashTrie **trie, U64 hash, LNK_Symbol *new_symbol);
|
||||
internal LNK_SymbolHashTrie * lnk_symbol_hash_trie_search(LNK_SymbolHashTrie *trie, U64 hash, String8 name);
|
||||
internal void lnk_symbol_hash_trie_remove(LNK_SymbolHashTrie *trie);
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal U64 lnk_symbol_hash(String8 string);
|
||||
|
||||
internal LNK_SymbolTable * lnk_symbol_table_init(TP_Arena *arena);
|
||||
internal LNK_Symbol * lnk_symbol_table_search_hash(LNK_SymbolTable *symtab, LNK_SymbolScopeFlags scope, U64 hash, String8 name);
|
||||
internal LNK_Symbol * lnk_symbol_table_search(LNK_SymbolTable *symtab, LNK_SymbolScopeFlags scope, String8 name);
|
||||
internal LNK_Symbol * lnk_symbol_table_searchf(LNK_SymbolTable *symtab, LNK_SymbolScopeFlags scope, char *fmt, ...);
|
||||
internal void lnk_symbol_table_push_hash(LNK_SymbolTable *symtab, U64 hash, LNK_Symbol *symbol);
|
||||
internal void lnk_symbol_table_push(LNK_SymbolTable *symtab, LNK_Symbol *symbol);
|
||||
internal void lnk_symbol_table_remove(LNK_SymbolTable *symtab, LNK_SymbolScopeIndex scope, String8 name);
|
||||
internal void lnk_symbol_table_replace(LNK_SymbolTable *symtab, LNK_SymbolScopeIndex iscope, LNK_Symbol *symbol);
|
||||
|
||||
internal LNK_Symbol * lnk_resolve_symbol(LNK_SymbolTable *symtab, LNK_Symbol *resolve_symbol);
|
||||
|
||||
internal LNK_SymbolList lnk_pop_comdat_chain(LNK_SymbolList *bucket, LNK_SymbolNode **cursor);
|
||||
internal LNK_SymbolNode * lnk_fold_comdat_chain(LNK_SymbolList chain_list);
|
||||
internal void lnk_fold_comdat_chunks(TP_Context *tp, LNK_SymbolTable *symtab);
|
||||
|
||||
|
||||
@@ -1,188 +0,0 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal
|
||||
THREAD_POOL_TASK_FUNC(os_data_size_from_file_path_task)
|
||||
{
|
||||
OS_DataSizeFromFilePathTask *task = raw_task;
|
||||
|
||||
String8 path = task->path_arr.v[task_id];
|
||||
OS_Handle handle = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead, path);
|
||||
FileProperties props = os_properties_from_file(handle);
|
||||
|
||||
task->handle_arr[task_id] = handle;
|
||||
task->size_arr[task_id] = props.size;
|
||||
}
|
||||
|
||||
internal
|
||||
THREAD_POOL_TASK_FUNC(os_data_from_file_path_task)
|
||||
{
|
||||
OS_DataFromFilePathTask *task = raw_task;
|
||||
|
||||
OS_Handle handle = task->handle_arr[task_id];
|
||||
U64 size = task->size_arr[task_id];
|
||||
U8 *buffer = task->buffer + task->off_arr[task_id];
|
||||
|
||||
U64 read_size = os_file_read(handle, rng_1u64(0, size), buffer);
|
||||
Assert(read_size == size);
|
||||
|
||||
task->data_arr.v[task_id] = str8(buffer, read_size);
|
||||
|
||||
os_file_close(handle);
|
||||
}
|
||||
|
||||
internal String8Array
|
||||
os_data_from_file_path_parallel(TP_Context *tp, Arena *arena, String8Array path_arr)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena,1);
|
||||
|
||||
OS_Handle *handle_arr = push_array_no_zero(scratch.arena, OS_Handle, path_arr.count);
|
||||
U64 *size_arr = push_array_no_zero(scratch.arena, U64, path_arr.count);
|
||||
U64 *off_arr = push_array_no_zero(scratch.arena, U64, path_arr.count);
|
||||
|
||||
// open handles and get sizes
|
||||
OS_DataSizeFromFilePathTask sizer;
|
||||
sizer.path_arr = path_arr;
|
||||
sizer.size_arr = size_arr;
|
||||
sizer.handle_arr = handle_arr;
|
||||
tp_for_parallel(tp, 0, path_arr.count, os_data_size_from_file_path_task, &sizer);
|
||||
|
||||
// compute file buffer size
|
||||
U64 total_data_size = sum_array_u64(path_arr.count, sizer.size_arr);
|
||||
|
||||
// assign offsets into file buffer
|
||||
MemoryCopyTyped(off_arr, sizer.size_arr, path_arr.count);
|
||||
counts_to_offsets_array_u64(path_arr.count, off_arr);
|
||||
|
||||
// read files and close handles
|
||||
OS_DataFromFilePathTask reader;
|
||||
reader.data_arr = str8_array_reserve(arena, path_arr.count);
|
||||
reader.handle_arr = handle_arr;
|
||||
reader.size_arr = size_arr;;
|
||||
reader.off_arr = off_arr;
|
||||
reader.buffer = push_array_no_zero(arena, U8, total_data_size);
|
||||
tp_for_parallel(tp, 0, path_arr.count, os_data_from_file_path_task, &reader);
|
||||
|
||||
String8Array result = {0};
|
||||
result.count = path_arr.count;
|
||||
result.v = reader.data_arr.v;
|
||||
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String8List
|
||||
os_file_search(Arena *arena, String8List dir_list, String8 file_path)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
String8List match_list; MemoryZeroStruct(&match_list);
|
||||
|
||||
if (os_file_path_exists(file_path)) {
|
||||
String8 str = push_str8_copy(arena, file_path);
|
||||
str8_list_push(arena, &match_list, str);
|
||||
}
|
||||
|
||||
PathStyle file_path_style = path_style_from_str8(file_path);
|
||||
B32 is_relative = file_path_style != PathStyle_WindowsAbsolute &&
|
||||
file_path_style != PathStyle_UnixAbsolute;
|
||||
|
||||
if (is_relative) {
|
||||
for (String8Node *i = dir_list.first; i != 0; i = i->next) {
|
||||
String8List path_list = {0};
|
||||
str8_list_push(scratch.arena, &path_list, i->string);
|
||||
str8_list_push(scratch.arena, &path_list, file_path);
|
||||
String8 path = str8_path_list_join_by_style(scratch.arena, &path_list, PathStyle_SystemAbsolute);
|
||||
B32 file_exists = os_file_path_exists(path);
|
||||
if (file_exists) {
|
||||
B32 is_unique = 1;
|
||||
OS_FileID file_id = os_id_from_file_path(path);
|
||||
for (String8Node *k = match_list.first; k != 0; k = k->next) {
|
||||
OS_FileID test_id = os_id_from_file_path(k->string);
|
||||
int cmp = os_file_id_compare(test_id, file_id) != 0;
|
||||
if (cmp == 0) {
|
||||
is_unique = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (is_unique) {
|
||||
String8 str = push_str8_copy(arena, path);
|
||||
str8_list_push(arena, &match_list, str);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
ProfEnd();
|
||||
return match_list;
|
||||
}
|
||||
|
||||
static struct
|
||||
{
|
||||
String8 string;
|
||||
OperatingSystem os;
|
||||
} g_os_map[] = {
|
||||
{ str8_lit_comp("windows"), OperatingSystem_Windows, },
|
||||
{ str8_lit_comp("linux"), OperatingSystem_Linux, },
|
||||
{ str8_lit_comp("mac"), OperatingSystem_Mac, },
|
||||
};
|
||||
|
||||
internal OperatingSystem
|
||||
operating_system_from_string(String8 string)
|
||||
{
|
||||
for (U64 i = 0; i < ArrayCount(g_os_map); ++i) {
|
||||
if (str8_match(g_os_map[i].string, string, StringMatchFlag_CaseInsensitive)) {
|
||||
return g_os_map[i].os;
|
||||
}
|
||||
}
|
||||
return OperatingSystem_Null;
|
||||
}
|
||||
|
||||
internal B32
|
||||
os_try_guid_from_string(String8 string, OS_Guid *guid_out)
|
||||
{
|
||||
Temp scratch = scratch_begin(0,0);
|
||||
B32 is_parsed = 0;
|
||||
String8List list = str8_split_by_string_chars(scratch.arena, string, str8_lit("-"), StringSplitFlag_KeepEmpties);
|
||||
if (list.node_count == 5) {
|
||||
String8 data1_str = list.first->string;
|
||||
String8 data2_str = list.first->next->string;
|
||||
String8 data3_str = list.first->next->next->string;
|
||||
String8 data4_hi_str = list.first->next->next->next->string;
|
||||
String8 data4_lo_str = list.first->next->next->next->next->string;
|
||||
if (str8_is_integer(data1_str, 16) &&
|
||||
str8_is_integer(data2_str, 16) &&
|
||||
str8_is_integer(data3_str, 16) &&
|
||||
str8_is_integer(data4_hi_str, 16) &&
|
||||
str8_is_integer(data4_lo_str, 16)) {
|
||||
U64 data1 = u64_from_str8(data1_str, 16);
|
||||
U64 data2 = u64_from_str8(data2_str, 16);
|
||||
U64 data3 = u64_from_str8(data3_str, 16);
|
||||
U64 data4_hi = u64_from_str8(data4_hi_str, 16);
|
||||
U64 data4_lo = u64_from_str8(data4_lo_str, 16);
|
||||
if (data1 <= max_U32 &&
|
||||
data2 <= max_U16 &&
|
||||
data3 <= max_U16 &&
|
||||
data4_hi <= max_U16 &&
|
||||
data4_lo <= 0xffffffffffff) {
|
||||
guid_out->data1 = (U32)data1;
|
||||
guid_out->data2 = (U16)data2;
|
||||
guid_out->data3 = (U16)data3;
|
||||
U64 data4 = (data4_hi << 48) | data4_lo;
|
||||
MemoryCopy(&guid_out->data4[0], &data4, sizeof(data4));
|
||||
is_parsed = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
scratch_end(scratch);
|
||||
return is_parsed;
|
||||
}
|
||||
|
||||
internal OS_Guid
|
||||
os_guid_from_string(String8 string)
|
||||
{
|
||||
OS_Guid guid = {0};
|
||||
os_try_guid_from_string(string, &guid);
|
||||
return guid;
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#pragma once
|
||||
|
||||
#if OS_WINDOWS
|
||||
# include "os_core_win32.c"
|
||||
#else
|
||||
# error "undefined OS"
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
String8Array path_arr;
|
||||
OS_Handle *handle_arr;
|
||||
U64 *size_arr;
|
||||
} OS_DataSizeFromFilePathTask;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
String8Array data_arr;
|
||||
OS_Handle *handle_arr;
|
||||
U64 *size_arr;
|
||||
U64 *off_arr;
|
||||
U8 *buffer;
|
||||
} OS_DataFromFilePathTask;
|
||||
|
||||
internal String8Array os_data_from_file_path_parallel(TP_Context *tp, Arena *arena, String8Array path_arr);
|
||||
internal String8List os_file_search(Arena *arena, String8List dir_list, String8 file_path);
|
||||
internal B32 os_folder_path_exists(String8 path);
|
||||
|
||||
internal OperatingSystem operating_system_from_string(String8 string);
|
||||
|
||||
internal B32 os_set_large_pages(B32 toggle);
|
||||
|
||||
internal U32 os_get_process_start_time_unix(void);
|
||||
|
||||
internal B32 os_try_guid_from_string(String8 string, OS_Guid *guid_out);
|
||||
internal OS_Guid os_guid_from_string(String8 string);
|
||||
@@ -1,168 +0,0 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal U32
|
||||
w32_unix_time_from_file_time(FILETIME file_time)
|
||||
{
|
||||
U64 win32_time = ((U64)file_time.dwHighDateTime << 32) | file_time.dwLowDateTime;
|
||||
U64 unix_time64 = ((win32_time - 0x19DB1DED53E8000ULL) / 10000000);
|
||||
|
||||
Assert(unix_time64 <= max_U32);
|
||||
U32 unix_time32 = (U32)unix_time64;
|
||||
|
||||
return unix_time32;
|
||||
}
|
||||
|
||||
internal B32
|
||||
os_w32_has_path_volume_prefix(String8 path)
|
||||
{
|
||||
if (path.size >= 2) {
|
||||
U8 *ptr = path.str;
|
||||
U8 *opl = path.str + path.size;
|
||||
UnicodeDecode a = utf8_decode(ptr, (U64)(opl-ptr));
|
||||
ptr += a.inc;
|
||||
UnicodeDecode b = utf8_decode(ptr, (U64)(opl-ptr));
|
||||
return a.codepoint < max_U8 && char_is_alpha(a.codepoint) && b.codepoint == ':';
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
internal B32
|
||||
os_w32_has_device_prefix(String8 path)
|
||||
{
|
||||
if (path.size >= 3) {
|
||||
U8 *ptr = path.str;
|
||||
U8 *opl = path.str + path.size;
|
||||
UnicodeDecode a = utf8_decode(ptr, (U64)(opl-ptr));
|
||||
ptr += a.inc;
|
||||
UnicodeDecode b = utf8_decode(ptr, (U64)(opl-ptr));
|
||||
ptr += b.inc;
|
||||
UnicodeDecode c = utf8_decode(ptr, (U64)(opl-ptr));
|
||||
return a.codepoint == '\\' && b.codepoint == '\\' && (c.codepoint == '?' || c.codepoint == '.');
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
internal B32
|
||||
os_w32_has_unc_prefix(String8 path)
|
||||
{
|
||||
if (path.size >= 2) {
|
||||
U8 *ptr = path.str;
|
||||
U8 *opl = path.str + path.size;
|
||||
UnicodeDecode a = utf8_decode(ptr, (U64)(opl-ptr));
|
||||
ptr += a.inc;
|
||||
UnicodeDecode b = utf8_decode(ptr, (U64)(opl-ptr));
|
||||
return a.codepoint == '\\' && b.codepoint == '\\';
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
internal B32
|
||||
os_w32_has_root_drive_prefix(String8 path)
|
||||
{
|
||||
if (path.size >= 1) {
|
||||
UnicodeDecode a = utf8_decode(path.str, path.size);
|
||||
return a.codepoint == '\\';
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
internal B32
|
||||
os_w32_is_path_relative_current_directory(String8 path)
|
||||
{
|
||||
if (os_w32_has_path_volume_prefix(path)) {
|
||||
return 0;
|
||||
}
|
||||
if (os_w32_has_device_prefix(path)) {
|
||||
return 0;
|
||||
}
|
||||
if (os_w32_has_unc_prefix(path)) {
|
||||
return 0;
|
||||
}
|
||||
if (os_w32_has_root_drive_prefix(path)) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
internal String8
|
||||
os_make_full_path(Arena *arena, String8 path)
|
||||
{
|
||||
String8 full_path;
|
||||
if (os_w32_is_path_relative_current_directory(path)) {
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
String8 current_dir = os_get_current_path(scratch.arena);
|
||||
String8List list = {0};
|
||||
str8_list_push(scratch.arena, &list, current_dir);
|
||||
str8_list_push(scratch.arena, &list, path);
|
||||
String8 temp_full_path = str8_list_join(scratch.arena, &list, &(StringJoin){ .sep = str8_lit_comp("\\") });
|
||||
String8List split_full_path = str8_split_path(scratch.arena, temp_full_path);
|
||||
str8_path_list_resolve_dots_in_place(&split_full_path, PathStyle_WindowsAbsolute);
|
||||
full_path = str8_list_join(arena, &split_full_path, &(StringJoin){ .sep = str8_lit_comp("\\") });
|
||||
scratch_end(scratch);
|
||||
} else {
|
||||
full_path = push_str8_copy(arena, path);
|
||||
}
|
||||
return full_path;
|
||||
}
|
||||
|
||||
internal B32
|
||||
os_folder_path_exists(String8 path)
|
||||
{
|
||||
Temp scratch = scratch_begin(0,0);
|
||||
|
||||
String8 actual_path = path;
|
||||
if (os_w32_is_path_relative_current_directory(path)) {
|
||||
String8 current = os_get_current_path(scratch.arena);
|
||||
String8List list = {0};
|
||||
str8_list_push(scratch.arena, &list, current);
|
||||
str8_list_push(scratch.arena, &list, path);
|
||||
StringJoin join = { .sep = str8_lit_comp("\\") };
|
||||
actual_path =str8_list_join(scratch.arena, &list, &join);
|
||||
}
|
||||
|
||||
String16 path16 = str16_from_8(scratch.arena, actual_path);
|
||||
DWORD attributes = GetFileAttributesW((WCHAR *)path16.str);
|
||||
B32 exists = (attributes != INVALID_FILE_ATTRIBUTES) && (attributes & FILE_ATTRIBUTE_DIRECTORY);
|
||||
scratch_end(scratch);
|
||||
return exists;
|
||||
}
|
||||
|
||||
internal B32
|
||||
os_set_large_pages(B32 toggle)
|
||||
{
|
||||
B32 is_ok = 0;
|
||||
|
||||
HANDLE token;
|
||||
if(OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token))
|
||||
{
|
||||
LUID luid;
|
||||
if(LookupPrivilegeValue(0, SE_LOCK_MEMORY_NAME, &luid))
|
||||
{
|
||||
TOKEN_PRIVILEGES priv;
|
||||
priv.PrivilegeCount = 1;
|
||||
priv.Privileges[0].Luid = luid;
|
||||
priv.Privileges[0].Attributes = toggle ? SE_PRIVILEGE_ENABLED : SE_PRIVILEGE_REMOVED;
|
||||
if (AdjustTokenPrivileges(token, 0, &priv, sizeof(priv), 0, 0) == ERROR_SUCCESS) {
|
||||
is_ok = 1;
|
||||
}
|
||||
}
|
||||
CloseHandle(token);
|
||||
}
|
||||
return is_ok;
|
||||
}
|
||||
|
||||
internal U32
|
||||
os_get_process_start_time_unix(void)
|
||||
{
|
||||
HANDLE handle = GetCurrentProcess();
|
||||
FILETIME start_time = {0};
|
||||
FILETIME exit_time;
|
||||
FILETIME kernel_time;
|
||||
FILETIME user_time;
|
||||
if (GetProcessTimes(handle, &start_time, &exit_time, &kernel_time, &user_time)) {
|
||||
return w32_unix_time_from_file_time(start_time);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#include "core/os_core.c"
|
||||
|
||||
#if OS_WINDOWS
|
||||
//# include "core/win32/os_core_win32.c"
|
||||
#elif OS_LINUX
|
||||
//# include "core/linux/os_core_linux.c"
|
||||
#else
|
||||
# error no OS layer setup
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/os_core.h"
|
||||
|
||||
#if OS_WINDOWS
|
||||
//# include "core/win32/os_core_win32.h"
|
||||
#elif OS_LINUX
|
||||
//# include "core/linux/os_core_linux.h"
|
||||
#else
|
||||
# error no OS layer setup
|
||||
#endif
|
||||
|
||||
@@ -998,12 +998,7 @@ exit:;
|
||||
internal MSF_UInt
|
||||
msf_stream_reserve__(MSF_Context *msf, MSF_Stream *stream, MSF_UInt res)
|
||||
{
|
||||
Temp scratch = scratch_begin(0,0);
|
||||
|
||||
#if PROFILE_TELEMETRY
|
||||
String8 size_string = str8_from_memory_size2(scratch.arena, res);
|
||||
ProfBeginDynamic("MSF Reserve %.*s", str8_varg(size_string));
|
||||
#endif
|
||||
ProfBeginV("MSF Reserve %m", res);
|
||||
|
||||
B32 is_ok = 1;
|
||||
|
||||
@@ -1019,7 +1014,6 @@ msf_stream_reserve__(MSF_Context *msf, MSF_Stream *stream, MSF_UInt res)
|
||||
AssertAlways(is_ok);
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
ProfEnd();
|
||||
return is_ok;
|
||||
}
|
||||
@@ -1152,20 +1146,13 @@ THREAD_POOL_TASK_FUNC(msf_write_task)
|
||||
internal B32
|
||||
msf_stream_write_parallel(TP_Context *tp, MSF_Context *msf, MSF_StreamNumber sn, void *buffer, MSF_UInt buffer_size)
|
||||
{
|
||||
Temp scratch = scratch_begin(0,0);
|
||||
|
||||
#if PROFILE_TELEMETRY
|
||||
String8 buffer_size_string = str8_from_memory_size2(scratch.arena, buffer_size);
|
||||
ProfBeginDynamic("MSF Write Parallel [%.*s]", str8_varg(buffer_size_string));
|
||||
#endif
|
||||
ProfBeginV("MSF Write Parallel %m", buffer_size);
|
||||
|
||||
MSF_Stream *stream = msf_find_stream(msf, sn);
|
||||
|
||||
B32 is_write_ok = msf_stream_reserve__(msf, stream, buffer_size);
|
||||
|
||||
if (is_write_ok) {
|
||||
Temp scratch = scratch_begin(0,0);
|
||||
|
||||
U64 expected_pos = stream->pos + buffer_size;
|
||||
|
||||
U64 pre_size = Min(AlignPadPow2(stream->pos, msf->page_size), buffer_size);
|
||||
@@ -1176,13 +1163,15 @@ msf_stream_write_parallel(TP_Context *tp, MSF_Context *msf, MSF_StreamNumber sn,
|
||||
U8 *mid_ptr = (U8*)buffer + pre_size;
|
||||
U8 *end_ptr = (U8*)buffer + pre_size + mid_size;
|
||||
|
||||
ProfBegin("Write Buffer Pre");
|
||||
ProfBeginV("Write Buffer Pre %M", pre_size);
|
||||
B32 is_pre_written = msf_stream_write__(msf, stream, pre_ptr, pre_size);
|
||||
AssertAlways(is_pre_written);
|
||||
ProfEnd();
|
||||
|
||||
// write buffer mid
|
||||
if (mid_size > 0) {
|
||||
Temp scratch = scratch_begin(0,0);
|
||||
|
||||
Assert(stream->pos % msf->page_size == 0);
|
||||
Assert(mid_size % msf->page_size == 0);
|
||||
|
||||
@@ -1199,20 +1188,19 @@ msf_stream_write_parallel(TP_Context *tp, MSF_Context *msf, MSF_StreamNumber sn,
|
||||
U64 after_mid = stream->pos + mid_size;
|
||||
B32 is_seek_ok = msf_stream_seek__(msf, stream, after_mid);
|
||||
AssertAlways(is_seek_ok);
|
||||
|
||||
scratch_end(scratch);
|
||||
}
|
||||
|
||||
ProfBegin("Write Buffer End");
|
||||
ProfBeginV("Write Buffer End %M", end_size);
|
||||
B32 is_end_ok = msf_stream_write__(msf, stream, end_ptr, end_size);
|
||||
AssertAlways(is_end_ok);
|
||||
ProfEnd();
|
||||
|
||||
// did we write bytes correctly?
|
||||
AssertAlways(stream->pos == expected_pos);
|
||||
|
||||
scratch_end(scratch);
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
ProfEnd();
|
||||
return is_write_ok;
|
||||
}
|
||||
|
||||
@@ -1265,7 +1265,7 @@ pdb_type_server_build(TP_Context *tp, PDB_TypeServer *ts, PDB_StringTable *strta
|
||||
lf_arr[lf_arr_idx] = lf;
|
||||
lf_arr_idx += 1;
|
||||
}
|
||||
lf_buf_size += AlignPow2(lf->string.size, PDB_LEAF_ALIGN);
|
||||
lf_buf_size += lf->string.size;
|
||||
lf_node_idx += 1;
|
||||
}
|
||||
|
||||
@@ -1274,7 +1274,6 @@ pdb_type_server_build(TP_Context *tp, PDB_TypeServer *ts, PDB_StringTable *strta
|
||||
ProfBegin("Write Type Data & Hints");
|
||||
|
||||
PDB_WriteTypesTask write_types_task;
|
||||
write_types_task.align = PDB_LEAF_ALIGN;
|
||||
write_types_task.ti_lo = ts->ti_lo;
|
||||
write_types_task.ti_hi = ts->ti_lo + ts->leaf_list.node_count;
|
||||
write_types_task.hint_count = hint_count;
|
||||
@@ -1472,7 +1471,7 @@ THREAD_POOL_TASK_FUNC(pdb_push_udt_leaf_task)
|
||||
CV_UDTInfo udt_info = cv_get_udt_info(leaf.kind, leaf.data);
|
||||
if (~udt_info.props & CV_TypeProp_FwdRef) {
|
||||
// hash udt and compute bucket index
|
||||
U32 hash = pdb_hash_udt(udt_info, leaf.data);
|
||||
U32 hash = pdb_hash_udt(udt_info, leaf.data);
|
||||
U32 bucket_idx = hash % type_ht_cap;
|
||||
|
||||
// fill out & insert bucket
|
||||
@@ -1649,7 +1648,7 @@ pdb_load_types_from_leaf_list(PDB_TypeServer **type_server_arr, CV_LeafList leaf
|
||||
////////////////////////////////
|
||||
|
||||
internal PDB_InfoContext *
|
||||
pdb_info_alloc(U32 age, COFF_TimeStamp time_stamp, OS_Guid guid)
|
||||
pdb_info_alloc(U32 age, COFF_TimeStamp time_stamp, Guid guid)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
Arena *arena = arena_alloc();
|
||||
@@ -2522,12 +2521,6 @@ gsi_push_many_list(PDB_GsiContext *gsi, U64 count, U32 *hash_arr, CV_SymbolList
|
||||
MemoryZeroStruct(list);
|
||||
}
|
||||
|
||||
internal void
|
||||
gsi_push_many_and_remove_duplicates(TP_Context *tp, CV_SymbolList *list)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
internal CV_SymbolNode *
|
||||
gsi_search(PDB_GsiContext *gsi, CV_Symbol *symbol)
|
||||
{
|
||||
@@ -3535,7 +3528,7 @@ pdb_alloc_msf(U64 page_size)
|
||||
}
|
||||
|
||||
internal PDB_Context *
|
||||
pdb_alloc(U64 page_size, COFF_MachineType machine, COFF_TimeStamp time_stamp, U32 age, OS_Guid guid)
|
||||
pdb_alloc(U64 page_size, COFF_MachineType machine, COFF_TimeStamp time_stamp, U32 age, Guid guid)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
Arena *arena = arena_alloc();
|
||||
@@ -3613,7 +3606,7 @@ pdb_set_machine(PDB_Context *pdb, COFF_MachineType machine)
|
||||
}
|
||||
|
||||
internal void
|
||||
pdb_set_guid(PDB_Context *pdb, OS_Guid guid)
|
||||
pdb_set_guid(PDB_Context *pdb, Guid guid)
|
||||
{
|
||||
pdb->info->guid = guid;
|
||||
}
|
||||
@@ -3649,7 +3642,7 @@ pdb_get_age(PDB_Context *pdb)
|
||||
return pdb->info->age;
|
||||
}
|
||||
|
||||
internal OS_Guid
|
||||
internal Guid
|
||||
pdb_get_guid(PDB_Context *pdb)
|
||||
{
|
||||
return pdb->info->guid;
|
||||
|
||||
@@ -135,7 +135,6 @@ typedef struct
|
||||
|
||||
typedef struct
|
||||
{
|
||||
U64 align;
|
||||
CV_TypeIndex ti_lo;
|
||||
CV_TypeIndex ti_hi;
|
||||
U64 hint_count;
|
||||
@@ -155,7 +154,7 @@ typedef struct PDB_InfoParse
|
||||
PDB_TpiVersion version;
|
||||
COFF_TimeStamp time_stamp;
|
||||
U32 age;
|
||||
OS_Guid guid;
|
||||
Guid guid;
|
||||
String8 extra_info;
|
||||
} PDB_InfoParse;
|
||||
|
||||
@@ -164,7 +163,7 @@ typedef struct PDB_InfoContext
|
||||
Arena *arena;
|
||||
COFF_TimeStamp time_stamp;
|
||||
U32 age;
|
||||
OS_Guid guid;
|
||||
Guid guid;
|
||||
PDB_FeatureFlags flags;
|
||||
PDB_HashTable named_stream_ht;
|
||||
PDB_HashTable src_header_block_ht;
|
||||
@@ -348,23 +347,23 @@ typedef struct
|
||||
////////////////////////////////
|
||||
// PDB
|
||||
|
||||
internal PDB_Context * pdb_alloc(U64 page_size, COFF_MachineType machine, COFF_TimeStamp time_stamp, U32 age, OS_Guid guid);
|
||||
internal PDB_Context * pdb_alloc(U64 page_size, COFF_MachineType machine, COFF_TimeStamp time_stamp, U32 age, Guid guid);
|
||||
internal PDB_Context * pdb_open(String8 data);
|
||||
internal void pdb_release(PDB_Context **pdb_ptr);
|
||||
internal void pdb_build(TP_Context *tp, TP_Arena *pool_temp, PDB_Context *pdb, CV_StringHashTable string_ht);
|
||||
internal void pdb_set_machine(PDB_Context *pdb, COFF_MachineType machine);
|
||||
internal void pdb_set_guid(PDB_Context *pdb, OS_Guid guid);
|
||||
internal void pdb_set_guid(PDB_Context *pdb, Guid guid);
|
||||
internal void pdb_set_time_stamp(PDB_Context *pdb, COFF_TimeStamp time_stamp);
|
||||
internal void pdb_set_age(PDB_Context *pdb, U32 age);
|
||||
internal COFF_MachineType pdb_get_machine(PDB_Context *pdb);
|
||||
internal COFF_TimeStamp pdb_get_time_stamp(PDB_Context *pdb);
|
||||
internal U32 pdb_get_age(PDB_Context *pdb);
|
||||
internal OS_Guid pdb_get_guid(PDB_Context *pdb);
|
||||
internal Guid pdb_get_guid(PDB_Context *pdb);
|
||||
|
||||
////////////////////////////////
|
||||
// Info
|
||||
|
||||
internal PDB_InfoContext * pdb_info_alloc(U32 age, COFF_TimeStamp time_stamp, OS_Guid guid);
|
||||
internal PDB_InfoContext * pdb_info_alloc(U32 age, COFF_TimeStamp time_stamp, Guid guid);
|
||||
internal void pdb_info_parse_from_data(String8 data, PDB_InfoParse *parse_out);
|
||||
internal PDB_InfoContext * pdb_info_open(MSF_Context *msf, MSF_StreamNumber sn);
|
||||
internal void pdb_info_build(PDB_InfoContext *info, MSF_Context *msf, MSF_StreamNumber sn);
|
||||
|
||||
@@ -1177,29 +1177,26 @@ internal U64
|
||||
rdib_sizeof_type(RDIB_Type *type)
|
||||
{
|
||||
U64 size = 0;
|
||||
|
||||
RDIB_Type *curr = type;
|
||||
while (curr->kind == RDI_TypeKind_Modifier) {
|
||||
curr = curr->modifier.type_ref;
|
||||
}
|
||||
|
||||
if (RDI_TypeKind_FirstBuiltIn <= curr->kind && curr->kind < RDI_TypeKind_LastBuiltIn) {
|
||||
size = curr->builtin.size;
|
||||
} else if (curr->kind == RDI_TypeKind_Ptr || curr->kind == RDI_TypeKind_LRef || curr->kind == RDI_TypeKind_RRef) {
|
||||
size = curr->ptr.size;
|
||||
} else if (curr->kind == RDI_TypeKind_Struct || curr->kind == RDI_TypeKind_Class ||
|
||||
curr->kind == RDI_TypeKind_IncompleteStruct || curr->kind == RDI_TypeKind_IncompleteClass) {
|
||||
size = curr->udt.struct_type.size;
|
||||
} else if (curr->kind == RDI_TypeKind_Union || curr->kind == RDI_TypeKind_IncompleteUnion) {
|
||||
size = curr->udt.union_type.size;
|
||||
} else if (curr->kind == RDI_TypeKind_Enum || curr->kind == RDI_TypeKind_IncompleteEnum) {
|
||||
size = rdib_sizeof_type(curr->udt.enum_type.base_type);
|
||||
} else if (curr->kind == RDI_TypeKind_Bitfield) {
|
||||
size = rdib_sizeof_type(curr->bitfield.value_type);
|
||||
if (RDI_TypeKind_FirstBuiltIn <= type->kind && type->kind < RDI_TypeKind_LastBuiltIn) {
|
||||
size = type->builtin.size;
|
||||
} else if (type->kind == RDI_TypeKind_Modifier) {
|
||||
size = rdib_sizeof_type(type->modifier.type_ref);
|
||||
} else if (type->kind == RDI_TypeKind_Ptr || type->kind == RDI_TypeKind_LRef || type->kind == RDI_TypeKind_RRef) {
|
||||
size = type->ptr.size;
|
||||
} else if (type->kind == RDI_TypeKind_Struct || type->kind == RDI_TypeKind_Class ||
|
||||
type->kind == RDI_TypeKind_IncompleteStruct || type->kind == RDI_TypeKind_IncompleteClass) {
|
||||
size = type->udt.struct_type.size;
|
||||
} else if (type->kind == RDI_TypeKind_Union || type->kind == RDI_TypeKind_IncompleteUnion) {
|
||||
size = type->udt.union_type.size;
|
||||
} else if (type->kind == RDI_TypeKind_Enum || type->kind == RDI_TypeKind_IncompleteEnum) {
|
||||
size = rdib_sizeof_type(type->udt.enum_type.base_type);
|
||||
} else if (type->kind == RDI_TypeKind_Bitfield) {
|
||||
size = rdib_sizeof_type(type->bitfield.value_type);
|
||||
} else if (type->kind == RDI_TypeKind_Array) {
|
||||
size = type->array.size;
|
||||
} else {
|
||||
Assert(!"error: type doens't have a size");
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
@@ -91,6 +91,13 @@ struct TypeWithBitfield
|
||||
int z : 10;
|
||||
};
|
||||
|
||||
typedef struct BitfieldType64 BitfieldType64;
|
||||
struct BitfieldType64
|
||||
{
|
||||
uint64_t size : 63;
|
||||
uint64_t is_free : 1;
|
||||
};
|
||||
|
||||
void
|
||||
c_type_with_bitfield_usage(void)
|
||||
{
|
||||
@@ -103,4 +110,8 @@ c_type_with_bitfield_usage(void)
|
||||
int x = (b.v + b.x);
|
||||
int y = (b.y - b.z);
|
||||
int z = (b.w) + 5;
|
||||
BitfieldType64 b64 = {0};
|
||||
b64.size = 524288;
|
||||
b64.is_free = 1;
|
||||
int abc = 0;
|
||||
}
|
||||
|
||||
@@ -279,8 +279,8 @@ few_params1(Pair *pairs, int count, Function_No_Params_Type *no_params_type){
|
||||
}
|
||||
|
||||
static void
|
||||
type_coverage_eval_tests(void){
|
||||
|
||||
type_coverage_eval_tests(void)
|
||||
{
|
||||
Basics basics = {-1, 1, -2, 2, -4, 4, -8, 8, 1.5f, 1.50000000000001};
|
||||
Basics_Stdint basics_stdint = {-1, 1, -2, 2, -4, 4, -8, 8, 1.5f, 1.50000000000001};
|
||||
|
||||
@@ -432,6 +432,10 @@ type_coverage_eval_tests(void){
|
||||
OutputDebugStringA("\n");
|
||||
}
|
||||
|
||||
const int32_t x1 = 3;
|
||||
const int32_t y1 = -10;
|
||||
const int32_t z1 = x1 + y1;
|
||||
|
||||
int x = (int)(Anonymous_D);
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user